AIDive

動画パック

Claude Code の検証ループ: ベンチ表、Stop hook チェックリスト、ソース

10 分で読めます

TL;DR

  • Anthropic 自身の推奨は考え方として正しい。フィードバックループを持つモデルは、より良い成果物を出す。問題は、そのループを誰が回すかだ。116 回の実行で、組み込みの /verify は 24 回中 24 回 PASS を返した。明示された要件を壊す変更に対しても同じだった。
  • 自分の変更を自分で確認するモデルは、同じ盲点を共有する。Haiku 4.5 は、同一モデルのすべてのセットアップで、同じ unique-field のケースを 11 回中 11 回見落とした。Haiku 自身の /verify も、誤ったケースの横にチェックマークを付けた。
  • Opus 5.5 では、/verify のコストは 2.5 倍($0.96 対 $0.39)で、結果は何も変わらなかった。素の Opus は 12 回中 12 回正解し、そのうち 11 回で自分からテストスイートを実行した。
  • プロジェクトの skill はモデルにとって任意だ。24 回中 10 回しか発動せず、Haiku では 6 回中 0 回だった。Stop hook は毎回発動し、Opus ではコストが約 20% 増えた。
  • 機能したチェックは、作者の外側から来た。同じ /verify を Opus で実行すると、Haiku の変更に対して 3 回中 3 回 FAIL を返し、バグを名指しした。これを Stop hook として組み込むと、Haiku は 3 回中 3 回バグを直した。コストは 1 タスクあたり $1.36 で、Opus が単独で書く場合の $0.76 と比較できる。
  • 真似するならこの形だ。決定的な部分には Stop hook、判断が要る部分には作者ではない verifier、仕様が明確な作業の Opus では /verify を使わない。

What the measurements say

Anthropic の主張: "If Claude has that feedback loop, it will 2-3x the quality of the final result." s4 ブログはこれを 5 ステップの導入手順にしている。最も繰り返す手動チェックを選ぶ、組み込みの /verify を試す、手順を平易な英語で skill に書く、それを決定的にする、CI に移す、の順だ。s1 v2.1.215 以降、"Claude no longer runs the /verify and /code-review skills on its own; invoke them with /verify or /code-review when you want them." s3

現場の報告は、検証したと主張されながら実行されていないケースに集中している。Issue #96416 は、懸念 19 件のうち 5 件しか検証していないのに "accept as-is" を出したレビュー判定だ。s6 Issue #97039 は、チェックリストを読み込んでいたのに、部分的なチェックだけで "held up" と主張した例だ。s7 "build passes" と "production-ready" は別の水準で、見逃しのたびに 2-3 回の再プロンプトが発生する。s8

私たちのベンチは、エージェントが一度も見ない隠し受け入れテストで、すべての "done" を採点した。タスク実行 112 回 + モデル間 /verify 実行 4 回 = 116 回、API 換算コストは $66.29 だった。誤った "done" は 112 回中 12 回。そのうち 11 回はセットアップ A から E のすべてでの T6 の Haiku、1 回は skill セットアップでの T6 の Sonnet で、自分で書いた新しいテストが落ちていたのに skill が発動しなかった。s1

組み込みの /verify は、3 モデル合計 24 回中 24 回で Verdict: PASS と言った(23 回はパース可能、1 回はラベルなしの pass)。Haiku の壊れた T6 も含む。Opus では、素の実行の $0.39 に対し $0.96(2.5 倍)、75 s に対し 125 s かかり、結果は何も変えなかった。s3

5 ステップの手順どおりに書いたプロジェクト skill が呼ばれたのは 24 回中 10 回だった。Opus 8/12、Sonnet 2/6、Haiku 0/6。Stop hook は毎回発動し、Opus では $0.39 に対して $0.47(+20 %)だった。s19

盲点は 1 つの要件、T6 の req 4 だ。複数の一致ドキュメントに同じ unique な値を与える単一の update は、DuplicateKeyError を送出しなければならない。Haiku は、すべてのセットアップ(plain、/verify、skill、hook、tests first)で 11 回中 11 回見落とした。Haiku 自身の /verify は "update one doc onto another's email" を確認しただけで、1 回の update が複数のドキュメントに当たるケースは試さなかった。テストファーストのルールも効かなかった。3/3 が req 4 を見落とし、1 回は req 3 まで壊した。s1

