AI エージェントを本番運用し始めた瞬間、必ず直面する問題があります:
「このエージェント、本当に大丈夫?」
人間がちょっと触って「それっぽく動く」ことは分かる。でも、1 万回使われたら何パーセント失敗するのか、どういう入力で破綻するのかは、見えない。
伝統的なソフトウェアテスト(unit test / integration test)では、AI エージェントの品質を担保できません。AI エージェント用の評価(evaluation、略して evals) という別の仕組みが必要です。
本稿では、
- なぜ unit test では足りないのか
- Evals の 3 層構造(Unit evals / Integration evals / End-to-End evals)
- LLM-as-a-judge の使い方と落とし穴
- 統計的に意味のある評価サンプル数
- 本番モニタリングと evals の関係
- 実装パターン(最小構成)
を整理します。
なぜ unit test では足りないのか
伝統的なソフトウェアテスト
test("add function", () => {
expect(add(1, 2)).toBe(3);
expect(add(0, 0)).toBe(0);
});
これは、入力と期待出力が確定 しているので動きます。add(1, 2) の答えは 3 で、永遠にそう。
AI エージェントの出力は非決定
test("agent writes a Python function", () => {
const result = await agent.run("Write a Python function that reverses a string");
// ... 何をチェックすればいい?
});
LLM の出力は、
- 同じ入力でも違う出力(temperature、ランダム性)
- 複数の正解がある(
[::-1]でもreversed()でも''.join(...)でも OK) - “正しい” の基準が曖昧(コードが動けば良い? 可読性も? パフォーマンスも?)
単純な expect(x).toBe(y) では捉えられません。
評価の軸が複数ある
AI エージェントの「良さ」は 1 次元ではありません:
- 正確性: 答えが合っているか
- 網羅性: 必要な情報が全部入っているか
- 形式: 要求されたフォーマットに沿っているか
- トーン: 読み手に合った言い方か
- 安全性: 害のある内容を含まないか
- 効率: 無駄なトークンを使っていないか
全部を 1 つの数値にまとめると、どこが悪いか分からなくなります。
Evals の 3 層構造
ソフトウェアテストに unit / integration / E2E があるように、evals にも層があります。
Layer 1: Unit evals — プロンプト単位の評価
対象: 1 つのプロンプトに対する 1 ターンの応答。
例:
- 「このテキストを英訳して」というプロンプトに対して、翻訳の品質を評価
- 「このコードをレビューして」というプロンプトに対して、指摘の網羅性を評価
評価方法:
- 期待出力との match(厳密 / セマンティック)
- LLM-as-a-judge によるスコア
- カテゴリ分類(good / acceptable / bad)
サンプル数: 50-200 件、カテゴリごとに最低 20 件。
実装: GitHub の braintrust, promptfoo, openai evals 等。
Layer 2: Integration evals — ツール連鎖の評価
対象: エージェントがツールを使ってタスクを完遂できるか。1 ターンではなく、複数ターンのツール呼び出しを含む。
例:
- 「このバグを直して PR を出して」というタスクに対し、
git・ファイル編集・テスト実行・コミット・PR 作成の全ツール連鎖 - 「このドキュメントを検索して要約」の web search + 読み込み + 要約
評価方法:
- タスク完了率(Success Rate)
- 中間ステップの正しさ(Trajectory analysis)
- ツール呼び出しの効率(無駄な呼び出しがないか)
サンプル数: 20-100 件。1 件あたりが重いので、unit evals より少なめ。
実装: カスタム harness が必要なことが多い。
Layer 3: End-to-End evals — ユースケース単位
対象: 実ユーザーのシナリオをエージェントが完結できるか。
例:
- 「顧客サポートチャットで、不満を持った顧客を満足させて帰す」
- 「Deep Research で、2026 年の AI 市場レポートを 10 ページ書く」
評価方法:
- 人間のレビュー(最も信頼できるが遅い・高い)
- LLM-as-a-judge
- A/B テスト(本番トラフィックで)
サンプル数: 10-50 件。シナリオを変えて多様性を確保。
実装: 本番環境に近い整備が必要。モックしたバックエンド、合成ユーザーなど。
LLM-as-a-judge — 使い方と落とし穴
評価の自動化で避けて通れないのが LLM-as-a-judge:別の LLM にスコア付けさせる手法。
基本パターン
async function judge(input: string, output: string, criteria: string): Promise<number> {
const prompt = `
以下の出力を、次の基準で 1-5 のスコアで評価してください。
## 入力
${input}
## 出力
${output}
## 基準
${criteria}
スコアと理由を JSON で返してください。
`;
const result = await claude.messages.create({ ... });
return parseInt(result.text);
}
使いどころ
- 主観性の高い評価: 自然さ、読みやすさ、トーン
- 多数の候補からの選定: A と B のどちらが優れているか
- 形式適合性のチェック: 要求された構造に沿っているか
落とし穴 1: Judge のバイアス
LLM-as-a-judge には、よく知られたバイアスがあります:
- Length bias: 長い回答を高く評価しがち
- Position bias: A/B 比較で先に出された方を優先しがち
- Self-preference: 自分と似たスタイルを高く評価
- Verbosity bias: 具体的な理由を書いた方を高く評価
対策
- 複数 judge の投票: Claude judge, GPT judge, Gemini judge の多数決
- 位置のランダム化: A/B 比較は半々で順序を入れ替える
- ルーブリックの明示: 「このスコアはこういう場合に出す」を細かく指定
- 人間との整合性チェック: 100 件を人間が評価、judge のスコアと比較、相関係数を測る
落とし穴 2: Reward hacking
Judge が特定のパターンを好むと、エージェントがそれを exploit するようになります。
例: 「ステップバイステップで」と書くと judge のスコアが上がると分かったら、エージェントは意味なく「ステップバイステップで」を含めるようになる。
対策
- Judge のプロンプトを頻繁に更新
- 複数の judge をローテーション
- 人間レビューを定期的に挟む(spot check)
統計的妥当性のためのサンプル数
典型的な数
- 1 プロンプトのバリアント比較: 50-100 件
- モデル間比較: 200-500 件
- 本番 KPI の推定: 1000 件以上
Rule of thumb
95% 信頼区間で ±5% の精度が欲しいなら、約 400 件が目安。
サンプル数 ≈ (1.96 / 0.05)² × 0.25 ≈ 400
ただし、評価対象が偏りがあるなら(例: タスクの難易度が様々)、カテゴリごとに 20-50 件は必要。
継続的評価
リリースごとに全 1000 件を回すとコストがかかりすぎるので、
- Full regression: リリース前に 1000 件
- Smoke test: 毎日 50 件(代表的なサブセット)
- Canary: 本番トラフィックの 1-5%(新バージョン)
という階層にします。
本番モニタリングと evals の関係
Evals はリリース前
本番に出す前に「品質が許容範囲か」を数値で担保する。
本番モニタリングはリリース後
実トラフィックで、
- 成功率: タスクが完了する割合
- 失敗率: エラーが出る割合、分類
- レイテンシ: 応答時間
- コスト: 1 リクエストあたりのトークン消費
- ユーザーフィードバック: thumbs up/down
両方のループ
Evals (リリース前) → 本番 → モニタリング → 失敗事例を収集
↑ ↓
← Evals データセットに追加(失敗事例を eval 化)
本番で失敗したケースを、次のリリースの eval に組み込む のが、品質を上げ続けるループ。
最小実装 — 50 行で始める
Promptfoo で始める
promptfoo は、OSS の prompt eval ツール。設定は YAML 1 枚:
# promptfooconfig.yaml
prompts:
- "Translate to Japanese: {{text}}"
providers:
- anthropic:messages:claude-sonnet-5
- openai:chat:gpt-5
tests:
- vars:
text: "Hello, world"
assert:
- type: contains
value: "こんにちは"
- vars:
text: "I love you"
assert:
- type: llm-rubric
value: "日本語として自然な愛情表現を含むこと"
npx promptfoo eval で全プロバイダ × 全テストを一括実行。結果が web UI で見られる。
自作する場合
// evals.ts
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
type EvalCase = {
input: string;
judge: (output: string) => Promise<boolean>;
};
async function runEvals(cases: EvalCase[]) {
const results = await Promise.all(cases.map(async (c) => {
const output = await agent.run(c.input);
const passed = await c.judge(output);
return { input: c.input, output, passed };
}));
const passRate = results.filter(r => r.passed).length / results.length;
console.log(`Pass rate: ${(passRate * 100).toFixed(1)}%`);
return results;
}
const cases: EvalCase[] = [
{
input: "What is 2+2?",
judge: (out) => Promise.resolve(out.includes("4")),
},
{
input: "Translate 'cat' to Japanese",
judge: async (out) => {
const result = await client.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 100,
messages: [{
role: "user",
content: `この翻訳は 'cat' の正しい日本語訳ですか: "${out}". yes か no で答えてください。`,
}],
});
return result.content[0].text.toLowerCase().includes("yes");
},
},
];
runEvals(cases);
これだけで、プロンプトごとに pass/fail を自動判定できる最小構成が動きます。
MulmoTerminal / MulmoClaude での実運用
MulmoTerminal や MulmoClaude のような長時間動くエージェントでは、以下の層で evals を回します:
Layer 1: 単発プロンプトの evals
- プロンプトテンプレートを変更したときに走る regression suite
- 50-200 件のカテゴリ別テスト
Layer 2: Tool chain の evals
- 「GitHub issue から PR を作る」のようなタスクに対する完了率
- カスタムベンチマークを 20 件維持
Layer 3: Round table / 複雑シナリオの evals
- Multi-agent 対話の品質を LLM-as-a-judge で評価
- 10-30 件のシナリオ、月 1 で回す
Singularity Society BootCamp の第 4 期では、参加者も自分のプロダクトごとに eval suite を作る前提で動いています。
まとめ
- AI エージェントは unit test では捉えられない。Evals が必要
- 3 層構造: Unit (プロンプト単位) / Integration (ツール連鎖) / E2E (ユースケース)
- LLM-as-a-judge は便利だが、length bias / position bias / reward hacking 等の落とし穴
- 統計的妥当性にはカテゴリごと 20-50 件、全体で 400 件以上
- Evals はリリース前、本番モニタリングはリリース後、両方のループを回す
- Promptfoo で始めるか、50 行で自作する
- MulmoTerminal / MulmoClaude のような長期エージェントでは 3 層のそれぞれで eval
「それっぽく動く」から「数値で担保」に移行する のが、AI エージェントを本番で使う覚悟です。
関連リンク
- Anthropic Engineering Blog の歩き方 — Evals シリーズ参照
- 「Building Effective Agents」を実務に落とす
- Context Engineering 入門
- Claude Code のベストプラクティス
- Promptfoo (OSS eval ツール)
- MulmoTerminal — 並列エージェントのコックピット
Singularity Society はテクノロジー集団として MulmoClaude / MulmoTerminal / MulmoCast を開発しています。エンジニア・起業家向けの実践プログラム BootCamp も運営しています。

