Alejandro Rioja.
AI Agents Operations

恐れずにAIエージェントを出荷するために使う評価ハーネス

Alejandro Rioja
Alejandro Rioja
1 分で読める
TL;DR

恐れずにエージェントを出荷できるのは、たった一つのもの——評価ハーネスのおかげだ。採点済みのテストケースを固定した集合を、自動でスコアリングし(アサーションとLLMジャッジ)、すべてのプロンプトやモデルの変更前に実行する。スコアが保たれれば出荷する。テストセットは実際の本番障害から構築する。

無料ニュースレター

毎週水曜。28,400人以上の読者。無駄なし。

目次

2026年6月更新。

TL;DR: 稼働中のエージェントでプロンプトを変えたりモデルを差し替えたりしても息を呑まずに済む理由は、たった一つ——評価ハーネスだ。採点済みのテストケースを固定した集合を、自動でスコアリングする——書ける場所には厳格なアサーションを、書けない場所にはLLMジャッジを——そしてすべての変更前に実行する。スコアが保たれれば出荷する。スコアが下がれば出荷しない。テストセットは合成ではない。実際の本番障害から構築するので、すべてのバグが恒久的な回帰テストになる。

オペレーターの読み: 100を超えるエージェントを見てきて、自信を持って触れるものと怖くて触れないものの違いは、評価があるかどうかだ。評価ハーネスがなければ、あらゆるプロンプトの微調整は賭けになる。評価ハーネスは「これの方が良いと思う」を「これは測定可能に4ポイント良く、何も壊さなかった」に変える。それが解放のすべてだ。

テストなしにコードを出荷しないだろう。人々は評価なしに絶えずエージェントを出荷し、その後「ほんの小さなプロンプトの微調整」がなぜ本番を壊したのか首をかしげる。評価ハーネスは非決定論的ソフトウェアのためのテストスイートだ。これが私が実際に走らせているものだ。

実際の障害から構築したテストセットから始める

ハーネスはそのテストケースの質を超えられず、最良のテストケースは想像ではなく本番から来る。エージェントが現場で失敗するたびに、私は正確な入力を捕捉し(すべての実行をトレースIDとともにログに残す——本番でエージェントをデバッグする方法を参照)、それを評価ケースに変える。

typescript
interface EvalCase {
  id: string;
  input: AgentInput;        // 正確な本番入力
  expected?: string;        // 正解がある場合のグラウンドトゥルース
  assertions: Assertion[];  // 通過しなければならない厳格なチェック
  rubric?: string;          // 出力がオープンエンドな場合のLLMジャッジ用
}

ここで重要な実践が二つある。本番から引くこと。そうすれば評価は、推測したものではなく実際に壊れるものをテストする。そして幅をカバーすること——ハッピーパス、エッジケース、敵対的入力、そして静かな失敗を引き起こす空/不正な入力。よく選ばれた30〜50ケースのテストセットは、500の怠惰なケースよりはるかに多くを捕まえる。すべて同じ簡単なパスをテストする千のケースより、それぞれが実際の失敗モードを表す40ケースの方がいい。

まずアサーションで、次にLLMジャッジで採点する

すべての出力にモデルによる採点が要るわけではない。私は機能する中で最も安い採点器に手を伸ばす。

構造化されたものすべてには厳格なアサーションを。出力は有効なJSONとしてパースできるか?必須フィールドを含むか?抽出された日付は範囲内か?正しい引数で正しいツールを呼んだか?これらは決定論的で、無料で、曖昧さがない——書けるだけ書こう。

typescript
const assertions: Assertion[] = [
  (out) => isValidJSON(out),
  (out) => parse(out).category in ALLOWED_CATEGORIES,
  (out) => parse(out).confidence >= 0 && parse(out).confidence <= 1,
];

オープンエンドな残りにはLLMジャッジを——トーン、有用性、「これは本当に質問に答えたか」。ここではモデルに入力、出力、ルーブリックを与え、採点を求める。ジャッジを正直に保つルールは二つ。ルーブリックを具体的にすること(記述されたアンカー付きの1〜5スケールは「品質を評価せよ」に勝る)、そして強いモデルをジャッジに使うこと——判定は推論タスクなので、ここはエージェント自体がコスト計算に従ってHaikuで動いていても、私が喜んでSonnetに支払う場面だ。曖昧なルーブリックや弱いジャッジは、信号に見えるノイズを与える。

すべての変更前にハーネスを走らせる

ハーネスは一つの問いに答えるために存在する。この変更はエージェントを良くしたか悪くしたか? だから私はすべてのプロンプト編集、モデル差し替え、ツール変更の前にそれを走らせる。

bash
# main上のベースライン
npm run eval -- --suite=booking-agent > baseline.json