同じ Haiku の変更を、別のモデルで /verify した結果: Sonnet は PASS(1/1)、Opus は FAIL 3/3 で、毎回同じケース、つまり 1 回の update が同じ値を複数のドキュメントに書くケースを名指しした。1 回のチェックは $0.39 から $0.47 だった。Haiku への Stop hook として(セットアップ F)、Opus の verifier はバグを 3 回中 3 回直させた。3 回とも修正中に 60 ターンの上限に達し、verifier を含む T6 1 回の平均は $1.36 だった。Opus が T6 を単独で書いた場合は $0.76 で、誤った "done" は 0 だった。s19

Measurements

ハーネス: Claude Code 2.1.283 headless(claude -p)、分離した config dir、タスクごとに同じプロンプト、60 ターン上限。リポジトリ: msiemens/tinydb @ 18d73a1(Python、テスト 226 件)。機能要望 T1 から T6 の 6 件で、それぞれ明示された要件が 5 つ(T5 は 6 つ)。隠し受け入れテストは要件ごとに 1 つで、エージェントには一切見せず、すべての実行を採点する。リポジトリ自身のスイートも実行する。誤った "done" とは、隠しテストまたはリポジトリのスイートが失敗しているのに完了を主張して終わった実行のこと。

セットアップ: A plain(要望のみ)、B /verify(A のあと、2 ターン目で組み込みの /verify)、C verify skill(5 ステップの手順どおりに書いた、モデルが呼び出せるプロジェクト skill)、D Stop hook(prove-it.py: スイートが赤の間は停止をブロックし、最初の停止では要件ごとに証拠 1 行を求めてブロックする)、E tests first(CLAUDE.md のルール: コードの前に要件ごとに落ちるテストを書く)、F Opus verifier hook(変更に対して claude -p /verify --model opus を実行し、PASS 以外の verdict ならブロック、最大 2 ラウンド)。

model setup runs false done avg cost avg turns avg wall
Opus 5.5 A plain 12 0 $0.39 16.6 75 s
Opus 5.5 B /verify 12 0 $0.96 22.3 125 s
Opus 5.5 C skill 12 0 $0.43 19.5 80 s
Opus 5.5 D hook 12 0 $0.47 19.8 94 s
Opus 5.5 E tests first 2 (T6) 0 $0.64 18.5 129 s
Sonnet 5 A 7 0 $0.44 24.0 112 s
Sonnet 5 B 6 0 $1.18 36.3 210 s
Sonnet 5 C 7 1 $0.48 25.7 136 s
Sonnet 5 D 6 0 $0.53 27.0 157 s
Haiku 4.5 A 8 3 $0.34 35.4 172 s
Haiku 4.5 B 6 1 $0.68 43.3 217 s
Haiku 4.5 C 6 1 $0.26 28.2 124 s
Haiku 4.5 D 8 3 $0.37 38.9 179 s
Haiku 4.5 E 3 (T6) 3 $0.41 38.3 186 s
Haiku 4.5 F Opus verifier 3 (T6) 0 $1.36 verifier 込み 61 (cap) 457 s
Sonnet 5 F 1 (T6) 0 $2.30 verifier 込み 50 512 s

制約: リポジトリは 1 つ(小さく、テストが充実した Python ライブラリ)、仕様が明確な要望は 6 件、各セルの繰り返しは 1 から 3 回、headless 実行。隠しテストは、要望に書かれたことだけを検証する。

