迴圈工程實驗發現回饋迴圈與驗證器可能悄然失效
重點速覽
- •該實驗評估了兩個迴圈工程元件:使用真實測試失敗的回饋迴圈,以及將程式碼生成與最終判斷分離的 maker/checker 架構。
- •第一次測試執行顯示,真實回饋沒有帶來效益,原因是隱藏測試框架只回傳裸露的 assertion error,缺乏有用的失敗細節。
- •在框架加入失敗輸入、預期輸出與實際結果後,真實回饋解出了一個通用重試迴圈無法解決的問題。
- •執行測試的驗證器在 8 個錯誤候選中錯誤接受了 3 個,在該測量比較中高於兩個基於意見的檢查器。
- •最終組合系統的成效主要來自回饋迴圈,而驗證器產生的一次錯誤接受,是靠隱藏測試評分才被抓到。

最後更新於 2026 年 7 月 27 日,作者為編輯團隊。原刊於 Towards AI。
「我的工作是寫迴圈。」
這句話出自 Boris Cherny,他在 Anthropic 負責 Claude Code。Cherny 曾表示,他已停止直接提示 Claude,現在把時間花在設計會替他提示 Claude 的迴圈上 [1]。這句話,加上幾個類似說法,促成了今年一波迴圈工程解說文章 [1][2]。讀完其中六篇後,我自己建了一個。
更精確地說,我建了幾乎每篇解說都會描述、但很少真正端到端執行的兩個元件。第一個是 run-until-done 迴圈:模型失敗後,不是要求它再猜一次,而是把它自己的真實測試失敗回饋給它。第二個是 maker/checker 架構:寫程式碼的模型不能成為判斷程式碼是否正確的最終裁判。
這項區分很重要,因為編碼代理工作流程通常仰賴同樣的分離:一個系統提出變更,另一個工具、測試套件或模型則決定該變更是否可接受。如果回饋通道或驗證器薄弱,迴圈看起來可能已自動化,卻不會因此變得實質上更安全。
我用約 600 行 Python 從零實作這兩者,將其接到 claude-opus-4-8,並用 MBPP+ [3] 評估。MBPP+ 是 EvalPlus 的小型 Python 程式設計任務基準,適合在不引入儲存庫規模複雜性的情況下隔離迴圈行為。本文討論的所有實驗總成本不到兩美元。第二個元件——常被視為較安全的一半,因為它「實際執行測試」,而不是相信模型自己的說法——在我的測量中產生了那些解說文章未曾警告過的結果。
簡短版本是:迴圈工程的兩個核心部分很容易接起來,也很容易在不知不覺中做錯。我的「真實回饋」迴圈一開始看起來與隨機重試沒有差別,直到我在自己的測試框架中發現一個錯誤。我的「安全」執行測試驗證器,錯誤接受率高於一個只是詢問模型有多大信心的檢查器。建立迴圈只是容易的 20%。
把迴圈接到空訊號上
許多關於迴圈工程的文章都停在接線圖。它列出觸發器、可驗證目標、工具、狀態與停止規則——五個方塊,中間用箭頭連起來。其隱含訊息是,只要方塊接上了,迴圈就會運作。
這就像安裝煙霧偵測器後,因為它已裝在天花板上且接好了線,就宣稱房子安全,卻沒有檢查它是否有可用的電池。
我在自己的「真實回饋」迴圈中遇到的正是這種失敗。它連接的是實際測試輸出,而不是通用重試提示。理論上,它應該明顯優於只收到「那是錯的,再試一次」訊息的迴圈。但我的第一次執行結果並非如此。
會評分評分器的評分器
在碰迴圈本身之前,我先建立了其他所有東西都依賴的元件:一個評分器,會在隔離的子程序中、搭配硬性逾時限制執行候選程式碼,並依據隱藏測試評分。
在它能為自己評分之前,我不信任這個評分器。給它一個已知正確的解法時,它必須通過。給它一個已知錯誤的解法時,它必須失敗並附上 assertion error。給它一個無限迴圈時,它必須被逾時機制終止,而不是永遠卡住。
接著,我用 75 個 MBPP+ 參考解法驗證整條管線。75 個全數通過。只有在那之後,我才信任迴圈產生的任何數字。
看起來正確但其實不是的迴圈
迴圈本身非常簡單。它產生一個解法、進行評分,並在失敗時回饋真實 stderr——不是通用的「再試一次」,而是實際錯誤——最多嘗試三次。
我也建立了一個控制組,因為我不想在沒有基準的情況下相信標題式數字。控制組使用完全相同的迴圈,但把真實錯誤替換成通用指令:「那是錯的,寫一個不同的解法。」如果真實回饋沒有明顯勝過它,那就代表接線中有東西壞了。
第一次在 35 個問題上執行時,三組結果全都一樣。這不是迴圈正常運作的證據,而是一個長得像迴圈的警訊。
我沒有只看總體指標,而是檢查失敗案例,並找到了問題:MBPP+ 的隱藏測試框架失敗時只給出裸露的 AssertionError。它沒有包含失敗輸入、預期值或實際值。因此,「真實回饋」在資訊上等同於「再試一次」,因為模型沒有收到任何可據以行動的內容。
我為框架加上儀器化,使其回報失敗輸入、預期輸出,以及程式碼實際回傳的值。第二次在同樣 35 個問題上執行時,真實回饋解出了一個通用組無法解決的問題,整次執行額外花費約 2,500 個輸入 token。
迴圈本身並沒有壞。它連接到的訊號是空的。只有控制組揭露了這件事;單看標題指標不會發現。
驗證器以理論未預測的方式失敗
迴圈需要停止規則,而「模型說它完成了」不是停止規則。因此,我建立了一個檢查器,會根據規格自行撰寫測試。它從未看見隱藏測試,也從未看見自己正在評判的解法程式碼。然後它會執行那些測試。策略是只有完全通過才接受,預設拒絕。
我把這個驗證器與三個較弱的檢查器比較,對象是我的迴圈產生的 41 個候選解法:33 個正確、8 個錯誤。測量項目是錯誤接受率,也就是各檢查器有多常讓實際上有問題的程式碼通過。
| 檢查器 | 錯誤接受 | 錯誤拒絕 |
|---|---|---|
| 全部信任 | 8/8 — 100% | 0/33 — 0% |
| 詢問模型是否有信心 | 2/8 — 25% | 4/33 — 12% |
| 第二個模型閱讀程式碼 | 2/8 — 25% | 5/33 — 15% |
| 撰寫測試並執行 | 3/8 — 38% | 1/33 — 3% |
我原本預期執行測試的檢查器會在錯誤接受方面直接勝出。但它沒有。它放行錯誤程式碼的比例,高於任一基於意見的檢查器。
原因比數字本身更重要。所有八個錯誤候選都來自三個規格真正含糊的問題。檢查器與修正器是同一個模型,在閱讀同一句含糊描述。因此,檢查器自行撰寫的測試編碼了錯誤程式碼已經具有的同一種誤讀,使錯誤程式碼能乾淨地通過那些測試。
基於意見的檢查器之所以在錯誤接受比較中「勝出」,主要是因為它們通常比較保守。這種保守也正是它們錯誤拒絕正確程式碼的次數多出四到五倍的原因。
執行測試並不是避免錯誤接受的通行證。它是另一種證據:包含具體輸入、預期值與實際值,而不是一般印象。這使它 3% 的錯誤拒絕率可作為真正的閘門使用。會拒絕 15% 良好工作的檢查器,在阻止一次糟糕合併前,可能先讓工作流程淹沒在重試中。
組合兩個部分
最終組合會先執行回饋迴圈。如果失敗,則抽樣新的候選解法,並讓驗證器——而不是模型的信心——決定提交什麼。如果沒有任何候選達到標準,也有明確的放棄路徑。
我在一個保留的 MBPP+ 子集上評估這套設定;在建構前述任何元件時,我都沒有使用過這個子集。評分是依據隱藏測試完成,且獨立於驗證器做出的任何判斷。
迴圈基本上完成了全部工作:它增加 14.2 分,恢復了六個單次解題失敗中的五個,並需要約 10 次額外 API 呼叫。驗證器階段只觸發一次,發生在迴圈無法解決的那個問題上。它第一個抽樣候選通過了自己撰寫的測試,但仍未通過隱藏測試。
那是一次實際發生的錯誤接受,正好符合前面表格預測的失敗模式。它之所以被抓到,只是因為執行器會根據驗證器永遠看不到的真實依據來評分提交內容。如果驗證器自己的判斷就是最終結果,那個錯誤就會被送出。
此階段總成本為 45 次呼叫,約十三美分。
這種方法會在哪裡失效
當目標確實可測試時,這種方法有效:例如具有隱藏測試案例的函式、要嘛通過驗證要嘛不通過的結構描述,或是迴圈無法靠話術繞過的判定器。當規格本身含糊時,它就無效,因為同模型檢查器可能繼承產生器的同一種誤讀。在這種情況下,修正方式不一定是更聰明的檢查器,而是更清楚的規格,或來自完全不同模型家族的獨立判定器。
我也只在小型、獨立的 MBPP+ 函式上測試了這一點。這項實驗沒有處理具有跨檔案相依性的龐大程式碼庫。我也沒有建立或測試用於平行執行多個迴圈的 worktree 隔離。那是實際問題,但不是這次實驗測量的問題。
這個迴圈也停在「已驗證」。它不會決定要自動套用變更,還是升級交給人類處理。一旦系統接觸到任何具有實際寫入權限的東西,這就會成為另一個更困難的問題。
從這裡開始
先從評分器開始。在寫任何迴圈邏輯之前,先寫自我測試——已知正確、已知錯誤與無限迴圈。這個五分鐘腳本,是防止虛構標題數字的主要保護。
對於即使只有少量單元測試的程式碼庫,下一步是接上回饋迴圈,並從第一天起同時建立通用重試控制組。在它勝過「再試一次」之前,不要相信改善幅度。
接著,建立第二個檢查器,並與第一個比較。當錯誤接受表與理論暗示不一致時——而且它可能會不一致——其原因將說明為什麼迴圈比其底層模型更重要。
參考資料
[1] Rohan Mistry, “Prompt Engineering Is Dead. Loop Engineering Is Here.,” Towards AI, July 2026.
[2] Mehmet Özel, “Loop Engineering for AI Agents : Building Verifiable, Self-Correcting Coding Workflows,” Towards AI, June 2026.
[3] EvalPlus, “MBPP+ Dataset,” Hugging Face Datasets.