Claude Media
Anthropicが示したコーディング評価の落とし穴 — リソース設定が6ポイントのスコア差を生む

Anthropicが示したコーディング評価の落とし穴 — リソース設定が6ポイントのスコア差を生む

AnthropicがTerminal-BenchとSWE-benchで実験。Kubernetesのリソース上限の置き方だけで成功率が最大6ポイント動くことを示し、評価設定の標準化を提起しました。

エージェント型コーディング評価のリーダーボード差が、モデルの実力ではなく実行環境のリソース設定から生まれている可能性を、Anthropicが定量化しました。Terminal-Bench 2.0では、最も潤沢な構成と最も厳しい構成の差が6ポイント(p < 0.01)です。上位モデル同士の差が数ポイントに収まる世界では、無視できない大きさです。

背景 — リーダーボードの「実力差」を疑う動機

AnthropicはTerminal-Bench 2.0をGoogle Kubernetes Engine(GKE)のクラスタ上で走らせています。セットアップを校正している途中で、自社の評価結果が公式リーダーボードと合っていないことに気づきました。インフラのエラー率も想定外に高く、タスクの最大6%がpodエラーで失敗していました。しかもその多くは、モデルが課題を解けるかどうかとは無関係でした。

原因は、リソース仕様の強制のしかたにありました。Terminal-Benchはタスクごとに推奨のCPUとRAMを指定しています。Anthropicの実装は、その値をコンテナの下限と、超えれば即座に強制終了する上限の両方に使っていました。

Two agents with different resource budgets and time limits aren't taking the same test.

(訳: リソースの予算と制限時間が違う2つのエージェントは、同じテストを受けていない)

評価の対象が静的な出力ならランタイムは結果に関与しません。ところが、エージェントは環境の中でプログラムを書き、テストを走らせ、依存をインストールし、何ターンも試行します。ランタイムは受け身の容れ物ではなく、問題解決の一部です。

リソースを指定することと、それを一貫して強制することは別の話です。Terminal-Benchの公式リーダーボードは、一時的な超過割り当てを許してコンテナを落とさない別のサンドボックス事業者で動いています。実装がより寛容なので、インフラの安定性が優先される作りです。同じ仕様書でも、強制の方法が違えば測っているものが変わります。

コンテナランタイムの「2つのパラメータ」を分離する

コンテナランタイム(Docker / containerd / Kubernetesなど)は、リソースを2つの独立したパラメータで扱います。

パラメータ役割Kubernetesでの名称
保証割り当て(floor)役割あらかじめ確保される量Kubernetesでの名称requests
強制終了の閾値(ceiling)役割超えるとコンテナが落とされる量Kubernetesでの名称limits

Terminal-Bench 2.0のタスク仕様をそのまま両方に入れると、requests = limits になります。直感的には「必要な分だけ確保して、それ以上は使わせない」という妥当な設定に見えます。ただし一時的な増加を受け止める余白がゼロになるため、瞬間的なメモリのゆらぎでOOM-Kill(メモリ不足による強制終了)が走り、本来は成功したはずのコンテナが消えます。

# 余白ゼロ(requests = limits)
resources:
  requests:
    memory: "4Gi"
  limits:
    memory: "4Gi"
 
# 床と天井を分ける(例: 天井をタスク仕様の3倍に)
resources:
  requests:
    memory: "4Gi"
  limits:
    memory: "12Gi"

この数値は設定の書き方を示す例で、Anthropicが使った値ではありません。

厳密な強制のまま走らせた評価では、この種の失敗もモデルの失敗として集計されます。エージェントが諦めたのではなく、動いていたpodごと消えているのに、です。

6つのリソース構成を比較した実験 — 1x / 3x / 無制限の差

Anthropicは6つのリソース構成でTerminal-Bench 2.0を走らせました。仕様どおりに厳密に強制する1x(下限と上限を兼ねる)から、上限を完全に外した構成までです。Claudeモデルもハーネスもタスクセットも同じで、変えたのはリソース設定だけです。

数字

インフラ起因の失敗率

  • 1x(厳密に強制)

    5.8%

    ベースライン

  • 3xヘッドルーム

    2.1%

    1xからの低下は p < 0.001

  • 無制限

    0.5%

    成功率の合計上昇は +6ポイント(p < 0.01)

Terminal-Bench 2.0。数値は同じClaudeモデル・同じハーネス・同じタスクセットでの比較

インフラ失敗率は構成を緩めるたびに単調に下がりました。注目したいのは、1xから3xまでと、3xから無制限までで、起きていることの質が違う点です。

