p4ni.

研究紹介

Claude Code の effort level を 45 回測ったら、答えはほぼ変わらなかった

· 読了まで約9分

目次

claude code effort levels で検索すると、出てくる説明はどれも同じ形をしている。low は機械的な作業向け、max は難しい問題向け、上げれば答えがよくなる。公式ドキュメントは設定の仕様を説明していて、その周りの記事は「どの段階がどれくらい賢いか」を並べている。

同じタスクを 5 段階で回して、返ってきたものを見せている記事が無い。

そこで測った。3 タスク × 5 段階 × 3 試行の 45 セッション、モデルは Opus 5、採点はコードを実際に実行して作った正解と突き合わせる。答えはほとんど動かなかった。動いたのはそれ以外だった

測り方

effort はコマンドラインのフラグで渡せるので、設定を触らずに比較できる。

claude -p "$PROMPT" --effort low --output-format stream-json --verbose

1 回ごとに新しいセッションを立てるので、前の回の内容は持ち越さない。数字は JSON ストリームの result イベントから取る。所要時間の duration_ms、ターン数の num_turns、出力トークンの usage.output_tokens、そして usage.output_tokens_details.thinking_tokens —— effort の効き目が実際に出るのは最後のこれ。

タスクは深さの違う 3 つを用意した。

  • T1 — 17 行の CSV を Markdown の表にする。答えは 1 つに決まり、考えることが無い
  • T2 — 41 ファイル・200 個のエクスポート関数から、"" を渡すと例外を投げるものを全部挙げる
  • T3 — 同じ問いを、流し読みでは解けないように作ったコードベースに対して投げる

T2 は grep では解けない。危険な処理は helpers.ts 側にもあるので呼び出し側だけ見ても分からず、しかもガードはランダムに入っていて、効くものと効かないものが混ざっている。

export function mod004Handler2(input: string): string {
  if (!input) return "none";         // "" を弾く。安全
  return parseTag(input);
}

export function mod017Service2(input: string): string {
  if (input === null) return "none"; // "" は null ではない。素通しする
  return pickId(input);              // "".match(/id=(\d+)/) は null -> null[1] で例外
}

T3 はもう一段深い。helper が 3 段のチェーンになっていて、降りていく途中で引数が書き換わる

// helpers-b.ts
export function decorateTag(raw: string): string {
  return takeSecond(raw + ",fallback");  // "" が ",fallback" になる -> 例外にならない
}
export function normalizeTag(raw: string): string {
  return takeSecond(raw.trim());         // "" のまま -> takeSecond が例外を投げる
}

見た目が同じ 2 つの呼び出しが、3 段先で逆の答えになる。200 個のうち 86 個が深さ 3、78 個が深さ 2 で、167 個はどこかで引数が変換される。

正解は自分の生成スクリプトを信じずに作った。検証スクリプトが型注釈を落として生成物を Node に読み込ませ、200 個の関数を "" で呼んで、実際に例外を投げたものを記録する。生成器の主張と実行時の挙動は、2 つのコードベース合わせて 400 関数すべてで一致した。もう 1 本のスクリプトは各回のツール呼び出しを走査して、正解ファイルや ~/.claude/projects/ に残る過去セッションのログを覗いていないかを見る。45 回すべてで該当ゼロ。

45 回の結果

T1 — CSV から Markdown の表(答えが 1 つに決まる)

effortnツール呼び出し思考 tok出力 tok正答
low37.31.00498100%
medium37.01.00498100%
high36.51.00498100%
xhigh311.82.00594100%
max39.11.70561100%

T2 — 200 関数・間接参照が 1 段

effortnツール呼び出し思考 tok出力 tok再現率
low344.25.72,0883,14899.5%
medium380.520.73,9316,549100%
high3107.145.35,79510,052100%
xhigh3107.144.76,23810,316100%
max3136.946.010,00714,372100%

T3 — 同じ問い・helper が 3 段チェーン

effortnツール呼び出し思考 tok出力 tok再現率
low380.37.35,6027,062100%
medium3120.322.78,31211,245100%
high3147.423.711,48714,430100%
xhigh3187.835.314,73018,497100%
max3199.746.016,24620,691100%

