9月28日、claude.devチームが「Automating eval design and hillclimbing with Claude / claude.dev Blog」と題した記事を公開した。LLMアプリのプロンプト改善で陥りがちな「evalへの過学習」を自動検出・巻き戻しする仕組みは、現場で繰り返し起きる問題への実践的な答えであり、評価設計の原則から自動化ツールの実装まで一気通貫で解説されている点が特徴的だ。
LLMを使ったアプリケーション開発において「evalを設計する」「evalを使って改善する」の2ステップは、言うは易く行うは難しい。eval(評価セット)とは、モデルやプロンプトの品質を定量的に測るためのテストケース集のことで、機械学習でいうテストスイートに相当する。過学習(overfitting)に気づかず無駄な改善を積み重ねたり、そもそも評価設計が実態からズレていたりする問題は、現場のエンジニアが頻繁に直面するところだ。
claude.devチームは、こうした問題を解決するための原則と、それを自動化したclaude-apiスキルを公開した。スキルとはClaude Codeから呼び出せるコマンド群のことで、今回のツールはClaude Code自体の組み込み機能ではなく、claude-apiスキルをClaude Code上で実行する構成になっている。スキルは2つのコマンドで構成される:
/claude-api build-eval:コードベース内にevalを構築する/claude-api hillclimb:evalを使って一変更ずつアプリを改善する
hillclimbingとは、評価スコアを少しずつ上げるようにプロンプトやコードを反復改善する手法のことで、山を一歩ずつ登るイメージから名づけられている。
良いevalの4条件
記事はまず、評価設計の原則を整理する。特に重要なのが以下の4点だ。
- タスクが本番環境を反映している:生成しやすい・採点しやすいタスクではなく、実際にケアする分布からサンプリングする
- 強いモデル・高い思考量で性能が上がる:そうならない場合は、タスクが曖昧かグレーダーの校正がずれているサイン
- 最高性能のモデルでも100%に届かない余裕がある:上限に張り付いていると改善の効果が測れない。ただし「どんな試行でも必ず失敗するタスク」は不可能または曖昧なタスクのサイン
- 実行ごとのばらつきが小さい:高分散の多くは曖昧なタスクか、同じ出力に異なる判定を返すグレーダーに起因する
「Adversarial sampling」に注意
記事が特に強調するのが、タスクのサンプリング戦略だ。今日のモデルが失敗するケースを優先して集めると、そのモデル固有の「失敗のフィンガープリント」を測るevalになってしまう(Fig 2の図解が直感的にわかりやすい)。
正しいアプローチは「人間が難しいと判断したから難しい」ケースを選ぶこと。選定前に「このタスクがなぜ難しいか」を言語化できることが基準になる。本番トラフィックからの抽出も有効だが、ユーザーは「動くと思うもの」を試す傾向があるため、そのままでは易しいケースに偏ることも指摘されている。
/claude-api build-evalの動作
コマンドを実行すると、ClaudeがインタビューしながらevalをClaudeリポジトリ内に構築する。入力サンプルは以下の優先順位で収集される:
- 本番トランスクリプト(データ保持・機密性を確認後)
- バグレポートとサポートチケット
- 手作りの5〜10件
- コードベースから合成したケース
グレーダーの選択も自動化されており、出力の性質によって使い分けられる:
- プログラマティック検証:出力の取りうる値が限られる場合(完全一致、固定ラベル、JSONスキーマ、テスト合否)
- LLM-as-judge:出力空間がオープンエンドな場合にLLMを採点者として使う手法。重要なのは、ジャッジモデルはテスト対象のモデルとは別にすること。また、ベースラインとの比較がある場合は、どちらがベースラインか明かさずに2つを並べて判定させる
診断チェックとして、同じ出力に対してグレーダーを2回実行し判定が変わらないかを確認する処理も含まれている。ベースラインが95%以上の場合は「hillclimbはコストや遅延の改善に使え」と警告が出る。
/claude-api hillclimbの過学習対策が実用的
hillclimbコマンドの肝は、過学習を自動検出して変更を巻き戻す仕組みにある。
evalがハーネス(モデル周辺のコード、プロンプト、ツール等をまとめた実行環境)に「漏れ込む」例として記事が挙げるのが興味深い:OCRが必要なタスクがevalに多く含まれていると、hillclimberがOCRツールを追加し評価スコアは上がるが、本番では無関係という状況が生まれる。
これを防ぐため、コマンドは以下の手順を踏む:
- evalセットをtrainとtestにランダム分割し、hillclimberはtrainの失敗トランスクリプトのみを読む
- 1ラウンドにつき1つの変更だけをパッチとして提案。表面的な言い換えではなく、失敗の根本原因を修正する
- trainが改善してもtestがフラットなら過学習と判定してrevert。両方改善した場合のみ変更を採用

2〜3ラウンドスコアが停滞した場合は、残りのtrain失敗を原因別に分類し、「測定できないほど小さな変更に費やすのではなく、ケース数や繰り返し数を増やすべき」と示唆する。
hillclimbが完了すると、testセットで最高スコアだったバージョンにコードを戻し、信頼区間付きでベースラインとの比較結果を出力する。改善幅がノイズの範囲内であれば「マージを推奨しない」と明示する。
改善対象として適したもの
hillclimbに適した対象の条件として、記事は3点を挙げる:
- 安く反復できるもの(プロンプト、スキルファイルなど。コード変更は向かない)
- スコアの変化が変更に帰属できるもの(スキルのトリガー率とスキルの説明文など)
- 目標が明確なもの。evalが飽和している場合でも「品質を維持しながらコストを削減」は常に有効な目標になりえる
詳細はAutomating eval design and hillclimbing with Claude / claude.dev Blogを参照していただきたい。