
【AI実測 #2】Claude Codeの「合格」は6割しか当たらない
AIが直したコード60件を、別のAIに「本当に直ったか」採点させました。3モデルとも「合格」と答えた38件のうち、実際に直っていたのは23件。6割です。
残りの4割は、見えているテストを全部通ったまま壊れていました。AIにコードを書かせて、AIにレビューさせている人には、そのまま効く数字だと思います。
採点役が何を見落としたのか、そしてAIの採点のどこなら信じてよかったのかまで書きます。先に言ってしまうと、信じてよかったのは「合格」ではないほうでした。
先に結論
先に、60件を数え終えたあとの結論だけ書きます。
採点役が「合格」と言った回のうち、本当に直っていたのは Opus 5 で6割・Sonnet 5 で6割・Haiku 4.5 で4割
逆に「不合格」と言った回は、180回のうち一度も外れなかった
3モデルの判定が割れた20件は、20件とも実際に壊れていた。割れること自体が、いちばん当てになる信号でした
手元に「正解つきの60件」がある、という話
前回の「安いモデルも1行足せば直すのか」を測った回と、その前の回で、同じ課題をClaude Codeの3モデルに何度も直させていました。手元のMacで実際に走らせたもので、合計60件の修正が残っています。
この60件には、ちょっと珍しい性質があります。
60件とも、渡したテストは全部通っている(つまり、普通に見れば「直った」)
それとは別に、モデルに一度も見せていないテストを後から当ててある
2つめを、ここでは伏せテストと呼びます。「バグ報告に書いてある症状が、報告に出てきた入力以外でも直っているか」だけを確かめる短いテストです。
この伏せテストの結果が、そのまま合否の正解になります。今回あらためて60件すべてに当て直したところ、直っていたのは23件、直っていなかったのは37件でした。過去2回の記録と1件の食い違いもありません。
見えているテストは60件とも通る。落ちるのは、後から当てた伏せテストだけ。
つまり「答えが分かっている採点問題」が60問ある状態です。これに採点役をぶつけます。
採点役に渡したもの、渡さなかったもの
採点役にはClaude Codeの3モデル(Opus 5 / Sonnet 5 / Haiku 4.5)を使い、60件すべてを3モデルに採点させました。合計180回です。
渡したのは4つだけ。
修正後のコード一式
見えているテスト(実行してよい、と伝えてあります)
元のバグ報告
その回の差分
渡さなかったものが大事です。伏せテスト・正解ラベル・他の回の結果・どのモデルが直したかは、一切渡していません。どれか1つでも混ざれば答えを見ながら採点することになるので、混入していないかをスクリプト側でも検査しています。
採点役に聞いたことは、これ1つだけです。
この修正は、見えているテストだけでなく、すべての妥当な入力に対して、報告されたバグを正しく直しているか。見えているテストが全部通ることは前提です。それだけを理由に合格にしないでください。
答えは「合格」か「不合格」の一言と、理由1行。採点役が実装を書き換えていないことは、実行前後のファイルのハッシュを突き合わせて確認しました(180回とも書き換えゼロ)。

結果:「直った」は当てにならず、「直っていない」は外さない

表の言葉だけ補足します。見逃しは「合格と言ったのに、実は壊れていた」。空振りは「不合格と言ったのに、実は直っていた」。品質の観点でまずいのは前者です。
数字を本文にも書いておきます。
判定が当たった: Opus 5 が45/60、Sonnet 5 が44/60、Haiku 4.5 が25/60
見逃し: 15件・16件・35件
空振り: 3モデルとも0件
そして、いちばん意外だったのがここです。
空振りは、180回の判定で1件も出なかった。
3モデルとも、実際に直っていた23件は全部「合格」と言い当てています。間違えるのは必ず一方向 —— 壊れているものを「直った」と言う側にだけ寄っていました。
裏を返せば、採点役が「直っていません」と言ったときは、毎回それが正しかったということになります。正直、ここまできれいに片側へ寄るとは思っていませんでした。
なぜ見逃すのか——教科書のバグは消えて、その先が残る
見逃しの理由を読んでいくと、ほとんどが同じ形をしていました。経費の集計で出た見逃し51件のうち19件が、「可変デフォルト引数」あるいは「可変既定引数」という言葉をそのまま使って「正しく直っている」と述べています。
3箇所とも根本原因を修正し、境界値・丸め・可変デフォルト引数の一般ケースでも正しく動作する
可変デフォルト引数というのは、Pythonを勉強すると必ず出てくる有名な落とし穴です。関数の初期値に空のリストを書くと、そのリストが呼び出しのたびに使い回されて中身が溜まっていく、というもの。
安いモデルたちは、これをきちんと直しています。初期値を空にするのをやめて、中で作り直すようにした。だから採点役も「教科書どおりに直っている」と判断しました。
消えたもの: 関数の初期値が呼び出しをまたいで使い回される問題
残ったもの: 呼び出す側から渡されたリストを、そのまま書き換えてしまう問題
ところが、残った穴があります。

