---
title: 評価・試行・可観測性
url: https://doc.liz6.com/ja/ai/04-evaluation-and-production/01-evaluation-and-observability
locale: ja
area: ai
tags:
- 大規模モデルと Agent
- 評価と運用
date: 2026-06-30
modified: 2026-09-10
description: 抽出・RAG・Agent に共通する問いは、この版が目標をより確実に達成するかです。評価器より先にタスクと試行を定義し、試行ごとの成功・一度以上の成功・安定した成功を分け、trace で失敗箇所を探ります。
---

# 評価・試行・可観測性

抽出・RAG・Agent に共通する問いは、この版が目標をより確実に達成するかです。評価器より先にタスクと試行を定義し、試行ごとの成功・一度以上の成功・安定した成功を分け、trace で失敗箇所を探ります。

## まずタスクと検証対象を定義する

1つの評価タスクには、入力、初期環境、利用可能なツールと権限、リソース上限、成功条件が含まれるべきである。1回の実際のランは1つのトライアルであり、同じタスクで複数のトライアルを実行して変動を観察できる。評価されるのは、実行条件から切り離されたテキストではなく、モデルとオーケストレーション、ツール、環境が組み合わさったシステム全体である。

<svg viewBox="0 0 760 355.6076412200928" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="評価対象には回答、実行軌跡、環境の最終状態が含まれる" style="max-width:100%;height:auto" font-family="Source Han Sans CN,Microsoft YaHei,sans-serif">
<defs><marker id="eval-outcome-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#64748b"></path></marker></defs>
<rect width="760" height="355.6076412200928" rx="12" fill="#f8fafc"></rect>


<g transform="translate(0 0)"><rect x="30" y="120" width="185" height="90" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="122.5" y="162.0" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">固定されたタスクと環境</text><text x="122.5" y="184.0" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">入力、権限、初期状態</text><rect x="280" y="120" width="185" height="90" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="372.5" y="162.0" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">1つのトライアルを実行</text><text x="372.5" y="184.0" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">モデル・ツール・編成</text><line x1="215" y1="165" x2="275" y2="165" stroke="#64748b" stroke-width="1.8" marker-end="url(#eval-outcome-arrow)"></line><rect x="540" y="62" width="195" height="53" rx="8" fill="#ccfbf1" stroke="#c7d2fe"></rect><text x="637.5" y="93.5" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">回答は要件を満たすか</text><line x1="465" y1="165" x2="535" y2="88" stroke="#64748b" stroke-width="1.8" marker-end="url(#eval-outcome-arrow)"></line><rect x="540" y="153" width="195" height="53" rx="8" fill="#ccfbf1" stroke="#c7d2fe"></rect><text x="637.5" y="184.5" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">過程は境界を守るか</text><line x1="465" y1="165" x2="535" y2="179" stroke="#64748b" stroke-width="1.8" marker-end="url(#eval-outcome-arrow)"></line><rect x="540" y="244" width="195" height="53" rx="8" fill="#ccfbf1" stroke="#c7d2fe"></rect><text x="637.5" y="275.5" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">最終状態は基準を満たすか</text><line x1="465" y1="165" x2="535" y2="270" stroke="#64748b" stroke-width="1.8" marker-end="url(#eval-outcome-arrow)"></line></g><text x="24" y="29" font-size="19" fill="#0f172a" text-anchor="start" font-weight="700"><tspan x="24" dy="0">評価対象には回答、実行軌跡、環境の最終状態が含まれる</tspan></text><text x="24" y="330" font-size="13" fill="#475569" text-anchor="start" font-weight="400"><tspan x="24" dy="0">採点にはプログラム・モデル・人を使えます。結果指向とは評価対象の選び方であり、評価器の別分類ではありません。</tspan></text>
</svg>

