← 所有文章

證據關卡

一個 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 會複製這種模式。證據關卡是一種訓練後的介入措施,透過拒絕接受缺乏產物的報告來打破這個模式。

榮譽檢查

證據關卡是更廣泛的品質體系——榮譽檢查——的一部分。每次非瑣碎的變更後,問自己五個問題:

  1. 資深工程師會認可這個做法嗎?
  2. 程式碼是否不言自明?
  3. 邊界情況是否已處理?
  4. 簡潔程度是否恰到好處?
  5. 我是否讓程式碼庫比之前更好了?

榮譽檢查是主觀的,而證據關卡是客觀的。證據關卡問的是「你能證明這行得通嗎?」榮譽檢查問的是「你會驕傲地把這個展示給你尊敬的人看嗎?」兩者缺一不可。有證據無榮譽,產出的程式碼能運作但無人願意維護。有榮譽無證據,產出的程式碼讀起來漂亮但未必能用。

兩者結合形成品質迴圈:實作、逐行審查、通過證據關卡、進行榮譽檢查、修正所有發現的問題,反覆直到兩者都通過。這個迴圈不高效,也不快速,但它是正確的。在 Agent 能高速產出看似合理的程式碼的時代,正確性才是真正的差異化因素。

失敗模式

證據關卡能捕捉幽靈驗證,但無法捕捉所有失敗模式。在自主 Agent 工作階段中,有七種已命名的失敗模式:1

捷徑螺旋。 跳過證據關卡步驟以更快回報完成。Agent 產出不完整的報告卻聲稱已完成。

信心海市蜃樓。 以高度確信的語氣說出「我有信心」。證據關卡能捕捉這類語言,但足夠流暢的 Agent 可能會改寫措辭來規避偵測。

差不多高原。 程式碼能運作,但既不乾淨也缺乏測試。證據關卡的「最簡可行方案」準則能部分解決此問題,但榮譽檢查才是主要防線。

隧道視野。 精雕細琢一個函式,卻破壞了相鄰的程式碼。「無迴歸問題」準則能應對此問題,但前提是 Agent 檢查了正確的檔案。

延遲債務。 在提交的程式碼中留下 TODO/FIXME/HACK。證據關卡不檢查這些,應由單獨的 lint 規則來防範。

空洞報告。 一句「完成」卻沒有任何準則的證據。證據關卡的結構使這種情況明顯不完整,但 Agent 可能產出看似完整卻遺漏某項準則的報告。

幽靈驗證。 證據關卡的首要目標。聲稱進行了測試或驗證卻沒有產物。當關卡被持續執行時,12% 的失敗率降至接近零。

紀律

證據關卡不是技術創新,而是一種紀律。在接受聲明之前要求舉證的紀律。將「我相信」視為不充分的紀律。即使你知道測試會通過,仍然執行測試的紀律。

這種紀律在 Agent 時代比以往更加重要。當人類開發者說「測試通過」時,通常確實跑過了測試——聲明與觀察合而為一,因為兩者都是人類親自完成的。但當 Agent 說「測試通過」時,可能兩者都沒做。證據關卡將聲明與觀察分離,並要求兩者兼備。

在看似合理的輸出充斥的時代,舉證是唯一可靠的訊號。其餘一切不過是推論。


常見問答

這不就是程式碼審查嗎?

程式碼審查檢查的是程式碼是否正確。證據關卡檢查的是完成報告是否誠實。程式碼審查可能批准從未測試過的正確程式碼。證據關卡則無論程式碼看起來多正確,都要求測試輸出。

這會拖慢開發速度嗎?

會。執行測試、讀取檔案、引用具體證據都需要時間。替代方案是將經過幽靈驗證的程式碼上線,然後在正式環境中才發現 Bug。證據關卡用開發速度換取部署信心。

Agent 能學會規避證據關卡嗎?

Agent 可能偽造測試輸出或引用錯誤的行號。證據關卡並非對抗性攻擊的防護。它捕捉的是常見失敗模式(推論偽裝成觀察),而非蓄意偽造。蓄意偽造需要不同的防禦機制。

如何對自主 Agent 執行此機制?

證據關卡的準則是系統提示的一部分。品質迴圈(實作、審查、關卡、檢查、修正、重複)被編碼在編排系統中。Agent 無法在未提供全部六項準則的證據之前回報完成。若任一準則缺失,迴圈會返回修正步驟。


參考資料


  1. Blake Crosley, “What I Told NIST About AI Agent Security,” blakecrosley.com, February 2026. 12% phantom verification rate across 60+ autonomous sessions. 

相關文章

品質是唯一的變數

時間、成本、資源與心力都不是限制條件。真正的問題是「什麼才是對的」,而非「什麼最有效率」。一套與 AI 代理協作的工程哲學。

1 分鐘閱讀

每個鉤子都是一道傷疤:84 個代理故障編碼於程式碼中

84 個鉤子攔截了 Claude Code 公開的 26 個生命週期事件類型中的 15 個。每一個都可追溯到特定的生產環境故障:被清空的快取、外洩的憑證、虛構的測試。

2 分鐘閱讀

為什麼我的AI代理擁有品質哲學

我的Claude Code代理以機器速度繼承了人類所有的馬虎習慣。我建立了3套哲學、150多道品質關卡和95個hooks。以下是有效的做法。

4 分鐘閱讀