AIDive

影片資料包

Claude Code 驗證迴圈:測試表格、Stop hook 檢查清單與資料來源

閱讀約 10 分鐘

TL;DR

  • Anthropic 自己的建議方向沒錯:模型有了回饋迴圈,產出的成果會更好。問題在於誰來跑這個迴圈。在 116 次執行中,內建的 /verify 24 次全部回傳 PASS,包括一次違反明確需求的修改。
  • 模型檢查自己的修改,會共用同一個盲點。Haiku 4.5 在所有同模型設定下,11 次中有 11 次漏掉同一個唯一欄位的情境,它自己的 /verify 還在錯誤的情境旁打了勾。
  • 在 Opus 5.5 上,/verify 成本是 2.5 倍($0.96 對 $0.39),而且沒有改變任何結果。單純用 Opus 12 次全對,其中 11 次自己跑了測試套件。
  • 專案 skill 對模型來說是選擇性的:24 次執行中只觸發 10 次,Haiku 上 6 次中 0 次。Stop hook 每次執行都會觸發,在 Opus 上成本多約 20%。
  • 真正有效的檢查來自作者以外:同一個 /verify 由 Opus 執行,對 Haiku 的修改 3 次中 3 次判定 FAIL,並指出了 bug。把它接成 Stop hook 後,Haiku 3 次中 3 次修好了 bug,每個任務 $1.36,而 Opus 單獨寫這個任務是 $0.76。
  • 可以直接照做:確定性的部分用 Stop hook,需要判斷的部分用不是作者的驗證者,需求寫得清楚的工作在 Opus 上不要用 /verify。

測量結果說了什麼

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

我們的測試用 agent 從未看過的隱藏驗收測試,為每一次「done」評分。112 次任務執行 + 4 次跨模型 /verify 執行 = 116 次執行,API 等值花費 $66.29。錯誤的「done」:112 次中有 12 次,其中 11 次是 Haiku 在 T6 上,設定 A 到 E 全中;另 1 次是 Sonnet 在 T6 的 skill 設定下,它自己新寫的測試是失敗的,而 skill 從未觸發。 s1

內建的 /verify 在三個模型的 24 次執行中,24 次都回報 Verdict: PASS(23 次可解析,1 次未標示的通過),包括 Haiku 壞掉的 T6。在 Opus 上它花 $0.96,單純執行是 $0.39(2.5 倍),耗時 125 s 對 75 s,沒有改變任何結果。 s3

依 5 步流程寫的專案 skill,在 24 次執行中被呼叫了 10 次:Opus 8/12、Sonnet 2/6、Haiku 0/6。Stop hook 每次執行都觸發,在 Opus 上 $0.47 對 $0.39(+20 %)。 s19

盲點是同一條需求,T6 需求 4:一次 update 讓多份符合條件的文件得到相同的唯一值時,必須拋出 DuplicateKeyError。Haiku 在每種設定下(單純、/verify、skill、hook、先寫測試)11 次中有 11 次漏掉。Haiku 自己的 /verify 檢查的是「把一份文件更新成另一份的 email」,從沒試過一次 update 命中多份文件。先寫測試的規則沒有幫助:3/3 仍然漏掉需求 4,其中一次還弄壞了需求 3。 s1

同一份 Haiku 的修改,由另一個模型執行 /verify:Sonnet 說 PASS(1/1),Opus 3/3 說 FAIL,每次都點名同一個情境,也就是一次 update 把相同的值寫入多份文件,每次檢查成本 $0.39 到 $0.47。把 Opus 驗證者接成 Haiku 上的 Stop hook(設定 F),bug 在 3 次中 3 次被修好;三次修復時都撞到 60 turn 上限,每次 T6 執行平均 $1.36(含驗證者),而 Opus 單獨寫 T6 平均 $0.76,且 0 次錯誤的「done」。 s19

測量數據

測試環境:Claude Code 2.1.283 headless(claude -p),隔離的設定目錄,每個任務使用相同提示,60 turn 上限。儲存庫:msiemens/tinydb @ 18d73a1(Python,226 個測試)。六個功能需求 T1 到 T6,每個有 5 條明確需求(T5:6 條)。隱藏驗收測試每條明確需求一個,從不給 agent 看,為每次執行評分;儲存庫自己的測試套件也會跑。錯誤的「done」指一次執行以宣稱完成作結,但有隱藏測試或儲存庫測試套件失敗。