# 変更を加え、再実行する
npm run eval -- --suite=booking-agent > candidate.json

# 比較する
npm run eval:diff baseline.json candidate.json

差分は集計スコア、ケースごとの合否、そして——決定的に——どの特定ケースが回帰したかを示す。三つのケースが静かに壊れる一方で集計が上昇するのは改善ではない。それは私が見て承認したいトレードオフであり、こっそり通り抜けるものではない。ケースごとの差分を見守ることが、「一つ直して二つ壊す」——人々を自分のプロンプトに怯えさせる失敗モード——を避ける方法だ。

回帰ゲートを設定し、ブロックさせる

ハーネスを信頼したら、それをゲートとして本番への経路に組み込む。私のルールは率直だ。スコアをベースラインの閾値より下げる変更は出荷しない。 「後で見ておく」ではない——失敗したCIテストと同様にブロックされる。

typescript
const PASS_THRESHOLD = 0.90; // 90%のケースが通過しなければならない
if (candidate.passRate < PASS_THRESHOLD || candidate.passRate < baseline.passRate) {
  throw new Error(`Eval regression: ${candidate.passRate} < ${baseline.passRate}`);
}

これが評価を「あれば良いもの」から、速く動けるようにするものへと変える。ゲートこそが「恐れずに出荷する」を文字通り真にする。悪い変更の最悪のケースは赤い評価実行であって、本番インシデントではない。そしてテストセットは何かが壊れるたびに成長するので、ゲートは時とともに自ら厳しく、より保護的になっていく。

採点における非決定論を考慮する

人々がつまずく微妙な点。同じ入力でも実行ごとに異なるスコアになりうる。モデルが異なるサンプリングをするからだ。各ケースを一度だけ実行すると、幻の回帰が見える——「壊れた」ケースが実はサンプリングノイズにすぎない。

緩和策が二つ。分散を縮めるために評価を**temperature: 0**で実行する(完全には消えない)。そしてちらつきを見たケースは、単一の合否ではなく、N回実行して合格率を取る。9/10通過するケースは、両方とも緑の単一実行を示しうるとしても、5/10通過するケースより状態が良い。これは断続的な失敗をデバッグするときに使うのと同じ、逸話より物量の原則だ——一度の実行は意見、五十回の実行はデータだ。

本番モニタリングでループを閉じる

評価ハーネスは既知のケースに対してテストする。本番は未知のケースを投げてくる。だからループはこうだ。稼働中の挙動をモニタリングし、新しい失敗モードを捕まえ、それを評価ケースに変え、修正する。すると今やそれは恒久的に守られる。モニタリング側——稼働トラフィックでの成功率、出力の妥当性、実行ごとのコストを追跡すること——はAIエージェントが本当に機能しているかをどう測るかで扱っている。評価とモニタリングは同じシステムの二つの半分だ。モニタリングがバグを見つけ、評価がそれが死んだままであることを保証する。

そのフィードバックループこそが本当のプロダクトだ。単一の評価セットはどれも古びる。だが、すべての本番障害を恒久的なテストに変えるプロセスは毎週強くなる。こうしてエージェントは「触るのが怖い」から、金曜の午後にひるまずリファクタリングするものへと変わる。

よくある質問

AIエージェントの評価セットには何が入るのか?

実際の本番入力を採点済みケースに変えたもの——ハッピーパス、エッジケース、敵対的入力と不正な入力——それぞれに厳格なアサーションを、オープンエンドな出力にはLLMジャッジのルーブリックを添える。実際の障害から引いた30〜50ケースは、すべて簡単なパスをテストする何百もの合成ケースに勝る。

エージェントの出力の採点にLLMを使うべきか?

出力が構造化されている場所では(有効なJSON、正しいフィールド、正しいツール呼び出し)どこでも厳格なアサーションを使う——無料で決定論的だ。トーンや有用性のようなオープンエンドな性質には、具体的なルーブリックと強いジャッジモデルを伴うLLMジャッジを取っておく。そうすればノイズではなく信号が得られる。

プロンプト変更が静かに本番を壊すのをどう止めるか?

すべての変更前に評価ハーネスを走らせ、ベースラインと差分を取り、集計スコアだけでなくケースごとの回帰を見守る。そして結果でデプロイをゲートし、ベースラインの閾値を下回る変更は失敗したテストのようにブロックする。

評価における非決定論をどう扱うか?

分散を減らすために温度0で実行し、ちらつくケースは複数回実行して、単一実行ではなく合格率で採点する。10回中9回通過するケースは、単一実行で両方とも緑を示すとしても、10回中5回通過するケースより健全だ。

続きを読む

AIプレイブックをメールでお届け

毎週水曜。28,400人以上の読者。無駄なし。

↵ すべての結果を見る esc esc で閉じる