くらべる

緩めるほど、何が変わるか

インフラの安定化

1x → 3x

インフラ失敗率は5.8%から2.1%へ下がりますが、成功スコアはノイズの範囲(p = 0.40)に収まります。1xで落ちていたタスクの大半は、落ちなくても失敗していたようです。エージェントは探索して資源の壁にぶつかり、強制終了されますが、もともと正解に向かう途中ではありませんでした。

タスクの難易度が下がる

3x → 無制限

インフラ失敗率の追加の低下は1.6ポイントで、成功率は約4ポイント跳ねます。余裕があると、大きな依存ライブラリの導入、重いサブプロセスの起動、メモリを食うテストスイートの実行といった、潤沢な割り当てでしか成り立たないやり方が選べるようになるためです。

3倍までは、評価が易しくならずに安定します。Terminal-Benchの運営側が使うサンドボックス事業者は、この安定化を裏で暗黙のうちに行っている、とAnthropicは見ています。3倍を超えると、上限の緩さが評価の中身を変え始めます。

個別のタスクでは、rstan-to-pystan や compile-compcert のように、メモリの余裕で成功率が大きく改善するものがありました。

上限の厳しさは、どんな戦略に報いるか

bn-fit-modify(ベイジアンネットワークの当てはめを求めるタスク)が、好例です。モデルによっては、最初の一手として標準的なPythonデータサイエンス一式(pandas、networkx、scikit-learnと、その周辺のツールチェーン)をインストールします。上限が寛容なら通ります。厳しいと、解答コードを1行も書く前に、インストール中にpodがメモリ不足になります。

標準ライブラリだけで数式を自前実装する軽い戦略もあり、最初からそちらを選ぶモデルもあります。選ばないモデルもあります。リソース構成によって、どちらの戦略が成功するかが決まります。

厳しい上限は効率のよい戦略に報い、寛大な上限は利用できる資源を使い切る力押しの戦略に報います。どちらも測る価値のある能力ですが、リソース構成を明示せずに1つのスコアにまとめると、差の意味が読めなくなります。実世界への一般化も判断しにくくなります。

SWE-benchでも向きは同じ

Terminal-Bench以外でも成り立つかを調べるため、SWE-benchでも交差実験をしています。227問を10サンプルずつ、総RAMをベースラインの最大5倍まで振りました。スコアはRAMに対して単調に上がりましたが、5xと1xの差は1.54ポイントです。SWE-benchのタスクはリソース消費が小さく、効果が小さいのは想定どおりです。それでも、割り当てが中立でないことは示されました。

複数のAnthropicモデルで再現した結果、効果の向きは一貫し、大きさはモデルによって違いました。Claude以外のモデルにも同じ傾向がありそうだとされていますが、厳密な検証はしていません。

ノイズ源はメモリだけではない

リソース割り当ては、隠れた変数の1つにすぎません。条件によっては制限時間も効いてきます。原則として、評価設定のあらゆる要素が最終スコアに影響し得ます。クラスタの健全性、ハードウェアの仕様、並行度、外向き通信(egress)の帯域幅といった要素です。エージェント型評価は設計上、エンドツーエンドのシステムテストなので、システムのどの部品も交絡要因になります。

時間帯の影響は、定量化されていない観察です。合格率が時間帯によってぶれる事例が見られ、トラフィックの波や障害でAPIのレイテンシが変わるためと推測されています。数値の裏づけは出ていません。それでも、「モデルの能力」と「インフラの挙動」の境界が、1つのベンチマークスコアから想像するよりも曖昧だという論点は動きません。

モデル提供側は、専用ハードウェアを確保して評価基盤をこのノイズから守れます。外部の評価者には、同じことは簡単にできません。公開前提のコーディング評価は、複数の時間帯・複数の日で走らせて平均を取るとノイズが均されます。

Anthropicが提示する3つの設定指針

ハードウェア条件を、評価を回すスキャフォールドと推論スタックの両方で完全に揃えられれば、再現性は完全になります。ただ、現実にはいつも実現できるわけではありません。そこで次の3点が示されています。

1. リソースは requests と limits を分けて宣言する

タスクごとに、保証割り当てと強制終了の閾値を別の値で書きます。単一の固定値は両者を同じにしてしまい、余白がゼロになります。1xで観察した一時的なメモリの跳ねだけで、評価が不安定になる水準です。2つを分ければ、不要なOOM-Killを避ける余裕を与えつつ、硬い天井でスコアの水増しも防げます。

