← All posts / Research

叫 AI 用更好的測試方法,結果反而更糟:Dan Luu 的 26 組對照實驗

Dan Luu 對程式代理跑了 26 種測試指令條件、數千次 Rust 實作,發現指定 TDD、Lean 4、QuickCheck、Verus 等技術的正確率,普遍低於什麼都不說的預設條件。

叫 AI 用更好的測試方法,結果反而更糟:Dan Luu 的 26 組對照實驗

2026 年 9 月 8 日,Dan Luu 發表了一篇文章,悄悄動搖了 AI 輔助工程領域裡一個最令人安心的假設:想讓程式代理寫出正確的軟體,只要告訴它該用哪種品質技術就行。在〈How well do agents use test/verification techniques?〉一文中,他公布了一場大規模對照實驗的結果:他把同一個實作任務交給程式代理,分別套用 26 種不同的測試指令——測試驅動開發(TDD)、Lean 4、QuickCheck、Verus、TLA+、模糊測試、變異測試、SMT 求解器等等——然後實際測量結果。

結論相當直白:沒有任何一個條件大幅勝出,而「Default」——完全不下測試指令——的得分明顯高於平均。點名一項技術不僅沒有幫助,在多數情況下反而有害,因為代理只會膚淺地「表演」那個技術的名目形式,寫出來的測試和實作反而比不指示時更差。

實驗設計

這個評測沿用 Luu 先前文章描述過的基準:在 Rust 中實作 Zstd 壓縮演算法,以「通過隱藏測試套件 100% 的執行次數比例」計分,每個條件、每種運算力等級各跑 80 次取平均。代理是執行 GPT-5.6 Sol 的 codex,分為 medium 與 xhigh 兩種等級。26 個條件涵蓋:重量級形式化方法(ACL2、Alloy、Creusot、Kani、Lean 4、Spin、TLA+、Verus,以及預裝 Z3/cvc5/Yices 的 SMT 求解器)、隨機化測試家族(QuickCheck、Proptest、Hegel、屬性測試、模糊測試、差異測試、蛻變測試),以及流程類指令(TDD、「先稽核」、「稽核並對高風險區域做模糊測試」、用 Insta 做快照測試、用 rstest 做 fixture 測試、Rust 內建測試框架,還有一個只要求代理「自行判斷用最佳技術」的 Judgement 條件)。

另外還測了四個 skill:Hegel 官方 skill、ECC 的 Rust 測試 skill(來自一個有 25 萬 GitHub 星標、3.8 萬 fork 的合集)、Trail of Bits 的屬性測試 skill,以及 Luu 自己花兩分鐘寫的極簡 skill。前三個的挑選標準恰恰是「請 codex 自行找出相關測試 skill」時的頂尖結果——換句話說,就是真實使用者實際會遇到的那幾個。

他還預先註冊了預測(pre-registered predictions),這是少見的嚴謹做法:TDD 會表現不佳(55% 信心)、形式化方法不會勝出(52%)、「Make no mistakes」不會優於不指示(95%)、熱門 skill 會令人失望。這些猜測最後全部應驗。

代理實際上做了什麼

失敗模式在各條件間高度一致,而且比總分數更有意思。代理並沒有拒絕指令——它們在技術上都照辦了,卻幾乎沒有從技術本身獲得任何價值:

  • 形式化方法淪為表演。Verus 條件的代理證明了抽象的算術性質和「A ⇒ A」這類空洞的蘊含式,卻避開真正藏有 bug 的程式路徑。Lean 4 條件如出一轍。TLA+ 條件的代理建了狀態機模型,但 80 次執行中有 75 次是先寫完程式碼才補模型,Luu 找不到任何一個案例是 TLA+ 的發現真正改變了 Rust 實作。
  • 屬性測試退化成煙霧測試。QuickCheck 條件的代理多半只寫了琐碎的檢查;160 次執行中有 63 次只檢查了一個性質。對 Zstd 這種格式,完全隨機的輸入大多只會走進拒絕路徑,所以那種「隨機化」什麼都測不到。
  • 差異測試一點都不差異。160 次執行中有 135 次做了某種「差異測試」,但沒有任何一次建立兩個真正獨立的實作——代理把同樣的東西寫兩遍,把同樣的 bug 編進兩個版本裡。
  • TDD 產生更多測試、更差的測試。TDD 條件的代理寫了約兩倍數量的測試,跑著「測試—寫碼—測試—寫碼」的循環,卻更容易漏掉困難案例,例如 Zstd 的四位元流跳躍表——常常寫出四條完全相同、極度 trivial 的位元流,讓「流順序寫反」這類真正的 bug 完全隱形。

Gary Bernhardt 對代理測試行為的總結——把病態的邊角案例撿出來,當成整個測試策略的骨幹——結果發現只要點名任何一項技術,這個模式就會套用到那項技術上。代理對每種方法做了表面儀式的模式匹配,卻沒有讓方法真正發揮作用的那種判斷力。

例外更值得玩味

有兩個結果讓悲觀的圖像出現了裂縫。第一,當代理產生的是結構化隨機輸入而非天真亂數位元組時,有一半的機率找到真實的 bug——但這種情況只出現在 160 次模糊測試執行中的 10 次。能力是潛在的,只是預設行為觸發不了它。第二,Luu 自己手寫的 skill 在所有條件中得分最高,儘管它只是五條要點:實作前先思考容易有微妙 bug 的區域、偏好邊界與不對稱的例子、把隨機化導向有趣的狀態路徑等等。對照那個 34k 字元的 Hegel 官方 skill——因為 token 龐大和反覆重讀而增加 16–18% 成本、同時降低正確率——反差極為鮮明。寫成「教學手冊」的表現不佳;寫成「把代理推離已知失敗模式」的確實有用。

「解釋」與「引導」的這個區別,大概是全文對今天正在打造代理工具的人最有行動價值的洞見。

為什麼這件事超越 Zstd 本身

Luu 在文末提出了更宏觀的問題:為什麼 AI 實驗室還沒有打造 RL 環境來訓練代理好好測試?他指出代理已經非常擅長有界的執行期最佳化問題——那正是最容易大量生成 RL 環境的任務類型——並推測有效的測試也屬於同一類問題,限制因素可能只是「有效測試技術的知識不夠普及」,以至於實驗室內部沒人想過要試。他還提醒,他的 RFC 評測其實比真實世界更容易,因為真實的規格更含糊、更有歧義,所以這裡看到的失敗模式在實際使用中只會相同或更糟。

文章結尾的一句話,會讓所有正在交付代理程式碼的人心有戚戚:從公開程式代理問世到今天(2026 年 9 月),如果代理不需要測試專家引導就懂得怎麼測試,代理式編碼的效能早就大幅提升了。在實驗室補上這個缺口之前,「怎麼讓代理把測試寫好?」這個問題的實證答案,不是任何一個技術名稱,而是一個會看代理做了什麼、發現失敗模式、再多打幾句話的人。