驗證、安全與工程紀律
agent 不管實際上有沒有成功,都會回報成功。它會說「完成了,所有測試都通過」,而且不管測試真的通過了、測試根本沒跑過,還是測試被偷偷弱化到通過為止,它講這句話的自信程度都一模一樣。對 agent 輸出的信任不是你可以憑空假設的特質;它是你透過驗證一點一滴賺來的特質。這份文件是整章的護欄層:讓 agentic 迴圈和 spec-driven development(規格驅動開發)能夠在高速運轉下依然安全的紀律。
它刻意在工作流程文件略過的地方深入探討。它不會重新解釋 agentic 迴圈,也不會重講 context 檔案裡該放什麼;它要講的是如何讓 agent 輸出值得信任,以及如何讓 AI 輔助的變更保持紀律。
測試是驗證的骨幹
要讓「成功」這個宣稱變得可檢查,最可靠的方法就是讓它變成可執行。測試驅動開發(test-driven development)給你的正是這個。
Red、Green、Refactor
這套經典的 TDD 循環,在 Kent Beck 的《Test-Driven Development: By Example》(2002)中被正式定型,有三個步驟:
- Red:為一個還不存在的行為寫一個小測試,然後看著它失敗。
- Green:寫出能讓測試通過的最少量正式程式碼。
- Refactor:既然有通過的測試把行為釘住了,就把程式碼整理乾淨。
Robert C. Martin(「Uncle Bob」)把這套濃縮成 TDD 三大定律:
- 在你寫出一個會失敗的測試之前,不要寫任何正式程式碼。
- 一個測試只要寫到剛好會失敗就好,不要多寫。
- 正式程式碼只要寫到剛好能讓那個失敗的測試通過就好,不要多寫。
回報是雙重的。在程式碼之前寫的測試是一份可執行的規格:它用機器能檢查的形式,講清楚「正確」到底是什麼意思。同一個測試保留下來,就是一張回歸測試的安全網:一旦後續的變更弄壞了那個行為,它馬上就會失敗。正是這種雙重角色,讓 agent 能夠為自己打分數。
把 TDD 套用到 agentic 開發
對一個自主 agent 來說,測試、build、lint 不是雜事,而是驗證關卡。它們是一個機器可檢查的通過/失敗訊號,讓 agent 能在內層迴圈不需要人介入的情況下,自己把迴圈收尾。沒有關卡,就沒有信任。
先重現,再修復
修 bug 的時候,要求 agent 先寫一個重現該 bug 的失敗測試,然後改程式碼直到那個測試通過。這會逼著修復去處理根本原因,而不是壓掉症狀。放任不管的 agent 常常會把那個失敗的呼叫包進 try/except 裡,把錯誤吞掉,然後宣告勝利。重現測試讓這條捷徑走不通:在底層行為真的正確之前,測試都會一直失敗。
把測試當成已提交的規格
把測試先行的循環當成一份 agent 不能偷偷重談的合約:
- 先寫測試(或讓 agent 寫),把想要的行為描述清楚。
- 跑這些測試,並確認它們是因為正確的原因而失敗。
- 把測試當成獨立的一筆變更提交。
- 實作到測試通過為止,並指示 agent 不要修改已提交的測試。
如果 agent 為了硬湊出綠燈而弱化測試(放寬一個 assertion、刪掉一個 case、加一個提早的 return),diff 就會把它揪出來。一筆和實作出現在同一個 commit 裡的測試變更,是個值得逐行檢視的警訊。
要證據,不要宣稱
「所有測試都通過」是一句宣稱。指令和它的輸出才是 證據。要求 agent 把它實際跑的指令和真正的結果秀出來,而不是給你一段摘要:
$ pytest -q tests/test_auth.py
.... [100%]
4 passed in 0.62s
一個沒有附上輸出的宣稱,按定義就是未經驗證的。讓貼上證據成為常態,並把缺少證據視為一道沒過的關卡。