AIDive

Claude Code 幫自己蓋章 PASS,功能其實是壞的

AIDive · 發布

編碼 agentAI 模型

它自己批改自己:PASS

Claude Code 內建的驗證檢查 /verify,在一個其實壞掉的功能上回傳了 PASS。這是在一個真實程式庫上跑了 116 次 Claude Code session 後得到的結果,每一次「完成」事後都用 agent 從未看過的驗收測試來評分。

Boris Cherny,Claude Code 的創造者,稱驗證是你能給它的最重要的東西。這個內建檢查自 Claude Code v2.1.215 起只能手動觸發:你打 /verify,不然它就不會跑。在這次測試中,它在 24 次執行裡全部回傳 PASS,其中一次還是已經出包的功能。真正抓到那個 bug 的是什麼,會在下面說明,還有那個貴了兩倍半、卻什麼都沒改變的設定。

測試方式:116 次任務,從沒看過的測試

一次假的「完成」,指的是某個 session 宣稱工作已經完成,但一個隱藏的驗收測試,或是程式庫自己的測試套件,卻失敗了。這次測試衡量的,就是在六種驗證設定下,這種情況發生的頻率。

背後的疑慮來自 Claude Code 自己的 issue tracker:2026-09-23 提出的 issue #96416,描述了一次列出 19 項疑慮、驗證了其中 5 項、卻仍然做出「照現狀接受」(accept as is)結論的審查。

Parameter Value
程式庫 msiemens/tinydb(Python 文件資料庫),commit 18d73a1
程式庫測試套件 226 個測試
功能需求 6 個,每個列出 5 項要求
隱藏驗收測試 每項要求一個,在任何一次執行之前就寫好,agent 從未看過
模型 Opus 5.5、Sonnet 5、Haiku 4.5
Claude Code 2.1.283,headless 模式(claude -p),60 回合上限
Sessions 112 次任務執行 + 4 次跨模型 /verify 執行 = 116
花費 66.29 美元(API 等值)

六種設定,從純 Claude Code(只丟出需求)到讓第二個模型在停下時檢查工作:

Setup What it adds
A plain 什麼都沒加
B /verify 內建的 /verify,在第二輪手動輸入
C verify skill 依照 Anthropic 的流程寫的一個 project skill
D Stop hook 一個 script,在測試套件是紅燈時阻擋停下,並要求針對每項要求提供證據
E tests first 一條 CLAUDE.md 規則:任何程式碼寫之前,先為每項要求寫一個會失敗的測試
F Opus verifier 一個 Stop hook,讓 Opus 對這次變更執行 /verify

清楚的需求配上一個測試完善的函式庫,是最簡單的情況。純 Opus 5.5 十二次執行全部答對,而且有十一次是自己主動跑了測試套件才說完成。

內建的 /verify:每次都 PASS,貴 2.5 倍

/verify 是 Claude Code 內建的驗證 skill。它會跑一次變更、讀取 diff,然後逐步寫下判定結果。自 v2.1.215 起它只能由使用者觸發,所以在這次測試中,它是在每個任務之後,作為第二輪手動輸入執行的。

它在三個模型、24 次執行中全部回傳 PASS 判定,包括 Haiku 那個壞掉的變更。在 Opus 5.5 上,它沒有改變任何結果,卻多花了 2.5 倍的成本:

Opus 5.5, per task Plain With /verify
成本 $0.39 $0.96
實際耗時 75 秒 125 秒
結果改變 12 次中 0 次

平心而論,/verify 確實抓到了一個真的 bug:在一次 Opus 任務中,它標出了一個「重用已關閉物件」的問題,但那個問題本來就存在於函式庫裡,並非這次要檢查的變更造成的。在原本就寫對的工作上,它只是一個昂貴的第二意見。

Skill 還是 hook:哪一個會被跳過

skill 是一份 Claude 判斷相關時才會打開的 markdown 流程。Anthropic 部落格文章談驗證迴圈的那篇,描述了一套六步驟做法:挑出你最常手動做的後續檢查、先試試內建的 /verify、把流程寫成白話文字、把它變成一個 skill,然後在新任務上呼叫它並反覆迭代。這次測試用的 skill,verify-change,就是照這個方法建的,它會要求 Claude 在說完成之前,先對照真正的程式碼證明每一項要求。

skill 是一種建議,Claude 自己決定要不要打開它:

Model Sessions that opened the skill
Opus 5.5 12 次中 8 次
Sonnet 5 6 次中 2 次
Haiku 4.5 6 次中 0 次
總計 24 次中 10 次

唯一一次 Sonnet 假「完成」,來自一個從未打開 skill 的 session:它結束時,自己新寫的兩個測試都是失敗的。

Stop hook 是 Claude Code 每次 agent 嘗試結束時都會執行的一個 script。它可以拒絕結束,並附上理由把 agent 送回去。這次測試的 hook 會跑測試套件、在紅燈時擋下,並在第一次嘗試結束時要求針對每項要求提供一行證據。它在每一個 session 都有觸發。在 Opus 上,它多花了 20% 的成本,$0.47 對比 $0.39(94 秒對比 75 秒)。在這次測試中,它從未遇到過在停下那一刻是紅燈的測試套件,所以沒有東西可抓:hook 每次都會觸發,但它只檢查你告訴它要檢查的東西。

