評価ハーネス
評価ハーネス(zeroclaw eval run、クレート crates/zeroclaw-eval)は、エージェント評価の_ケース_(JSONトレースフィクスチャ)を実際のエージェントループに通し、各実行を宣言的な期待値に照らして採点します。ZeroClawは、これによってエージェントループの動作(ツールディスパッチ、複数ターンの順序、応答フォーマット、拒否応答)が回帰していないかを検証しています。
It は [agent.eval](ループ内の応答品質スコアラー)とは別物です。ハーネスは [eval] の下で設定され、CLI サブコマンドとして呼び出されます。
モード
| モード | 何をするものか | コスト | CI |
|---|---|---|---|
replay | フィクスチャからスクリプト化された LLM の応答をエージェントループに再生します。完全に決定論的で、ネットワーク通信は発生しません。 | 無料 | ゲート制御(デフォルト) |
live | 実際のプロバイダーに対してケースを実行します(予定。ライブモードのセクションが追加され次第、そちらを参照してください)。 | 実トークン | Never by default |
Suiteの分類
Suite は *.json フィクスチャを格納するディレクトリです(evals/README.md を参照):
evals/regression/: 常に100%の合格を維持する必要があります。CIではcrates/zeroclaw-eval/tests/regression_suite.rsによってゲートされ、失敗するとマージがブロックされます。これはデフォルトの[eval].suite_dirです。evals/capability/(計画中):合格率の低い難しいタスク。経時的に追跡するが、ゲートには使用しない。evals/live/(計画中): 実際のプロバイダーに対して実行されるケース。CI ではデフォルトで実行されない。
実行中
# デフォルトのリグレッションスイートを再実行する
zeroclaw eval run
# 特定のスイートを指定し、機械可読な JSON を出力します:
zeroclaw eval run --suite evals/regression --format json
--suite は [eval].suite_dir を上書きします。--mode は [eval].mode を上書きします。スイートの読み込みは非再帰的で、スイートディレクトリ直下の *.json ファイルのみがケースとして扱われます。
終了コードの契約
zeroclaw eval run は、すべてのケースが合格した場合に 0 で終了し、それ以外(失敗したチェックまたは実行エラーがある場合)は 1 で終了します。これは CI のゲートであり、プロセスの終了コードがシグナルとなります。同じ判定は純粋関数 SuiteReport::exit_code() としても公開されており、その実際の境界でテストできるようになっています。
大文字・小文字の形式
この各フィクスチャは LlmTrace です。model_name、会話の turns のリスト(各ターンは user_input と、スクリプト化された応答の steps を持つ)、そして宣言的な expects で構成されます。ケースは正例(必ず発生すべき動作)か負例(発生してはならない動作。例: tools_not_used、response_not_contains、max_tool_calls: 0)のいずれかです。作成ルール(二人の専門家テストやプライバシー要件を含む)は evals/README.md を参照してください。フィクスチャではプレースホルダーの識別情報のみを使用する必要があります。
dispatch boundary をスクリプト化されたテキストではなく評価する期待値(tool_arguments_contain、tool_results_contain、exact_tool_calls)は、crates/zeroclaw-eval/README.mdに記載されています。ケースで値がツールを経由してラウンドトリップしたことや、ツール呼び出しが特定の回数行われたことを主張する場合には、これらを使用してください。最終応答だけに対する期待値では、リプレイプロバイダーがその応答自体をスクリプト化しているため、どちらも示せません。記録された呼び出しリストが正規のディスパッチの事実です。ツール名と全体の成功判定は採点時にこのリストから導出されるため、より豊富な境界の証拠を追加しても、独立して変更可能な第二のツール呼び出しサマリーが生まれることはありません。
フィクスチャの読み込みはフェイルクローズドで動作します。必須のゲートは、失敗しえないケースを合格と認定してはならないためです。LlmTrace::from_file() は、会話ターンを一つも宣言していないフィクスチャを拒否します(リプレイはエージェントを0回しか動作させず、空の実行に対して期待値を評価することになるため)。また、期待値ブロックが省略されているか空のフィクスチャ、文字列ベースの期待値ファミリー(response_contains、response_not_contains、response_matches、tools_used、tools_not_used)に長さ0のエントリを含むフィクスチャ、未知のトップレベルキーまたは期待値キーを持つフィクスチャも拒否します。ディスパッチ境界のファミリーも同じ原則でフェイルクローズドとなります。空のtoolまたはneedle、無意味なmin_tool_calls: 0、互いに矛盾する回数の上限・下限は、いずれも読み込み時に拒否されます。すべての拒否は、問題のあるフィクスチャとフィールドを明示します。
Admissionは、依然として残っている空虚さの一形態を検出できません。それは、何も生成しない実行がすでに満たしてしまうアサーションです。例えば、単独の max_tool_calls: 0 などが該当します。ゲート付きスイートのテストは、コミットされたすべてのフィクスチャを空の実行に対して採点し、少なくとも1つの失敗したチェックを要求します。そのため、いかなる振る舞いも証明しないケースは必須ゲートに組み込めません。