AI Forge Eval(評価) は何をしますか?
スキルとエージェントの行動検証。ルーブリックスコアリング(ai-forge-judge)はアーティファクトが適切に記述されているかを示します。Evalはそれが実際に機能するかを示します。
SKILL.md(スキル)と.agent.md(エージェント)の両方で動作します。同じ5フェーズフローですが、フェーズ2のセットアップがアーティファクトの種類によって異なります。
フェーズ0 — スイートの読み込みまたは作成
必須 — references/eval-suite.md を読む:ディスク上のフォーマット、トリガープロトコル、アサーション判別テーブルを参照してください。
アーティファクトの隣に evals/evals.json があるか確認します。
- 存在する場合 — 読み込んでフェーズ2に進みます。カバレッジが薄い場合はケースを追加します。既存のものを静かに置き換えるとトレンドが壊れるため、絶対に行わないでください。
- 存在しない場合 — フェーズ1で作成し、何かを起動する前に
evals/evals.jsonに書き込みます。
この会話の中だけでしか存在しないスイートは、来月の回帰を検出できません。永続化することこそが、意見とテストを区別するものです。
フェーズ1 — 評価ケースの作成
2~3個の評価ケースを作成します。各評価は、現実的なプロンプトと3~5個のアサーションで構成されます。
プロンプトは、アーティファクト自体が明示するトリガーよりも、ベースラインプローブ(ai-forge-create フェーズ1b)から引き出したものを優先します。アーティファクトから記述されたアサーションは、それが主張することを確認できるだけだからです。各キャプチャはシナリオの baseline_failure フィールドに記録します。
スキルの場合: スキルを自然に起動するプロンプト。アサーションはスキル固有の動作をチェックします(例:「出力にフェーズ1の要約が含まれている」、「NEVERルールの形式にWHYとINSTEADがある」)。
エージェントの場合: エージェントの対象範囲をカバーするプロンプト。アサーションは観察可能な動作(作成されたファイル、呼び出されたツール、トーンの制約、スコープの制限など)をチェックします(例:「src/lib/ 外のファイルを変更しなかった」、「PRを開いた」、「コミットメッセージが 'refactor:' で始まる」)。
アサーションのルール:
- 検証可能:評価者が出力だけから検証できること
- 具体的:「出力は適切に構造化されている」より「出力に 'Phase 1' ヘッダーが含まれている」の方が優れている
- 反証可能:失敗する可能性がなければならない
評価ケースの記録:
評価1: <プロンプト>
期待値:
- <アサーション1>
- <アサーション2>
- <アサーション3>
フェーズ2 — 並列実行
各評価について、同じメッセージ内でアーティファクトありの実行とベースライン実行を同時に起動します(決して逐次実行しない)。ベンチマークモードでは、評価ごとにN回の試行ペアになります。以下のベンチマークモードを参照してください。
アーティファクトありの実行: 評価プロンプトを与えます。スキルの場合は「このタスクには <スキル名> スキルを使用してください。」を追加します。エージェントの場合は、エージェントの完全な指示をシステムコンテキストとして貼り付けます。
ベースライン実行: 何を測定するかによって異なります。
- 新しいアーティファクト — 同じ評価プロンプト、スキル指示なし、エージェントコンテキストなし。プレーンなアシスタント応答。
- 既存のアーティファクトの改善 — まず現在のバージョンをスナップショットします(
cp -r <path> <scratch>/snapshot/)。その後、ベースラインをスナップショットに向けます。「アーティファクトなし」は、変更が役立ったかどうかという問いに対する誤った対照群です。それはアーティファクトの存在を測定するものであり、編集内容を測定しません。
完了時に即座にキャプチャ: 各タスク通知が到着したら、どの実行(およびベンチマークモードでの試行インデックス)かを記録し、<usage> ブロックから duration_ms と subagent_tokens を読み取ります。正確な値で、推定は禁止です。<usage> ブロックがない場合は null を記録し、決して壁時計による推測で代用しないでください。このデータは通知時のみ存在し、後から再構築することはできません。
評価ごとに保存: with_artifact と baseline の出力テキスト、および各アームの duration_ms と tokens。
フェーズ3 — 採点
必須読書: agents/assayer.md
各評価について、両方の出力に対してアッセイヤーを呼び出します。以下を渡します:
出力: <出力テキスト>
期待値:
- <アサーション1>
- <アサーション2>
アッセイヤーは期待値ごとに以下を返します:
{ "text": "...", "passed": true, "evidence": "..." }
pass_rate = passed / total を実行ごとに計算します。
delta = with_artifact.pass_rate - baseline.pass_rate を計算します。
次に、各アサーションを両アームでの振る舞いによって分類します:両方で成功(モデルを測定、アーティファクトではない)、両方で失敗(壊れているか手が届かない)、アーティファクトありで成功・なしで失敗(真のシグナル)、アーティファクトありで失敗・なしで成功(アーティファクトが有害)、または高分散(不安定)。references/eval-suite.md のテーブルを参照してください。すべてのアサーションが両アームで成功するスイートは、健康な成功率を示しながら何も教えてくれません。
また、出力だけでなくトランスクリプトも読みます:実行は実際にアーティファクトに従ったのか、それともアーティファクトを無視して正しい答えに到達したのか?アーティファクトが原因で何も生成されなかった作業は、削除候補です。
フェーズ3b — 人間によるレビュー
自分で分析する前に、生の出力をユーザーの前に提示します。
assets/eval-review.html を埋めてください — __ARTIFACT_NAME__ と __EVAL_DATA__({id, name, prompt, with_artifact, baseline, assertions} のJSON配列)を置き換え、評価スイートの隣に書き込みます。ファイル配信ツールが利用可能ならそれで表示します。そうでなければ、ユーザーにパスを伝えます。ユーザーが完了したら、エクスポートされた feedback.json を読み込みます。
モデルが自身のアーティファクトの出力を採点することはここで最も弱いシグナルです — 人間の一瞥は、どのアサーションも捕捉するために書かれなかったものを捉えます。ユーザーが辞退した場合のみスキップします。
フェーズ4 — 比較(オプション)
必須読書: agents/arbiter.md — フェーズ4が実行される場合のみ読み込みます。
フェーズ4を実行するタイミング: 任意の評価でデルタが0.1を超える場合、または評価間で成功率が矛盾する場合。
スキップするタイミング: 成功率が同一の場合、またはユーザーが採点のみを要求した場合。
アービター入力: 出力A(ラベルなし)、出力B(ラベルなし)、期待値リスト。フェーズ5のためにどちらがどちらかを記録します。
アービターの返答: 内容スコア(1~5)、構造スコア(1~5)、勝者(A/B/引き分け)、根拠、各側の強み/弱み。
2つのバージョンを比較する場合の出荷ゲート: 新しいバージョンがすべてのシナリオで勝つか引き分け、かつ少なくとも1つで勝つ場合のみ出荷します。あるケースで大きく勝ち、別のケースで負けるバージョンは、1つの失敗を別の失敗と交換しただけです — それは改善ではなく、集計デルタはそれを隠します。
フェーズ5 — 分析とレポート
必須読書: agents/refiner.md — フェーズ4が実行された場合のみ読み込みます。
フェーズ4がスキップされた場合: 直接ベンチマークテーブルに進みます。
リファイナー入力: アービターの出力 + ラベルマッピング { "A": "with_artifact", "B": "baseline" }(または逆)。リファイナーは勝者が敗者をなぜ破ったかを説明し、優先順位付けされた1~3の改善点を提示します。
ベンチマークテーブルのレンダリング — 評価ごとに1行と Avg 行、列は 評価 | with_artifact | baseline | デルタ | 実行時間ms (あり / なし)、各アームの成功数とパーセンテージ。フェーズ3でフラグが立った非判別または有害なアサーションを追加し、その後リファイナーが実行された場合はその改善提案を追加します。
任意の評価でデルタが負の場合、「アーティファクトがパフォーマンスを低下させている可能性があります — トリガーの表現やスコープ制約を見直してください。」とフラグを立てます。
フェーズ6 — トリガーチェック
行動評価は「呼び出されたときに機能するか」に答えます。これは「呼び出されるか」に答えます — より一般的な失敗であり、上記のすべてのフェーズでは見えません。
スイートに triggers ブロックがある場合に実行するか、フェーズ5の後に提案します。必須 — references/eval-suite.md を読む:プロトコル、60/40のホールドアウト分割、クエリ品質基準を参照してください。行動評価のみの実行では読み込まないでください。
分割(トレインとホールドアウト)ごとの再現率と適合率、および具体的な取りこぼしと誤検出を報告します。低再現率・高適合率は説明が狭すぎることを意味します — 広げてください。逆は隣接タスクを横取りしていることを意味します — ネガティブトリガーを追加してください。
ベンチマークモード
ユーザーがベンチマーク、回帰追跡、またはトレンドゲートを要求した場合に起動します。ベンチマークモードは、5つのフェーズを反復試行と永続化されたトレンドストアで拡張します。
必須読書: references/benchmarking.md を実行前に読む — 試行プロトコル、集計式、ゲートしきい値、および試行結果+benchmark.json スキーマはそこにあります。プレーンな1回実行の評価では読み込まないでください。
- 試行 — 各評価はN回(デフォルト3回)実行されます。評価ごとに、すべてのN試行ペア(2Nサブエージェント)を1つのメッセージで起動し、フェーズ2ごとに
<usage>をキャプチャしながらその評価の通知を処理し、次の評価に移ります。決してすべての評価の試行を一度に起動しないでください。 - 集計 —
node scripts/aggregate-benchmark.cjs --trials <scratch.json> --prior benchmarks/<artifact-name>.json --artifact <path>は、評価ごとの平均/標準偏差、不安定性と判別フラグ、前回実行とのデルタ、ゲート判定を返します。実行できない場合(nodeがない、スクリプトがない、使用法エラー)、生の試行結果を⚠ 集計不可 — バリデータ利用不可: <理由>とともに報告し、ゲート判定を手計算しないでください。ゲート判定は統計的有意性に関する主張であり、推定してはなりません。FAILの判定は常にブロックします。 - 永続化 — 返されたペイロードを
benchmarks/<artifact-name>.json(コミットされる)に新しいトレンドベースラインとして保存します。 - レポート — 平均±標準偏差の列とゲート判定を含むフェーズ5のテーブル。ゲート失敗の場合、判定は「回帰 — 準備できていません」です。
NEVER(絶対にしてはいけないこと)
-
決して試行のwith_artifactとbaselineの実行を逐次的に起動しない 代わりに: 各試行の両アームを同じメッセージで。ベンチマークモードでは、1つの評価に対するすべてのN試行ペアを1つのメッセージにまとめます。異なる評価は逐次的にバッチ処理しても構いません。 理由: 逐次アームはフィードバックを直列化します。しかし、すべての評価の試行を一度に起動すると通知が溢れ、到着ごとの
<usage>キャプチャが信頼できなくなります。 -
決して他の実行が完了するまで使用量キャプチャを延期しない 代わりに: 各通知の
<usage>ブロック(duration_ms、subagent_tokens)を到着した瞬間に読み取ります。 理由:<usage>データは通知時にのみ存在し、後から再構築できません。 -
決して1回の試行をベンチマークとして報告しない 代わりに: 平均と標準偏差が意味を持つように少なくともN=3回の試行を実行します。 理由: 単一の成功率は正確に見えますが、不安定性を隠します — 実際には3分の1の確率で合格するスキルが、1回の試行では100%または0%と読める可能性があります。
-
決してwith_artifact実行が失敗したシナリオを弱めない 代わりに: 実行がシナリオをそのまま通過するまで本体を強化します。 理由: シナリオは実際の失敗の記録です。それを弱めると、評価は緑色になる一方で、捕捉するために作られた失敗は手つかずで残ります。
-
決して説明をホールドアウトのトリガークエリに対してチューニングしない 代わりに: トレイン分割で反復し、最終バージョンを選択するためだけにホールドアウトを確認します。 理由: 自身のテストセットに対してチューニングされた説明はスコアは良いが一般化が悪くなります — 唯一の不偏推定値を失うことになります。
-
決して主観的なアサーションを書かない(「出力は明確」、「適切にフォーマットされている」、「徹底している」) 代わりに: テキストから検証可能:「出力に 'Phase 1' 見出しが含まれている」、「WHY節のないNEVERルールがない」 理由: 主観的なアサーションはアッセイヤーに真実の根拠を与えません。合格/不合格が恣意的で再現不可能になります。
-
決してwithとbaselineの実行で異なるプロンプトを使用しない 代わりに: 同一プロンプト — アーティファクト指示のみが異なります。 理由: プロンプトのバリエーションはデルタを混乱させます。プロンプト品質を測定することになり、アーティファクトの効果を測定しません。
-
決して非標準のフィールド名を持つアッセイヤー出力を受け入れない 代わりに:
text、passed、evidenceを厳密に要求 —name、met、detailsなどは拒否します。 理由: フェーズ5の集計は正確なフィールド名に依存します。静かに間違った名前は間違った成功率を生成します。