Skip to Content
Docs04. 評価回帰テストと CI 組み込み

この記事の音声は準備中です。

音声の一覧・再生リストへ

回帰テストと CI 組み込み

この記事の目的

プロンプトの 1 行修正・ツールの追加・モデルの更新といった変更のたびに「既存の品質が壊れていないか」を自動で検知できるように、評価データセットを回帰スイートとして CI に組み込む設計ができるようになります。コスト・実行時間・非決定性(flaky)との折り合いの付け方を判断できるようになります。

対象読者

  • Agent を継続的に変更・改善するフェーズに入ったチームのエンジニア
  • 「プロンプトを直したら、関係ないはずのケースが壊れた」を経験した人

前提知識

  • Agent 評価の基礎 — データセット・採点・メトリクスの設計
  • LLM-as-a-Judge — スイート内の自動採点手法
  • ライブラリ外の前提: 一般的な CI/CD(テストの自動実行とゲート)の経験

本文

概要: Agent の変更は「非局所的に効く」

通常のソフトウェアでは、変更の影響範囲をコードの依存関係からある程度限定できます。Agent では、プロンプトの 1 行・ツール説明文の 1 語・モデルのバージョンが挙動全体に非局所的に効きます。「経費精算まわりの指示を直したら、無関係なはずの検索の挙動が変わった」が普通に起きます。

影響範囲を静的に予測できない以上、対策は 1 つです — 変更のたびにスイート全体を再実行し、前回と比較すること。これが Agent における回帰テストで、通常のソフトウェア以上に「変更 → 全体再評価」の自動化が重要になります。

詳細: テストのレイヤ分け

すべてを Agent の E2E 実行で検証するとコストと時間が破綻します。LLM を含むか・何回呼ぶかでレイヤを分けます。

レイヤ対象LLM 呼び出し実行タイミング
L1: 決定的ユニットテストツール実装・入力検証・実行時ガード・軌跡アサーションのロジックなし毎コミット(通常のテストと同じ)
L2: コンポーネント評価単一の LLM 呼び出し(分類・抽出・構造化出力LLM の出力を JSON Schema などの機械可読なスキーマに従わせる技術。後続の処理がコードである出力(分類・抽出・スコア)に使う。・judge 自身)1 ケース 1 回PR ごと(小規模)+ 夜間(全量)
L3: E2E Agent 評価Agent ループLLM が「観測 → 思考 → 行動」のサイクルを繰り返し、完了・失敗・上限のいずれかの停止条件まで自律的に処理を続ける制御構造。全体(最終成果 + 軌跡)1 ケース多数回夜間・リリース前・影響の大きい変更時

ここで重要なのは、Agent システムの大部分は LLM なしでテストできることです。ツールの実装・権限ガード・パーサは決定的な普通のコードであり、L1 で毎コミット検証します。「Agent だから全部 E2E」は最も高くて遅い選択です。

詳細: 非決定性(flaky)との付き合い方

  • 1 回実行の合格/不合格は信号として弱いため、重要ケースは N 回実行して「N 回中 M 回成功」で判定します。「毎回成功すべき」タスクは全回成功を、「1 回できれば十分」なタスクは 1 回以上の成功を基準にします(Agent 評価の基礎)
  • ノイズの幅を先に測ります — 同じバージョンでスイートを 2〜3 回実行し、成功率の変動幅を把握します。これを知らないと「82% → 79%」が劣化なのかノイズなのか判断できず、ゲートの信頼が崩れます
  • flaky なケースを無効化して放置しないでください。「たまに失敗する」は同じ条件では本番でも失敗しうるという品質情報です。失敗率はケース分布や実行条件に依存するため、本番の分布で別に測ります

詳細: CI 組み込みの実務

  • トリガ設計 — PR ごと: L1 全量 + 少数の smoke セット(分単位・低コストに収める)。マージ後・夜間: フルスイート。リリース前: 複数回実行を含むフル
  • ゲート基準 — 絶対閾値(成功率 X% 以上)とベースライン比較(前回比 Y ポイント以上の劣化で失敗)の併用。レポートで最重要なのは新たに落ちたケースの一覧で、集計値だけでは調査が始まりません
  • コストの管理 — スイート実行ごとのトークンコストを記録し、上限を設けます。並列実行で時間を短縮できますが、API のレートリミットとの調整が必要です
  • 認証情報の分離 — CI が使う API キーは評価専用に分離し、予算・権限を本番と別に管理します

設計判断: 何が変わったら何を回すか

変更最低限回すもの
ツールの内部実装のみ(定義・挙動仕様は不変)L1
プロンプト・ツール定義の変更、ツールの追加L1 + L2 + L3(まず smoke、通ればフル)
モデルのバージョン更新フルスイート + judge の再検証(人手ラベルとの一致率から)

モデル更新は「コード変更ゼロで挙動が全面的に変わる」イベントです。評価なしで取り込まず、新旧モデルで同一スイートを実行して比較してから切り替えます。ケースごとの差とばらつきを併記し、反復回数を独立ケース数とみなさないようにします(評価の基礎: 件数とばらつき)。judge のモデルも更新するなら、judge 自体の一致率検証(LLM-as-a-Judge)からやり直します。運用の詳細は バージョニング・デプロイ・モデル更新追従 で扱います。

詳細: 落ちたときの動線と資産化

回帰で落ちたケースの調査は、最終出力の差分 → 軌跡の比較(軌跡(trajectory)評価)の順に降りていきます。スイートのレポートから各ケースの軌跡へ直接たどれる状態を作っておくと、調査コストが大きく下がります。

また、本番で見つかった不具合は、修正と同時に回帰ケースとして追加します。「一度起きた失敗は二度と静かに再発しない」状態を積み上げることが、回帰スイートの価値の中心です。

実務での注意点

アンチパターン

  • 全ケースを E2E で毎 PR 実行する → 時間とコストが膨らみ、やがて「CI が重い」を理由に誰も回さなくなる → レイヤ分けとトリガ設計で「軽く頻繁に、重く定期に」を徹底する
  • 1 回実行の合否でゲートする → flaky な失敗のたびに開発が止まり、「どうせノイズ」とゲート自体が無視されるようになる → 複数回実行・ノイズ幅の把握・ベースライン比較で信号の質を上げる
  • ダッシュボードで眺めるだけでゲートしない → 劣化に気づいても「今回はいいか」で通り、品質がじわじわ下がる → 合意した合格基準を CI の失敗条件として機械的に強制する
  • モデル更新を無評価で取り込む → コード変更ゼロで挙動が全面的に変わるのに、検知する仕組みがない → 新旧同一スイートの比較をモデル更新の必須手順にする

チェックリスト

  • LLM を含まない部分(ツール・ガード)が通常のユニットテストで毎コミット検証されている
  • PR ごと・夜間・リリース前に何を実行するかが決まっている
  • ゲート基準(絶対閾値 + ベースライン比較)が明文化され、CI の失敗条件になっている
  • 重要ケースは複数回実行で判定し、同一バージョンでのノイズ幅を把握している
  • レポートに「新たに落ちたケースの一覧」があり、そこから軌跡へたどれる
  • 本番の不具合を回帰ケースへ追加する運用がある
  • スイート実行コストが記録され、上限が設定されている
  • CI 用の API キーが評価専用に分離されている

関連トピック

参考資料

TODO・未確認事項