AIエージェントの評価:evals を作って「雰囲気」ではなく信頼性を数値で測る
AIエージェントの評価とは、固定した実タスクのセットを定期的に実行し、結果を自動で検証して指標を集計することです。数回の成功したセッションの印象で判断するものではありません。重要なのは pass@k(k回の試行のうち少なくとも1回成功する)だけでなく pass^k(k回すべてが成功する)も測ることです。無人で仕事を任せられるかどうかは安定性で決まるからです。
エージェントが動いているのが見えるのに、なぜ評価が必要なのか
実は、見えているからこそ分かりにくいのです。プロンプトを直した後、1週間エージェントが一度も立ち往生しなかったとします。それは修正の効果でしょうか、それとも単に簡単なタスクばかりの週だったのでしょうか。あるエンジニアは新しいテンプレートが全てを変えたと確信し、別のエンジニアは同じログを見ても違いに気づきません。二人とも、何も数えていない限りは正しいのです。
AIエージェントの評価(evals)は、印象を数字に置き換えます。固定したタスクのセットを用意し、エージェントを走らせ、結果を自動で検証し、変更の前後で指標を比べます。そうすれば「良くなったかどうか」という議論は、権威ではなく表で決まります。
評価がなければ、プロンプト、AGENTS.md、ツールセット、モデルのどれを変えてもそれは手探りの賭けです。評価があれば、測定可能な結果を伴う実験になります。
なぜ「雰囲気」で判断すると間違えるのか
エージェントの働きぶりに対する印象には、体系的な誤りが三つあり、どれも誤った確信へ向かわせます。
- 生存者バイアス。うまくいった実行は記憶され、同僚にも見せられます。失敗した実行は再実行されて忘れられます。成功した実行だけで計算した信頼性は、エージェントがどこで本当に壊れるのかを何も語りません。
- 小さすぎるサンプル。エージェントが半分の確率で成功するとしても、三つの課題が連続して成功するのは珍しいことではありません。その確率は 0.5³ = 12.5%、つまりおよそ8回に1回の連続です。
- 自信に満ちた口調。エージェントは、本当に通っているときも通っていないときも同じ自信で「完了しました、すべてのテストが通っています」と書きます。モデルの自信は較正されていません。回答の口調は正しさのシグナルではありません。
ここから導かれるルールは、記録されず再計算もされていないものは、測定されていないものとみなす、ということです。
pass@k と pass^k:混同されやすい二つの指標
エージェントは非決定的です。同じタスクを繰り返すと、成功することもあれば失敗することもあります。そのため、一つのタスクを複数回実行し、次の二つの指標のどちらかを計算します。
pass@k:k回の試行のうち少なくとも1回成功する
この指標はコード生成の評価から来ています。「複数回の試行を与えれば、システムはそもそもこのタスクを解けるか」という問いに答えます。人間が複数の候補から最良のものを選ぶ場合や、信頼できる自動検証が失敗を取り除く場合には、公正な指標です。
pass^k:k回すべてが成功する
この指標は別の問いに答えます。「エージェントはこのタスクをどれほど安定して解けるか」です。監視なしの作業、すなわちエージェントを何度も走らせ、失敗のたびにお金や時間がかかる状況を表します。
両者の差は非常に大きくなりえます。エージェントが1回の試行で70%の確率でタスクを解き、試行は独立しているとします。
| k | pass@k = 1 − 0.3^k | pass^k = 0.7^k |
|---|---|---|
| 1 | 70% | 70% |
| 3 | 97.3% | 34.3% |
| 5 | 99.8% | 16.8% |
| 10 | 約 100% | 2.8% |
pass@5 で見ればエージェントはほぼ完璧に見えますが、pass^5 で見れば信頼できません。どちらの数字も正しく、ただ異なることを表しています。エージェントを自律的に働かせるつもりなら、pass^k を見てください。実際の作業で目にする姿に近いのはそちらです。
実践での計算方法
各タスクを n 回(例えば5回)実行し、成功回数 c を記録します。pass^k については、k回連続で成功した実行の割合が近似値になります。より簡単には、成功確率を p = c / n と見積もり、k乗します。タスクのセット全体については、タスクごとの値を平均します。
import json
from statistics import mean
# results.jsonl: {"task": "add-pagination", "runs": [true, true, false, true, true]}
rows = [json.loads(line) for line in open("results.jsonl")]
def pass_at_k(runs, k):
p = sum(runs) / len(runs)
return 1 - (1 - p) ** k
def pass_pow_k(runs, k):
p = sum(runs) / len(runs)
return p ** k
for k in (1, 3, 5):
print(k,
round(mean(pass_at_k(r["runs"], k) for r in rows), 3),
round(mean(pass_pow_k(r["runs"], k) for r in rows), 3))
n が小さい場合、p の k乗による見積もりは粗いものです。しかしハーネスのバージョン同士を比べるには、通常これで十分です。より重要なのは、比較のあいだで n とタスクのセットを変えないことです。
評価用のタスクセットの作り方
タスクセットは最も重要な資産です。悪いタスクで測った優れた指標は、間違ったものを測っています。
自分の現実からタスクを取る
SWE-bench のような公開ベンチマークはモデルの比較には有用ですが、そのタスクは選び抜かれています。説明は明確で、テストも用意されています。自分のリポジトリでは要件があいまいで、テストが一部欠けていることも多いため、ベンチマークの数字は、実際にエージェントが見せる結果よりほぼ常に高く出ます。最良の情報源は、クローズしたチケットと、ログに残るエージェントの実際の失敗です。
セットの構成
- 最初は20〜50タスク。少なすぎるとノイズがバージョン間の差を飲み込みます。多すぎると実行が高価になり、誰も回さなくなります。
- 種類を混ぜる:新機能、バグ修正、リファクタリング、他モジュールでの作業、罠のあるタスク(正解が「そのやり方はしてはいけない」や「確認が必要」であるもの)。
- 作業中に失敗したタスクはテストになる。エージェントがどこで弱いかが分かるにつれてセットは育ち、回帰が気づかれないまま戻ってくることがなくなります。
- 固定された初期状態:特定のコミット、固定された依存関係、同一の環境。そうしないと、エージェントではなく環境のずれを測ることになります。
タスクの形式
各タスクは、説明、初期状態、人手を介さず確認できる成功基準からなります。
id: add-pagination
repo_ref: 3f2c1ab
prompt: |
GET /payments にページングを追加する。パラメータは limit(既定 20、最大 100)と
cursor。レスポンスには next_cursor を含める。
check:
- pytest tests/test_payments_pagination.py
- mypy app/
limits:
max_changed_files: 6
成功基準は、コマンドで書かれた Definition of Done だと考えてください。タスクの成功基準をコマンドで書けないなら、それはエージェントに渡すタスクも曖昧だというサインです。
自動検証か LLM 審判か
結果の検証はコードでも、別のモデルでも行えます。それぞれに得意な範囲があります。
| 自動検証(コード) | LLM 審判 | |
|---|---|---|
| 何を見るか | テスト、型、リンター、E2E、差分の大きさ、禁止ファイル | 要件への適合、読みやすさ、スタイル、説明の質 |
| 決定性 | 完全 | なし:評価は実行ごとに揺れる |
| コスト | ほぼゼロ | タスクごとにモデル呼び出しがもう一回 |
| 主なリスク | すべてを見ない:テストは緑でも機能が違う | 自信に満ちた誤った解答に審判が同意してしまう |
ルール:まずコード、審判は上乗せ
決定的に検証できるものは、決定的に検証してください。LLM 審判は、コードでは表現できない性質にだけ追加し、テストの代わりに使うことは決してしないでください。
LLM 審判を役立てるには
- 生成側と文脈を分ける。審判にはエージェントの推論を見せず、タスク、基準、最終的な差分だけを渡します。そうしないと同じ誤りを繰り返します。これは N バージョン化、つまり一つの視点の代わりに独立した二つの視点を持つことに当たります。
- 「10段階で評価して」ではなく、ルーブリック。「limit > 100 の検証があるか」「app/payments 以外のファイルが変更されたか」のように、はい/いいえで答えられる具体的な質問にします。
- 人手の採点で較正する。20〜30件の結果を手で採点し、審判の判定と比べます。一致率が低ければ、審判を信頼するのではなくルーブリックを直します。
- 誤りの非対称性。誤った「完了」は、誤った「未完了」よりも高くつきます。前者は本番に流れ、後者は再実行の一回分で済むからです。迷ったら却下するように審判を設定してください。
成功率以外に数えるべき指標
解けたタスクの割合は表面にすぎません。どこを直すべきかを知るには、古典的な工学の信頼性指標が必要です。
- MTBF:エージェントが行き詰まるまでに進めるステップやタスクの数。どれほどまれに壊れるかを示します。
- MTTR:失敗後に作業可能な状態へ戻るまでの時間。これを下げるほうが、MTBF を上げるよりたいてい安上がりです。良い進捗ファイルと再現可能な環境は、復旧を何倍も速くします。
- 影響範囲:一つの失敗したステップがどれだけのコードを壊すか。差分の上限と作業コピーの分離で抑えます。
- 誤った「完了」の割合:エージェントが成功を宣言したのに、検証が失敗したタスクの割合。最も危険な指標です。エージェントの報告を信じてよいかどうかを、この数字が示します。
- コストと時間:タスクあたりのトークンと分数。成功率を5%上げても、コストを2倍にしたハーネスが常に勝つとは限りません。
失敗ログ:日常の作業からの評価
すぐに評価の実行基盤を作れないチームもあります。その場合の最小版は、三列の失敗ログです。
| タスク | 結果 | 層 |
|-------------------------|------------------------------------|---------------|
| /payments のページング | 「完了」、テスト2件が赤い | 検証 |
| webhook のタイムアウト修正 | pip install に30分 | 環境 |
| refunds のリファクタリング | 古い ORM の構文 | 文脈 |
「層」とは、エージェントが壊れる五つの場所のいずれかを指します。タスクの仕様、文脈、実行環境、検証のフィードバック、状態の管理です。20件ほど記録すると、本当のボトルネックが見えてきます。そしてそれが、思っていた場所にあることはほとんどありません。ログの各行は、評価タスクの候補になります。
強力なモデルでも解決しない理由
エージェントが失敗したときの最初の反応は、より高価なモデルに替えることです。それで改善することもありますが、多くの場合、ベンチマークと自分の現実との間のギャップを埋めるのはモデルではなく、その周りの環境です。
エージェントが環境構築に30分かけているなら、それは環境の層の問題です。最先端のモデルでも同じ30分をかけるでしょう。テストが赤いのに「完了」と言うなら、それは検証の層の問題です。真実を教えてくれるコマンドがないのです。エージェントがプロジェクトと違う書き方をするなら、プロジェクトの規約を与えていないだけです。どれもモデルの知能の問題ではありません。
評価はこれを公正に確かめさせてくれます。現在のモデルと、より高価なモデルでタスクセットを回します。次に、現在のモデルで AGENTS.md に検証コマンドを加えた場合を回します。多くの場合、後者のほうが前者よりも大きな改善をもたらし、しかもコストはゼロです。ただし、それを言葉どおりに信じないでください。このような比較のためにこそ、タスクセットがあるのです。
一週間で始める評価のステップ
- 1日目。失敗ログを作り、エージェントの失敗のたびに層を明記して記録します。
- 2日目。クローズしたチケットと失敗ログから20タスクを選びます。各タスクのコミットを固定し、成功基準をコマンドで書きます。
- 3日目。実行スクリプトを書きます。クリーンな作業コピー、タスクのプロンプトでエージェントを起動、検証コマンドを実行、結果を JSONL に書き込みます。
- 4日目。各タスクを3〜5回実行します。pass@1、pass^3、誤った「完了」の割合、タスクあたりの平均コストを計算します。
- 5日目。ハーネスの一か所を変えて、もう一度実行します。タスクセットと試行回数が同じ場合にのみ比較します。
変数は一度に一つずつ変えてください。一回の実験でモデル、プロンプト、ツールを同時に変えると、何が効いたのか分かりません。
エージェント評価でよくある間違い
- タスクごとに一回だけ実行する。エージェントの非決定性のせいで、その結果は運任せになります。最低3回は繰り返してください。
- 比較のあいだにセットが変わる。新しいタスクを足し、同時にプロンプトも変えると、数字は比較できなくなります。
- エージェントが検証テストを見られる。テストがリポジトリにあると、エージェントはコードをテストに合わせたり、テストそのものを書き換えたりできます。検証は作業コピーの外に置き、エージェントがテストファイルに触れていないことを確認してください。
- 検証の代わりにエージェントの報告を使う。モデルの回答にある「すべてのテストが通りました」は結果ではありません。結果は、評価スクリプトが実行したコマンドの終了コードです。
- pass@k だけを見る。プレゼン用には見栄えがよくても、自律作業の予測としては悪い数字です。
まとめ
AIエージェントの評価とは、固定した実タスクのセット、自動検証、そしてハーネスの変更のたびに再計算される指標のことです。pass@k はエージェントに何ができるかを示し、pass^k はそれを監視なしで信頼できるかを示します。自動検証は真実を与え、ルーブリックと独立した文脈を持つ LLM 審判は、コードでは届かない部分を補います。五つの層に沿った失敗ログは、まず何を直すべきかを示します。それはたいてい、モデルではありません。信頼性の指標と診断ループは、講座のハーネスエンジニアリングの回で実践的に扱っています。
よくある質問
エージェントの評価にはタスクがいくつ必要ですか?
始めるには、自動の成功基準を持つ実タスク20〜50件と、各タスクの3〜5回の繰り返しで十分です。小さすぎるセットでは改善とノイズを区別できず、大きすぎるとコストがかさみ、誰も回さなくなります。
公開ベンチマークだけでエージェントを評価できますか?
いいえ。公開ベンチマークはモデルを、選び抜かれたタスクと用意されたテストで比べるものです。自分のリポジトリの要件やテストは別物です。自分のハーネスについて判断するには、独自のタスクセットが必要です。
pass@1 と pass^1 の違いは何ですか?
ありません。試行が1回なら、どちらの指標も成功した実行の割合に等しくなります。両者が違ってくるのは k が2以上のときです。
LLM 審判はエージェントと同じモデルでもよいですか?
文脈が独立していれば構いません。審判はタスク、ルーブリック、最終的な差分だけを見て、エージェントの推論は見ません。ただし、その判定は依然として手動の採点と照らし合わせる必要があります。
評価はどのくらいの頻度で回すべきですか?
ハーネスに目立つ変更を加えるたびに回してください。プロンプト、指示ファイル、ツールセット、モデルが対象です。定期的なスケジュール実行も有効で、環境や依存関係のずれに気づけます。
このテーマはコース「Harness Engineering: инженерия надёжности AI-агентов」で実践とともに詳しく解説しています。
- Метрики надёжности AI-агента: MTBF, MTTR, радиус поражения и закон Литтла
- Почему AI-агент ломается в проде: пять слоёв отказа и диагностическая петля