Do this Monday

  • モデルの "done" を読む前に、明示された要件ごとに受け入れテストを自分で 1 つ書く。ベンチの隠しテストは、同一モデルのどのチェックも見逃したものを捕まえた。
  • テストスイートを実行し、赤の間は block decision を返す Stop hook を追加する。毎回発動する。skill は発動しない。
  • タスクの最初の停止に、要件ごとに証拠 1 行を要求する(prove-it.py のパターン)。文章ではなく、コマンドとその出力で。
  • 判断が要るチェックは、その変更を書いていないモデルに回す。diff に対して claude -p /verify --model opus を実行し、PASS 以外ならブロック、上限は 2 ラウンド。
  • 仕様が明確な要望の Opus 5.5 では、習慣で /verify を打つのをやめる。コストは 2.5 倍で、12 回の実行で何も変わらなかった。テストのない領域や、既存バグの調査のために取っておく。
  • コスト削減のために Haiku 4.5 へ委任するなら、verifier の予算を見込む。Opus hook 付きで 1 タスク $1.36、Opus が単独で書けば $0.76。
  • 失敗した修正のリトライをすべて ledger に記録し、同じものが繰り返されたらループを止める。ブロックする hook が、同じ誤ったパッチでトークンを燃やさないようにするため。
  • 要件を、複数行のケースの観点で読み直す。"one update that matches several documents" は、Haiku の 11 回中 11 回が一度も試さなかったケースの形だ。

Go further

  • 5 ステップの手順と、手動チェックから CI ゲートまでの成熟度のはしご。hook がローカルで動くようになったら、決定的な部分が属するのは上の段(CI と PR のゲート)だ。s1
  • Stop hook の仕様: reason 付きの block decision はターンをモデルに差し戻す。自作のゲートを書く前に、exit code と JSON contract を読むこと。s19
  • Groundtruth は、チェックが通るまでターンの終了を拒否する Stop hook だ。この考え方の決定的な版で、参照実装として読める。s5
  • regressionledger はコスト側の話だ。同じ失敗した修正を再試行するループを止める hook で、実行が 60 ターンの上限に達したとき、私たちの Stop hook に欠けていた部品だ。s10

Sources

  • Building verification loops in Claude Code with skills, Anthropic blog. 読む理由: ベンチの skill セットアップの土台になった 5 ステップの手順とはしご。
  • Building verification loops in Claude Code, official Claude channel. 読む理由: /verify が初回に何をするかを 3 分で。使い続けるか決める前に。
  • Claude Code CHANGELOG, GitHub. 読む理由: v2.1.215 で /verify がユーザー呼び出しのみになった。実行される頻度が変わる。
  • Boris Cherny: give Claude a way to verify its work, X. 読む理由: "2-3x the quality" という主張の正確な文言。
  • Groundtruth, GitHub. 読む理由: ゼロから書く代わりにコピーできる、動作する Stop hook ゲート。
  • Issue #96416, GitHub. 読む理由: 懸念 19 件のうち 5 件しか検証せずに承認したレビュー判定の、日付付きトランスクリプト。
  • Issue #97039, GitHub. 読む理由: 2 日後に、チェックリストを読み込んだ状態で起きた同じ失敗。チェックリストでは解決しない。
  • AI coding agents can verify some of their work now, dev.to. 読む理由: "build passes" と "production-ready" の差を最も明快に述べた記事。
  • Saguaro, GitHub. 読む理由: ループ内レビューと PR レベルのレビューをめぐる議論。コメント欄に反論がある。
  • regressionledger, GitHub. 読む理由: ブロックする hook が生むリトライコストの問題と、それを抑える一つの方法。
  • SPICE simulation to oscilloscope to verification with Claude Code, personal blog. 読む理由: オラクルが物理的な計測器である検証ループ。
  • Hooks reference, code.claude.com. 読む理由: Stop hook が守るべき block decision の contract。

FAQ

組み込みの /verify はバグを捕まえるか?

このベンチでは捕まえなかった。Opus 5.5、Sonnet 5、Haiku 4.5 の 24 回中 24 回で PASS を返し、明示された要件を壊した Haiku の変更も含まれる。唯一の有用な発見は、変更とは無関係な、既存の upstream のバグだった。

なぜ強い verifier が弱い書き手の助けになるのか?

Haiku 自身のチェックは、すでに思いついていたケースを試しただけだった。Opus は同じ変更と同じ /verify で、1 回の update が複数のドキュメントに当たるケースを試し、3 回中 3 回 FAIL と言った。Sonnet は PASS と言った。verifier は、作者が見なかったケースを見る必要がある。

Haiku を Opus で検証するのと、Opus で書くのではどちらが安いか?

Opus で書くほうが安い。Haiku に付けた Opus verifier hook は T6 1 回あたり平均 $1.36 で、毎回 60 ターンの上限に達した。Opus が T6 を単独で書いた場合は平均 $0.76 で、誤った "done" は 0 だった。