設定:A plain(只有需求);B /verify(A,再以第二個 turn 執行內建的 /verify);C verify skill(依 5 步流程寫的、模型可呼叫的專案 skill);D Stop hook(prove-it.py:測試套件為紅燈時阻止停止,並在第一次停止時要求每條需求附上一行證據);E tests first(CLAUDE.md 規則:寫任何程式碼前,每條需求先有一個失敗的測試);F Opus verifier hook(對該修改執行 claude -p /verify --model opus,非 PASS 判定時阻止,最多 2 輪)。

模型 設定 執行次數 錯誤 done 平均成本 平均 turn 平均耗時
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 含驗證者 61 (cap) 457 s
Sonnet 5 F 1 (T6) 0 $2.30 含驗證者 50 512 s

限制:只有一個儲存庫(小型、測試完善的 Python 函式庫),六個寫得清楚的需求,每格 1 到 3 次重複,headless 執行。隱藏測試只檢查需求中寫明的內容。

週一就做

  • 在讀模型的「done」之前,自己為每條明確需求寫一個驗收測試。測試中的隱藏測試抓到了所有同模型檢查漏掉的問題。
  • 加一個 Stop hook 來跑你的測試套件,紅燈時回傳 block decision。它每次執行都會觸發,skill 不會。
  • 讓任務的第一次停止必須付出每條需求一行證據的代價(prove-it.py 模式):一個指令和它的輸出,而不是一句話。
  • 把判斷性的檢查交給沒有寫這份修改的模型:對 diff 執行 claude -p /verify --model opus,非 PASS 判定時阻止,最多 2 輪。
  • 在 Opus 5.5 上處理寫得清楚的需求時,別再習慣性輸入 /verify。它花了 2.5 倍,12 次執行中沒有改變任何結果;留給沒有測試的區域或既有 bug 的搜查。
  • 如果為了成本把工作交給 Haiku 4.5,要把驗證者算進預算:搭配 Opus hook 每個任務 $1.36,Opus 單獨寫是 $0.76。
  • 把每次失敗修復的重試記錄在帳本裡,重複出現就停止迴圈,這樣阻擋式 hook 就不會在同一個錯誤的修補上燒 token。
  • 重新檢視你的需求中的多列情境:「一次 update 命中多份文件」正是 11 次 Haiku 執行中 11 次都沒試過的情境形狀。

延伸閱讀

  • 5 步流程與成熟度階梯,從手動檢查到 CI gate:最上面幾階(CI 與 PR gate)是 hook 在本機跑順之後,確定性部分該待的地方。 s1
  • Stop hook 的語意:帶 reason 的 block decision 會把這個 turn 送回給模型;寫自己的 gate 之前,先讀 exit code 與 JSON 的約定。 s19
  • Groundtruth,一個在檢查通過前拒絕結束 turn 的 Stop hook:這個想法的確定性版本,可當參考實作來讀。 s5
  • regressionledger,成本面:一個阻止迴圈重試同一個失敗修復的 hook,這是我們的 Stop hook 在執行撞到 60 turn 上限時缺少的部分。 s10

Sources

FAQ

內建的 /verify 能抓到 bug 嗎?

在這次測試中沒有。它在 Opus 5.5、Sonnet 5 和 Haiku 4.5 的 24 次執行中 24 次回傳 PASS,包括一次違反明確需求的 Haiku 修改。它唯一有用的發現,是一個與該修改無關、本來就存在於上游的 bug。

為什麼較強的驗證者能幫到較弱的作者?

Haiku 自己的檢查測的是它早就想到的情境。Opus 拿到同樣的修改、同樣的 /verify,試了一次 update 命中多份文件的情況,3 次中 3 次判定 FAIL。Sonnet 判定 PASS。驗證者必須看到作者沒看到的情境。

用 Opus 驗證 Haiku 比較便宜,還是直接用 Opus 來寫?

用 Opus 來寫。Haiku 搭配 Opus 驗證者 hook,每次 T6 執行平均 $1.36,而且每次都撞到 60 turn 上限;Opus 單獨寫 T6 平均 $0.76,錯誤的「done」為 0。