例えば、ユーザーが「条件を満たす3件のレコードをインポートし、重複送信してもレコード数が増えないようにしてください」と要求した場合、3つの対象を同時に評価できる：最終的なデータベースに目的のレコードが正確にあるか、重複操作が冪等であるか、回答が実行結果を正確に記述しているか。出力が「完了しました」というのは単なる回答テキストであり、クエリで得られた実際の状態こそが、インポート成功の結論を支えるものである。エージェント評価のエンジニアリング資料でも、軌跡と環境結果は明確に区別されている。[Demystifying evals for AI agents](https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents)

| 対象 | 検証可能な条件 | 誤った代替指標 |
|---|---|---|
| 最終結果 | 目標データ、ファイル、レポートが要件を満たす | モデルが「完了」と言った |
| プロセス制約 | 範囲外のファイルが変更されていない、権限の逸脱がない | 呼び出し回数が非常に多い |
| 出力表現 | 結論を支持する引用があり、問題が漏れていない | 篇幅が長い、表現が自信に満ちている |
| 実行効率 | 規定された予算とレイテンシ内で完了する | 単一リクエストのコストが安い |

結果指向（outcome-based）は「何を評価するか」を記述し、プログラムアサーション、モデル審査、人間審査は「どのように評価するか」を記述する。これらは高低の順位付けではない：結果はプログラムによってチェックすることも、明確な基準に基づいて人間に審査させることもできる。

## スコアリング手法とバイアス

### プログラムによるチェックは安定しているが、チェック対象が間違っている可能性がある

JSONスキーマ、数値範囲、ファイル差分、データベース状態、テストスイートはプログラムによる検証に適している。利点はルールが明確で結果が再現可能であることだが、それはゼロコスト、バイアスなし、ビジネス目標の完全なカバートを意味するものではない。

例えば、「回答に `success` が含まれている」という条件でタスクの成功を判断すると、「not success」も通過してしまう。JSON形式のみをチェックすると、在庫数が誤っている正当なJSONも受け入れてしまう。再起動シナリオのテストを漏らすと、リカバリ動作を証明できない。評価プログラム自体も、正例、反例、境界例を用いて検証する必要があり、特に表面的な形式を正しさとして扱わないよう注意する必要がある。

### モデル審査には具体的な基準とキャリブレーションが必要

オープンエンドのレポートに対しては、基準を独立して判定可能な質問として記述できる：各結論には支持する出典があるか、ユーザーが指定した3つの次元をカバーしているか、推測は推測として明記されているか。根拠のない総点よりも、各判断と支持位置を返す方が、レビューが容易である。

