證據關卡
一個 Agent 回報「所有測試通過」,卻從未執行 pytest。輸出語氣自信,措辭自然,但內容是假的。該次工作階段中根本沒有呼叫任何測試套件。Agent 根據對程式碼變更的理解推斷測試會通過,並將推斷當作事實陳述。
我之所以發現,是因為我有一條規則:每份完成報告都必須引用具體證據。不是「我有信心測試會通過」,而是測試輸出本身——貼上來,顯示零失敗。不是「檔案應該已經更新了」,而是檔案路徑、行號、具體的變更內容。不是「這遵循了現有模式」,而是模式的名稱、它存在的檔案,以及新程式碼在哪一行與之吻合。
這條規則在我的系統中有個名字:證據關卡。任何工作在完成報告中的每項聲明都有可觀察的佐證之前,都不算完成。「我相信」不是證據。「應該沒問題」不是證據。「我有信心」不是證據。證據是檔案路徑、測試結果、具體的程式碼引用,或直接的觀察結果。
為何此刻格外重要
語言模型擅長產出看似合理的文字。這既是它們的核心能力,也是核心風險。除非你要求驗證產物,否則一段關於測試結果的合理聲明與一段經過驗證的聲明無從分辨。
失敗模式並非戲劇性的幻覺——Agent 不會憑空捏造測試框架或偽造錯誤訊息。真正的失敗模式是將推論偽裝成觀察。Agent 推理測試應該會通過,然後把這個推理當成測試報告來呈現。推理甚至可能是正確的。但推理測試結果和實際執行測試是兩回事,Bug 就藏在這道裂縫之中。
我將此稱為幽靈驗證:完成報告聲稱進行了驗證,實際上並沒有。在我追蹤的 500 多次自主工作階段中,幽靈驗證佔了需要人工介入的 Agent 失敗案例的 12%。1這是最常見的、不會產生可見錯誤的失敗模式。Agent 回報成功,輸出看起來乾淨俐落,Bug 就這樣上線了。
關卡機制
證據關卡包含六項準則。每次非瑣碎的變更都必須為全部六項提供證據,工作才算完成。
| 準則 | 必要證據 |
|---|---|
| 遵循程式碼庫模式 | 指出模式名稱及其所在的檔案 |
| 最簡可行方案 | 說明曾考慮哪些更簡單的替代方案,以及為何捨棄 |
| 已處理邊界情況 | 列出具體的邊界情況及各自的處理方式 |
| 測試通過 | 貼上測試輸出,顯示零失敗 |
| 無迴歸問題 | 指出檢查過的檔案與功能 |
| 解決了實際問題 | 陳述使用者的需求,以及此方案如何滿足該需求 |
這些準則刻意設定得非常具體。每一項都要求特定的產物,而非籠統的保證。「遵循程式碼庫模式」不能用「我遵循了現有慣例」來交差,而是要說明:「fetch_nvd() 中的重試模式與 fetch_semantic_scholar() 第 241 行的指數退避一致。」
具體性正是關鍵所在。當 Agent 必須提供檔案路徑和行號時,就無法進行幽靈驗證。檔案要麼在該路徑存在且程式碼與聲明吻合,要麼就不吻合。沒有模稜兩可的空間。
模糊語言作為訊號
證據關卡內建了模糊語言偵測機制。以下特定用詞會觸發重新驗證:
- 「應該」(「這應該可以運作」)
- 「大概」(「這大概能處理那個邊界情況」)
- 「看起來」(「輸出看起來正確」)
- 「我相信」(「我相信測試會通過」)
- 「看起來沒問題」(「實作看起來沒問題」)
- 「我有信心」(「我有信心這是對的」)
每個這樣的詞都表明 Agent 是在推理結果,而非觀察結果。推理或許正確,但如果 Agent 能夠直接觀察結果(執行測試、讀取檔案、檢查輸出),推理就是比觀察更弱的證據形式。
當完成報告包含模糊語言時,回應不是「你錯了」,而是「用觀察結果取代你的模糊說法」。如果你相信測試通過,就執行測試並貼上輸出。如果看起來正確,就讀取檔案並引用具體行號。模糊語言是驗證被跳過的訊號,而非驗證失敗的訊號。
Agent 為何使用模糊語言
Agent 使用模糊語言有三個原因,理解這些原因對設計關卡機制至關重要。
上下文視窗壓力。 執行測試套件消耗上下文空間,讀取檔案也消耗上下文空間。管理長時間工作階段的 Agent 可能會跳過驗證,以便為下一項任務保留上下文。證據關卡使這種取捨透明化:Agent 無法在缺少產物的情況下聲稱完成,因此上下文壓力會表現為未完成的工作,而非幽靈驗證。
工具呼叫迴避。 某些 Agent 配置會對工具呼叫施加懲罰或限制。如果 Agent 能在不呼叫 pytest 的情況下回報「測試通過」,就省下了一次工具呼叫。證據關卡消除了這條捷徑:測試輸出是必要的,因此工具呼叫也是必要的。
從人類模式中訓練。 人類經常在完成報告中使用模糊語言:「我更新了設定,測試應該會通過。」在人類文本上訓練的 Agent 會複製這種模式。證據關卡是一種訓練後的介入措施,透過拒絕接受缺乏產物的報告來打破這個模式。
榮譽檢查
證據關卡是更廣泛的品質體系——榮譽檢查——的一部分。每次非瑣碎的變更後,問自己五個問題:
- 資深工程師會認可這個做法嗎?
- 程式碼是否不言自明?
- 邊界情況是否已處理?
- 簡潔程度是否恰到好處?
- 我是否讓程式碼庫比之前更好了?
榮譽檢查是主觀的,而證據關卡是客觀的。證據關卡問的是「你能證明這行得通嗎?」榮譽檢查問的是「你會驕傲地把這個展示給你尊敬的人看嗎?」兩者缺一不可。有證據無榮譽,產出的程式碼能運作但無人願意維護。有榮譽無證據,產出的程式碼讀起來漂亮但未必能用。
兩者結合形成品質迴圈:實作、逐行審查、通過證據關卡、進行榮譽檢查、修正所有發現的問題,反覆直到兩者都通過。這個迴圈不高效,也不快速,但它是正確的。在 Agent 能高速產出看似合理的程式碼的時代,正確性才是真正的差異化因素。
失敗模式
證據關卡能捕捉幽靈驗證,但無法捕捉所有失敗模式。在自主 Agent 工作階段中,有七種已命名的失敗模式:1
捷徑螺旋。 跳過證據關卡步驟以更快回報完成。Agent 產出不完整的報告卻聲稱已完成。
信心海市蜃樓。 以高度確信的語氣說出「我有信心」。證據關卡能捕捉這類語言,但足夠流暢的 Agent 可能會改寫措辭來規避偵測。
差不多高原。 程式碼能運作,但既不乾淨也缺乏測試。證據關卡的「最簡可行方案」準則能部分解決此問題,但榮譽檢查才是主要防線。
隧道視野。 精雕細琢一個函式,卻破壞了相鄰的程式碼。「無迴歸問題」準則能應對此問題,但前提是 Agent 檢查了正確的檔案。
延遲債務。 在提交的程式碼中留下 TODO/FIXME/HACK。證據關卡不檢查這些,應由單獨的 lint 規則來防範。
空洞報告。 一句「完成」卻沒有任何準則的證據。證據關卡的結構使這種情況明顯不完整,但 Agent 可能產出看似完整卻遺漏某項準則的報告。
幽靈驗證。 證據關卡的首要目標。聲稱進行了測試或驗證卻沒有產物。當關卡被持續執行時,12% 的失敗率降至接近零。
紀律
證據關卡不是技術創新,而是一種紀律。在接受聲明之前要求舉證的紀律。將「我相信」視為不充分的紀律。即使你知道測試會通過,仍然執行測試的紀律。
這種紀律在 Agent 時代比以往更加重要。當人類開發者說「測試通過」時,通常確實跑過了測試——聲明與觀察合而為一,因為兩者都是人類親自完成的。但當 Agent 說「測試通過」時,可能兩者都沒做。證據關卡將聲明與觀察分離,並要求兩者兼備。
在看似合理的輸出充斥的時代,舉證是唯一可靠的訊號。其餘一切不過是推論。
常見問答
這不就是程式碼審查嗎?
程式碼審查檢查的是程式碼是否正確。證據關卡檢查的是完成報告是否誠實。程式碼審查可能批准從未測試過的正確程式碼。證據關卡則無論程式碼看起來多正確,都要求測試輸出。
這會拖慢開發速度嗎?
會。執行測試、讀取檔案、引用具體證據都需要時間。替代方案是將經過幽靈驗證的程式碼上線,然後在正式環境中才發現 Bug。證據關卡用開發速度換取部署信心。
Agent 能學會規避證據關卡嗎?
Agent 可能偽造測試輸出或引用錯誤的行號。證據關卡並非對抗性攻擊的防護。它捕捉的是常見失敗模式(推論偽裝成觀察),而非蓄意偽造。蓄意偽造需要不同的防禦機制。
如何對自主 Agent 執行此機制?
證據關卡的準則是系統提示的一部分。品質迴圈(實作、審查、關卡、檢查、修正、重複)被編碼在編排系統中。Agent 無法在未提供全部六項準則的證據之前回報完成。若任一準則缺失,迴圈會返回修正步驟。
參考資料
-
Blake Crosley, “What I Told NIST About AI Agent Security,” blakecrosley.com, February 2026. 12% phantom verification rate across 60+ autonomous sessions. ↩↩