呼び出す側がリストを渡してきた場合、そのリストに直接書き足してしまうのは変わっていないのです。Opus 5 だけが、渡されたリストを複製してから使っていました。差はほぼ一行です。
もう1つの課題も同じ形でした。鍵に「年」を足して年またぎの取り違えだけ直し、「日」は足さない。3月15日と3月20日の請求額が同じになります。
Haiku 4.5: 10回とも「日」を足さなかった
Sonnet 5: 10回中7回。残り3回は「日」まで入れて正しく直している
同じモデルでも回ごとに揺れます。1回動かして「このモデルはこう直す」と決めつけないほうがよさそうです。
2つの課題に共通していたのは、これです。
「有名なバグの形」が消えたところで、採点が止まっている。
教科書に名前が載っている問題は見つけられるのに、その修正が作り残した穴は見に行かない。
数字にも出ています。可変デフォルト引数のほうの課題は判定90件のうち51件が見逃し。日割り計算のほうは15件でした。名前のついた定番バグほど、採点役は安心してしまうようです。
判定が割れた20件は、20件とも壊れていた
3モデルの判定を並べて、揃ったかどうかで分けてみました。
3モデル全員が「合格」…… 38件(うち15件は実際には壊れていた)
3モデル全員が「不合格」…… 2件
判定が割れた …………………… 20件(20件とも実際に壊れていた)

全員一致の「合格」ですら4割が外れているのに、割れた20件は100%壊れている。つまり、採点役の多数決を取って「2対1で合格」としていたら、その20件を全部通していたことになります。
ついでに分かったことがあります。3モデルの判定はきれいに入れ子になっていました。Opus 5 が合格にしたものは Sonnet 5 も必ず合格にし、Sonnet 5 が合格にしたものは Haiku 4.5 も必ず合格にする。厳しさの順に一列に並んでいたわけです。
つまり判定が割れたとき、多数決の結果は「真ん中のモデルの意見」にしかなりません。3体に聞く意味が消えます。合議で決めるのではなく、割れた時点で赤信号として扱うほうが正しい使い方でした。
自分の修正を自分で採点させるとどうなるか
採点役と修正役の組み合わせ別にも出しました。ここも見事でした。

Haiku 4.5 が Haiku 4.5 の修正を採点した20件は、20件すべて「合格」。実際には20件とも壊れていました(的中0%)
同じ20件を Opus 5 に採点させると、14件は「不合格」と見抜きます
Sonnet 5 が Sonnet 5 の修正を採点した20件も、的中は11件
一方、Opus 5 の修正20件は、3つの採点役すべてが20/20で正しく合格と判定しています。直っているものを見抜くのは簡単なのです。難しいのは、もっともらしく壊れているものを見抜くことでした。
自己採点が甘くなるというより、自分が見落とした観点は、採点する側に回っても同じように見落とす、という当たり前のことが起きているだけだと思います。見落としの癖はモデルごとに固有なので、採点役は必ず別のモデル、できれば一段賢いモデルにする——ここは実務でそのまま使える結論になりました。
明日から使えると思ったこと
60件を数え終えて、自分の手順を3つ変えました。

採点役は、修正させたモデルと別にする。 同じモデルの自己採点は、いちばん当たらなかった条件です
「不合格」だけを信号として使う。 「合格」は情報がほぼゼロ(6割・4割)ですが、「不合格」は180回外れませんでした
判定が割れたら通さない。 多数決で押し切らない。割れた20件は全部壊れていました
そして、いちばん効くのは身も蓋もない話でした。AIの採点をテストの代わりにしない。 60件とも見えているテストは通っていて、それでも37件が壊れていたのです。症状の周辺を1本テストに足すほうが、採点役を1体増やすより確実でした。
費用の目安も出しておきます。採点1回あたりの中央値は Opus 5 が0.29ドル、Sonnet 5 が0.15ドル、Haiku 4.5 が0.09ドルでした。実行時に記録される換算額で、定額プランの請求額ではありません。
60件の採点を Opus 5 で一周して18ドル。この金額で得られるのが「見逃し15件」だとすると、テストを1本書いたほうが安い場面は多そうです。
よくある質問
Q. 課題が2つだけでは少なくないですか
少ないです。Pythonの小さな題材2つなので、他の言語や大きなコードベースに一般化はできません。ただ「見えているテストは通るが直っていない」という状況自体はどこにでもあるので、傾向としては参考になると思っています。
Q. 採点の聞き方を変えれば結果は変わりませんか
変わると思います。今回は「すべての妥当な入力に対して直っているか」という1通りの聞き方だけを試しました。逆に言えば、この程度の指示では足りないということでもあります。
Q. 採点役が勝手にコードを直してしまいませんか
そこは確認しました。実行の前後でファイルのハッシュを取って突き合わせ、180回とも書き換えゼロでした。
Q. 処理時間の比較は載せないのですか
載せません。今回は18本を同時に走らせる設定で回したので、秒数に順番待ちが混ざっています。速度の比較には使えない数字なので、費用と判定内容だけを出しました。
自分で確かめるなら
手順はこれだけです。
直してほしいバグを1つ選び、症状を再現する短いテストを2本作る
1本だけをAIに見せて直させる。もう1本は隠しておく
直った状態を別のモデルに見せて「すべての妥当な入力で直っているか」と聞く
隠しておいたテストを当てて、3の答え合わせをする
1往復で終わります。自分のコードでやると、どのモデルが自分の仕事に対してどれくらい甘いかが、その日のうちに分かります。
なぜ書いたか
私自身が、AIに書かせたコードをAIに見せて「大丈夫そうです」で先へ進めた回数を、正直に数えたくなったからです。数えてみたら、その「大丈夫そうです」は6割しか当たっていませんでした。
前回は「安いモデルに一行足すと直るのか」を測りました。今回はその修正を採点する側を測ったことになります。ここまで測って分かっていないのは、隠しておくテストの書き方しだいでこの数字がどこまで動くのか、です。私の伏せテストが厳しすぎた可能性も、まだ捨てきれていません。
あわせて読む記事はこちらです。