適合率はどの段階でも 100% だった。例外を投げない関数を挙げてしまう機会は 45 回で 1,995 回あったが、誤検出は 1 件も無い。実験全体で間違いは 1 個 —— T2 の low が 1 回だけ落とした 1 関数だけ。

効いたところ、効かなかったところ

考えることが無いタスクでは effort は何もしない。T1 は 5 段階すべてで思考トークンが 0 だった。low・medium・high は出力トークンまで完全に一致していて、3 試行とも 498。xhigh と max だけ Read を 1 回増やして自分の答えを検算するが、結果は同じものが出てくる。

effort が動かしていたのは探索のやり方だった。low は T2 を一息に読む。

Bash: cat mod0*.ts mod1*.ts

high は同じファイルを 1 つずつ開き、そのあと awk で区切りを入れて表示し直してもう一度眺める。ツール呼び出しは low の 5.7 回に対して 45 回前後。丁寧になっているのは見ていて分かる。ただしこのタスクでは、丁寧さが答えを変えていない。low の時点で答えは出ているからだ。

唯一の見落としは、いかにもな型だった。low が落とした関数はこれ。

export function mod017Service2(input: string): string {
  if (input === null) return "none";  // "" は null ではないので素通しする
  return pickId(input);               // 例外を投げる
}

ガードがあるのを見て、そのまま安全だと判断している。追加の推論が拾うはずの誤りそのもので、実際 1 段上げれば消えた —— medium 以上はこの関数を 12 回すべてで正しく挙げている。effort が無意味なわけではない。ただ、この形の問題では、上げて埋まる差が 1,995 個中 1 個だったというだけだ。

外した予想

T2 は天井を探すつもりで作ったのに、low が 100% を出した。タスクが簡単すぎたのだと考えて T3 を作った —— 3 段チェーン、途中での引数の書き換え、半分しか効かないガード。low はそれも 3 回とも 100% だった。

effort が効くタスクを 2 回作ろうとして 2 回とも外したことになる。200 関数の到達可能性を追う作業は、Opus 5 にとっては「もっと考える必要がある問題」の側に入っていないらしい。必要なのはファイルを読むことで、読み終えた時点で low はもう答えを持っている。max が余分に使う 11,000 の思考トークンには、見つけるものが残っていない。

きれいな階段になると思っていたのも外れた。xhigh は high と max の中間に来ない。T2 では high と 0.1 秒差で並び(107.1 対 107.1)、T3 では max のほうに寄る。この 2 段を分けているものが何なのかは、今回の計測には出てこなかった。

測っていないこと

  • どのタスクも正解が 1 つに決まる。設計の判断、リファクタの方針、筋の通る選択肢から選ぶ種類の仕事は測っていない。effort が効くとしたらそちら側だろう
  • Opus 5 だけで測った。Sonnet や Haiku なら天井の位置は違うはず
  • 各 3 試行。T2 の low の 99.5% は 3 回中 1 回の見落としなので、頻度としての精度は低い
  • 1 回きりの claude -p セッション。対話を重ねる使い方では別の結果になりうる
  • コストは途中で載せるのをやめた。同じ条件の 2 回でもプロンプトキャッシュのヒット率で 3 割動いてしまい、段階の比較に使えない。素直なのはトークン数のほう

結局どう設定するか

既定のまま触らないでいい。答えを検証できる仕事では、low と max の差は 1,995 個中 1 個で、その 1 個に所要時間 2.5〜3 倍と思考トークン最大 4.8 倍を払うことになる。

上げる理由があるとすれば「答えがよくなるから」ではない。low はときどきガードを額面どおりに受け取る、という一点で、そこは 1 段上げれば今回は毎回直った。手で確かめられないコードベースについて質問するなら、medium は安い保険になる。medium から先は、この種の問いに関しては待ち時間を買って、同じファイルを 2 回読むところを眺めることになる。

この結論が外れるとすれば、今回測らなかったほう —— 正解が 1 つに決まらない仕事の側だろう。max が medium に安定して勝つタスクを持っている人がいるなら、測るべきはそちらで、今回のこれではない。