2. 床と天井の幅を経験的にキャリブレーションする

床と天井での成績がノイズの範囲で並ぶように、幅を調整します。Terminal-Bench 2.0では、タスク仕様の3倍を天井にすると、インフラ失敗率が約3分の2減りました(5.8%から2.1%、p < 0.001)。一方でスコアの上昇は小さく、ノイズの範囲(p = 0.40)でした。インフラ由来の交絡がおおむね消え、意味のある資源の圧力は残る、という釣り合いの点です。

3. 採用した倍率を報告する

最適な倍率はベンチマークやタスク分布で変わります。Anthropicは次のように述べています。「the exact multiplier will vary by benchmark and task distribution, and should thus be reported」(正確な倍率はベンチマークとタスク分布によって変わるので、報告すべきだ)。経験的に較正するという原則は、どの評価にも共通です。

3ポイント未満の差は、どこまで割り引くか

ここまでがAnthropicの主張です。リーダーボードの数字の読み方に直すと、判断の材料は具体的です。

Anthropicは、リソース方法論が標準化されるまでは、評価設定が文書化されて揃うまで、3ポイント未満のリーダーボード差は疑ってかかる価値がある、としています。根拠は3段になっています。

手順

数ポイントの差に乗る不確かさ

  1. 1

    統計の幅だけで1〜2ポイント

    素朴な二項分布の信頼区間だけで、すでに1〜2ポイントの幅があります。

  2. 2

    中程度のリソース差で2ポイント弱

    Terminal-Benchでリソース構成を中程度の範囲で動かしたときの広がりは、2ポイントをわずかに下回ります。

  3. 3

    極端なら6ポイント

    割り当ての両端まで広げると、広がりは6ポイントに届きます。

インフラの交絡は、統計の幅の内側に収まるのではなく、その上に積み上がる、という位置づけです。「SWE-benchで2ポイント上だから採用」のような判断は、設定が揃っていなければ根拠が薄い、ということになります。Anthropic自身の言い方では、数ポイントのリードは本物の能力差かもしれませんが、単に大きなVMの差かもしれません。

自社の評価やCI上のエージェントで見直す点

公開ベンチマークの読み方以外にも、手元で使える示唆があります。

自社でClaudeと他のモデルを比較する評価環境を組むなら、リソース上限・並行度・実行する時間帯を固定し、両方を同じ条件で走らせることが重要になります。Anthropicの枠組みでは、リソース構成は、プロンプトの形式やサンプリング温度と同じ厳密さで管理する実験変数です。この姿勢は、エージェント向けツール設計の原則が掲げる「評価駆動でツール設計を進める」流れと整合します。評価の再現性が担保されないと、ツール改善の効果測定自体がノイズに埋もれます。評価の検証器が結果を左右する論点は、10万行のCコンパイラをClaudeに書かせた長尺コーディングの実験にも、別の角度で現れます。検証器が完璧でないと、モデルが別の問題を解いてしまうという指摘です。

Claude CodeのようなエージェントをKubernetesやDocker上で走らせているチームには、同じ罠が当てはまりそうです。requests = limits の構成だと、パッケージのインストールなどメモリが瞬間的に増える処理で、podが落ちます。

それが「エージェントが解けなかった」という失敗に見えていないかは、疑ってみる材料になります。サンドボックスの境界はClaude Codeのサンドボックス設計で扱っています。こちらはリソース境界で、別の軸の話です。

手元のクラスタで切り分けるなら、落ちたコンテナの終了理由を見るのが入口です。

# 落ちたコンテナの終了理由。メモリ超過なら OOMKilled と出る
# 再起動しないpod(restartPolicy: Never)は state、再起動するpodは lastState に出る
kubectl get pod <pod名> \
  -o jsonpath='{.status.containerStatuses[0].state.terminated.reason}'
kubectl get pod <pod名> \
  -o jsonpath='{.status.containerStatuses[0].lastState.terminated.reason}'

OOMKilled が並ぶなら、モデルの能力ではなく、limits の置き方を疑う材料になります。

AnthropicのContext Engineering論は、動くコンテキストを作る議論でした。モデルの出力は、プロンプトやツールだけでなく、実行環境の資源にも左右されます。その視点を、コンテナの外側の資源まで広げることもできます。

まとめ

数ポイントのスコア差は、設定が揃っていなければ実力差と読めません。評価を自分で組むなら、requests と limits を分け、採用した倍率を結果とあわせて残す、という選択肢があります。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. anthropic.com/engineering/infrastructure-noise
この記事を共有:XはてブLinkedIn