この記事の音声は準備中です。
音声の一覧・再生リストへ回帰テストと 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 キーが評価専用に分離されている
関連トピック
- Agent 評価の基礎 — スイートの中身(データセット・採点・メトリクス)の設計
- LLM-as-a-Judge — judge 自体も回帰テストの対象
- 軌跡(trajectory)評価 — 落ちたケースの原因調査の道具
- フレームワーク選定ガイド — 評価との統合しやすさは選定軸の 1 つ
- バージョニング・デプロイ・モデル更新追従 — モデル更新イベントの運用手順
- エージェント評価環境の構築 — 回帰スイートを載せる評価環境(モック・状態リセット)
- テスト工程での活用 — 企業システム開発のテスト工程でコーディングエージェントコードベースを読み、ファイルを編集し、コマンドを実行して検証するループで開発タスクを遂行する Agent。コード補完と異なり「タスク単位の委任」を受けられる。を使う SE 実践側
- examples/python/evaluation-harness/ — 閾値割れで異常終了する評価ハーネスAgent の評価を繰り返し実行可能にする仕組み一式。データセット・実行系・採点系・レポートの 4 点で構成される。(CI 組み込みの土台・モック実行可)
参考資料
- Your AI Product Needs Evals(Hamel Husain) — ユニットテスト・LLM 評価・人手評価の 3 レベル構成と CI 組み込みの実践(アクセス日: 2026-07-05)