盲點:11 次裡漏掉 11 次

那個失敗的任務要求資料表上的欄位要唯一:兩個使用者不能共用同一個 email,任何會讓兩份文件變成同一個唯一值的更新,都必須拋出 DuplicateKeyError。

Haiku 4.5 測試了把一個使用者的 email 改成另一個使用者的 email,這個情況正確地被拒絕了。但它從沒測試過這種情況:一次更新同時符合多份文件,把同一個新 email 寫進所有文件裡。這種情況在 11 次 Haiku session 裡全部都直接通過、沒有出現錯誤,而且是在每一種同模型設定下都一樣:plain、/verify、skill、Stop hook 和 tests first。

Haiku 自己的 /verify 勾選了它試過的那個情況,寫下 PASS。隱藏測試回報的卻是 DID NOT RAISE DuplicateKeyError。讓 Sonnet 5 對同一個變更執行 /verify,也一樣回傳 PASS。Opus 和 Sonnet 都各自把這個功能寫對了,所以這只是一個模型在一項任務上的結果,但由同一個模型寫的檢查,會有同一個盲點。

外部檢查:Opus 判定 FAIL

同樣的 /verify,對同一個 Haiku 變更,這次改由 Opus 5.5 執行,結果是 3 次中 3 次都判定 FAIL,每一次都準確指出漏掉的那個情況:一次更新同時符合多份文件,卻把同一個值寫進所有文件裡而沒有出現錯誤。抓到這個問題的,是另一個模型,不是作者本人,也不是作者自己的檢查。

把它接成 Stop hook(設定 F)之後,每次 Haiku 嘗試結束時,Opus 都會檢查這次工作。結果如下:

T6, per run Haiku + Opus checker Opus 5.5 alone
Bug 修好/假「完成」 3 次中 3 次修好 0 次假「完成」
回合數 每次執行都碰到 60 回合上限
成本 $1.36(含檢查者) $0.76

外部檢查真的有用。但在這個任務上,它花的錢比讓更強的模型自己寫這個功能還要多。

可以照抄的做法,以及代價

別再讓寫出變更的那個模型,成為唯一檢查它的人。

Rule Why Cost on this bench
對任何 script 就能檢查的事,保留一個 Stop hook 它每個 session 都會觸發 在 Opus 上大約多花 20%
讓真正的檢查來自作者之外:在關卡上放一個更強的模型,或是你自己依照需求寫的測試 同一個模型自己漏掉同一個 bug,11 次裡漏了 11 次 Haiku + Opus 檢查者,每個任務 $1.36
用 Opus 處理清楚的需求時,跳過手動輸入 /verify 0 個結果改變 成本 2.5 倍,125 秒對比 75 秒

限制:一個小型函式庫、六個清楚的需求、每格只跑一到三次、headless session,而且隱藏測試只檢查每個需求裡明講的內容。換成更混亂的工作,這些數字會變。

來源

常見問題

Claude Code 的 /verify 抓得到 bug 嗎?
當同一個模型檢查自己的工作時,不太可靠。在這次 116 個 session 的測試裡,/verify 24 次執行全部回傳 PASS,其中包含一次違反明講要求的 Haiku 4.5 變更;換成 Opus 5.5 對同一個變更執行,3 次中 3 次都回傳 FAIL。
在 Claude Code 上搭配 Opus 使用,/verify 值得嗎?
面對清楚的需求時不值得。在 Opus 5.5 上,它把每個任務的成本從 $0.39 拉高到 $0.96(2.5 倍),時間從 75 秒拉高到 125 秒,卻沒有改變 12 個結果中的任何一個,因為純 Opus 12 次裡已經有 11 次自己主動跑了測試套件。
做驗證時,該用 Claude Code 的 skill 還是 Stop hook?
只要 script 能檢查的事,就用 Stop hook。Claude 在 24 次 session 裡只打開驗證 skill 10 次(Opus 12 次中 8 次、Sonnet 6 次中 2 次、Haiku 6 次中 0 次),而 Stop hook 每次 agent 嘗試結束時都會執行;在 Opus 上大約多花 20% 成本。
什麼是 Claude Code 的 Stop hook?
一個 script,Claude Code 每次 agent 嘗試結束時都會執行。它可以用 block 的 JSON 決策拒絕結束並附上理由,把 agent 送回去繼續做;它只會檢查 script 裡有測試到的東西。
在 Claude Code 裡,可以讓更強的模型檢查較弱模型寫的程式碼嗎?
可以。把 Opus 5.5 的 /verify 接成 Stop hook,讓 Haiku 4.5 在 3 次執行裡都修好了它漏掉的情況。代價不小:每次執行都碰到 60 回合上限,平均花費 $1.36,相較之下讓 Opus 自己寫這個功能只要 $0.76。
為什麼 AI 模型會漏掉自己程式碼裡的 bug?
因為它的檢查只會測試自己已經想到的情況。Haiku 驗證了把一個使用者的 email 改成另一個人的,卻從沒測過一次更新同時打中多份文件的情況,所以它自己的 /verify 只勾了試過的那個案例,寫下 PASS,而隱藏測試卻是失敗的。

相關影片