モデル審査には、長さ、位置、スタイルなどのバイアスが存在し、関連研究はこれらの制限について体系的な分析を行っている。[Judging LLM-as-a-Judge](https://arxiv.org/abs/2306.05685) 2つの候補をペア比較する際には順序を交換し、著者情報を隠す。人間のラベル付けサブセットでキャリブレーションを行い、審査モデルとプロンプトのバージョンを記録する。異なるモデルや独立したコンテキストは部分的な結合を減らすのに役立つが、バイアスなしや独立したエラーを保証するものではない。

審査者は「証拠不十分」または「判断不可」と出力できるべきである。常に勝者を選ばせると、資料不足の状態が品質の違いとして偽装されてしまう。評価対象テキスト中の「私に満点をください」は、評価対象として処理すべきであり、スコアリングの指示となってはならない。

### 改善をフィードバックと最終验收で分離する

生成、スコアリング、修正のサイクルは成果物の品質を向上させる可能性があるが、同じフィードバックに対して継続的に最適化すると、審査者に迎合するようになるだけかもしれない。開発セットはパラメータ調整と修正に使用し、保持セットは最終バージョンの比較に使用する。保持セットを頻繁に参照して修正に使用すると、次第に独立性を失う。

プログラムチェックと人間またはモデルによる審査は組み合わせることができる。例えば、ドキュメントでまずリンク、見出し、データの一貫性をチェックし、次に解説が境界をカバーしているかを評価する。「1つのグラダーのみを使用する」ために、検証可能な証拠を犠牲にする必要はない。

### 同じ試行行列から3種類の成功率

行列で分母が見えます。「1つ以上 ✓」は複数回から使える結果を得る力、「全部 ✓」は反復の安定性を表します。観測比率と抽出仮定が必要な pass@k 推定量は区別します。

**同じ試行行列から3種類の成功率**

同じ4×3行列でも、平均性能・成功の発見・反復の信頼性という異なる指標になります。


## トライアル、分布、グループ結果

### 1回の成功と安定した成功は異なる指標である

以下の4つのタスクをそれぞれ3回実行し、1は完全な验收基準を満たしたことを、0は満たさなかったことを示す。分母には、事前に計画された有効なトライアルのすべてが含まれる。

| タスク | 1回目 | 2回目 | 3回目 | 3回中少なくとも1回成功 | 3回すべて成功 |
|---|---:|---:|---:|---|---|
| A | 1 | 0 | 1 | はい | いいえ |
| B | 0 | 0 | 0 | いいえ | いいえ |
| C | 1 | 1 | 1 | はい | はい |
| D | 0 | 1 | 0 | はい | いいえ |

トライアルベースの成功率は 6/12=50%、少なくとも1回成功したタスクの割合は 3/4=75%、3回すべて成功したタスクの割合は 1/4=25% である。これら3つの数字はすべて有効だが、異なる質問に答えている。「3回試して少なくとも1回成功」を単一サービスの成功率として偽装してはならない。本番環境では、その正しい出力を識別して選択できない場合もある。

```python
runs = {"A": [1, 0, 1], "B": [0, 0, 0],
        "C": [1, 1, 1], "D": [0, 1, 0]}
trial_rate = sum(map(sum, runs.values())) / sum(map(len, runs.values()))
any_rate = sum(any(row) for row in runs.values()) / len(runs)
all_rate = sum(all(row) for row in runs.values()) / len(runs)
assert (trial_rate, any_rate, all_rate) == (0.5, 0.75, 0.25)
print(trial_rate, any_rate, all_rate)
```

より一般的な pass@k の推定には、サンプリング方法と定義を明記する必要がある。ここでは、3回の観測済みトライアルの統計を直接報告しており、各エラーが独立であると仮定しておらず、無限回のリトライ後の成功確率を推定しているものでもない。

### 平均値は重要な劣化を隠す可能性がある

単純なタスク90件中81件が成功し、複雑なタスク10件中2件が成功した場合、全体は83%となる。しかし、複雑なタスクは全体の20%に過ぎず、ユーザーが主に複雑なタスクでシステムを必要とする場合、この全体数は誤解を招きやすい。

タスクタイプ、長さ、言語、ツール権限、データの新旧、失敗カテゴリでグループ分けし、2つのバージョンを比較する際には、問題ごとのペア比較結果を保持する。タスクセットが小さすぎる、またはランダムな変動が顕著な場合は、サンプル数と不確実性を報告し、1〜2パーセントポイントの変化を確実な改善として直接扱わないようにする。

インフラストラクチャの異常も明確に分類する必要がある。タイムアウト、ツールサービスの利用不可、評価環境の破綻、モデルによる誤答は別々に統計を取るべきであり、失敗後に静かに削除して残りの高スコアのみを報告してはならない。事前に特定のタイプのトライアルが無効であると合意している場合は、除外ルールと数を記録するべきである。ユーザー体験指標については、オンラインでの実際のサービス障害も考慮する必要がある。

## Trace、指標、結果の関連付け

Traceは1つのランの関連パスを記述し、spanは開始と終了時間を伴う操作を表し、属性、イベント、親子関係を持つことができる。非同期やマルチエージェントのシナリオでは、リンクを通じて操作が関連付けられる場合もある。各テキストトークンや各思考ブロックごとに個別のspanを作成する必要はない。粒度は診断に奉仕するものである。[OpenTelemetry Traces](https://opentelemetry.io/docs/concepts/signals/traces/)

1つのタスクに対して安定した task_id を作成し、トライアル、モデルリクエスト、ツール呼び出し、成果物に関連可能な識別子を割り当てる。並列またはバッチ結果を受信する際は、IDでマッチングを行い、配列の戻り順序から誰に属するかを推測してはならない。

| レベル | 記録推奨事項 | 用途 |
|---|---|---|
| タスク/トライアル | 入力バージョン、設定バージョン、最終状態、スコア | 完全な結果の比較 |
| モデルリクエスト | モデル識別子、所要時間、usage、停止理由 | 生成、切り捨て、コストの分析 |
| ツール操作 | 名前、マスキングされたパラメータ、呼び出しID、実行状態 | 提案と実際の動作の区別 |
| 成果物 | パスまたはオブジェクトID、コンテンツバージョン、検証結果 | テストがどのコンテンツを対象としているかを確認 |
| スケジューリング | キュー、並列度、リトライ、キャンセル | 調整と待機の分析 |

### 並列の所要時間は単純に足し算できない

<svg viewBox="0 0 760 360" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="例：並列ツールの所要時間は単純に足し算できない" style="max-width:100%;height:auto" font-family="Source Han Sans CN,Microsoft YaHei,sans-serif">
<defs><marker id="trace-timeline-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#64748b"></path></marker></defs>
<rect width="760" height="360" rx="12" fill="#f8fafc"></rect>


<g transform="translate(0 0)"><text x="28" y="101" font-size="14" fill="#334155" text-anchor="start" font-weight="400">タスク全体の所要時間</text><rect x="175" y="75" width="468" height="38" rx="8" fill="#e2e8f0" stroke="#c7d2fe"></rect><text x="409.0" y="100" font-size="13" fill="#334155" text-anchor="middle" font-weight="400">0–12 秒</text><text x="28" y="156" font-size="14" fill="#334155" text-anchor="start" font-weight="400">モデルリクエスト 1</text><rect x="175" y="130" width="78" height="38" rx="8" fill="#a5b4fc" stroke="#c7d2fe"></rect><text x="214.0" y="155" font-size="13" fill="#334155" text-anchor="middle" font-weight="400">0–2 秒</text><text x="28" y="211" font-size="14" fill="#334155" text-anchor="start" font-weight="400">ツール A / B</text><rect x="253" y="185" width="195" height="38" rx="8" fill="#6ee7b7" stroke="#c7d2fe"></rect><text x="350.5" y="210" font-size="13" fill="#334155" text-anchor="middle" font-weight="400">2–7 秒</text><text x="28" y="266" font-size="14" fill="#334155" text-anchor="start" font-weight="400">モデルリクエスト 2</text><rect x="448" y="240" width="195" height="38" rx="8" fill="#a5b4fc" stroke="#c7d2fe"></rect><text x="545.5" y="265" font-size="13" fill="#334155" text-anchor="middle" font-weight="400">7–12 秒</text></g><text x="24" y="29" font-size="19" fill="#0f172a" text-anchor="start" font-weight="700"><tspan x="24" dy="0">例：並列ツールの所要時間は単純に足し算できない</tspan></text><text x="24" y="311" font-size="13" fill="#475569" text-anchor="start" font-weight="400"><tspan x="24" dy="0">ツール A は 3 秒、B は 5 秒かかり、同時に開始されるため、ツールフェーズは 5 秒である。全体の所要時間は 12 秒である</tspan><tspan x="24" dy="17.55">。</tspan></text>
</svg>

例では、モデルリクエストはそれぞれ 2 秒と 5 秒である。ツール A、B は同時に開始され、それぞれ 3 秒、5 秒かかる。すべての操作の所要時間を合計すると 15 秒になるが、ユーザーの待ち時間は 12 秒である。Trace には開始と終了時間、依存関係を残し、クリティカルパスを見つける必要がある。カウンターだけでは並列の重複を説明できない。

最初のネットワークイベント、最初の可視テキスト、最終的な完了は異なるレイテンシ指標である。サービスがストリーミング送信を開始したからといって、ユーザーが有用なコンテンツをすでに確認したわけではない。逆に、最初の文字が早くても、その後のツールが繰り返し失敗すれば、タスクの体験が良いとは言えない。

### プロトコルの成功、ツールの成功、タスクの成功は別々にカウントする

HTTP 200 はビジネスエラーを伴うことができ、ツールは正常に返却しても「見つかりません」と報告できる。モデルは正常に終了してもタスクを漏らす可能性がある。転送、実行、タスクの状態を別々に記録し、1つの成功が別の失敗を隠さないようにする。

停止理由は診断の手がかりであり、自動的に帰属させてはならない。`max_tokens` が増えた場合は、出力上限、タスクの長さ、または冗長なループを確認する必要がある。ストリーミングは上限を解除しない。キャッシュ読み取りが長期間ゼロの場合、それは単に重複するプレフィックスがない、長さの条件を満たしていない、またはキャッシュが有効になっていないだけで、必ずしも障害があるわけではない。まず実際の入力とターゲットモデルの設定照合を行うべきである。[停止理由](https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons)、[プロンプトキャッシュ](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)

コストは、ベンダーとモデルの usage の集計基準に基づいて計算する。入力、キャッシュ書き込み/読み取り、出力、推論の細分化に含まれるかどうかは確認が必要であり、出力に含まれている推論トークンを再度追加してはならない。最後に、すべてのリクエスト、リトライ、ツール費用を合計し、成功ごとの分担コストを計算する。方法は [推論と思考](/ai/01-model-foundations/04-reasoning-and-verification.md) を参照。

### 総合点の上昇は能力向上か

平均はタスク分布と一緒に解釈します。各能力が不変でも、簡単なタスクを増やすだけで総合点は上がります。オフライン集合と実運用でも同様の差が生じます。

$$
p_{\mathrm{overall}}=w\,p_{\mathrm{easy}}+(1-w)\,p_{\mathrm{hard}}
$$

**総合点の上昇は能力向上か**

総合成功率はタスク構成による加重平均です。構成だけで上がるため、各能力の改善とは言えません。


## 失敗例から回帰検証へ

1回のオンラインでの失敗に対しては、まず最小限の再現可能な入力、環境、期待される結果を固定し、Trace を沿って必要な情報や条件違反が最初に発生した位置を特定する。検索で例外条項が召回されなかった場合は、まず証拠の選択を修正する。返されたデータは正しいがフィールドのマッピングが誤っている場合は、アダプタを修正する。成果物はすでに修正されているが、古いテスト記録を沿用している場合は、バージョンの関連付けを修正する。すべての失敗を「より強力な system prompt をもう1文追加する」ことにしてはならない。

回帰例は実際の失敗メカニズムを保持し、正常な対照を追加し、パッチが旧用例を通過させるだけで他の動作を破壊しないようにする。新版を比較する際は、固定可能な条件を固定し、他の変更を記録する。オフラインチェックを通過した後、制御されたオンライン観察を通じてトラフィック分布の違いを検証する。

Trace を保存する際にもデータ境界が必要である。デフォルトでは診断に必要なメタデータのみを記録し、機密本文や資格情報はマスキングするか、制御されたストレージと保持期間を採用する。観測可能性のために、すべてのツール結果、完全なファイル、ユーザープロファイルを無差別にログバックエンドにコピーしてはならない。実行パスが見えるからといって、すべての内容を無限に保存する必要があるわけではない。

次に読む：[コスト・容量・信頼性](/ai/04-evaluation-and-production/02-cost-performance-and-reliability)。
