我讓三個 AI 各司其職寫程式:Codex 出測試、Grok 寫實作、Claude 驗收
這週我沒有讓單一 coding agent 從頭包到尾,而是把一個功能拆成三個角色,讓三家的 CLI 各做一段,中間用 TDD 的紅綠燈當交接介面。跑完兩個 slice,我判斷這條 pipeline 在有嚴格測試當契約的前提下可用;但它省下的不是人力,是把「錯誤發現點」往前、往獨立處移。這只是 workflow 可用性判定,不含可商用判定--後者要另算 token/seat 成本、隱私、rate limit 與審計,本文不碰。
實驗條件(可自行驗證)
- 工具:
codex-cli 0.142.4、grok 0.2.77 (44e77bec3a)、Claude Code(CLI,版本未記錄,屬已知量測缺口)。 - 專案:一個 Zig 0.16.0 codebase(私有 repo,commit hash 僅供我本地對照),加一個「回合後反思」功能。
- 樣本:n=2 slices(config surface、reflection module),共 15 個測試(4 + 11)。
- 出題命令:
codex exec --sandbox read-only(單次、不寫檔)。 - 施工命令:Grok headless、可寫檔模式(write→test→fix)。
- 觸發 400 的命令:對
grok-composer-2.5-fast傳--effort(等同reasoningEffort參數)。 - 驗收命令:
zig test <libs> --dep build_options --dep compat -Mroot=src/root.zig --test-filter "<slice 前綴>";leak-detecting allocator 回報 0 leak。
樣本小,數字不外推;commit hash 為私有 repo,僅供我本地對照。以下每個論斷都設計成能被另一個工程師在幾分鐘內驗證或反駁。
這條 pipeline 實際長什麼樣
一個 slice(一次可 review 的提交)走五步:
- Codex 出測試 + 最小 stub。stub 讓測試「能編譯、但在斷言上失敗」--這是真正的 RED,不是因為符號缺失而編不過。
- Claude 對照原始碼核對測試。Codex 會猜 API(vtable 欄位、函式簽章、建構模式),必須逐一驗證符號存在才落地。
- Claude 放進隔離的 git worktree,跑到確定 RED:pass/fail 混合,每個失敗各有其原因。
- Grok 寫實作到 GREEN。任務只有一句:讓這些失敗的測試通過,只改實作、不准動測試。
- Claude 獨立驗收(不採信 Grok 的自述):跑測試、確認 0 leak、核對 diff 的正確性與改動範圍,才提交。
重點不是「三個比一個強」,而是出測試的人跟寫實作的人不是同一個 agent--測試因此成為獨立的規格,實作成為獨立的檢查。
對照三個真實替代方案
- 單 agent 跑 TDD(自己出測試、自己實作):最快,但自我驗證風險最高--同一個模型既定義正確、又判定自己是否正確。
- 人寫測試 + agent 實作:最可靠,測試由人把關;代價是人工成本最高。
- 本文的三 agent 分工:增加 orchestration 來回(見下),換到的是「假綠」風險下降--任何一環的自欺會在下一環被抓到。
選哪個,取決於你的錯誤成本 vs. 來回成本。
每家 CLI 的落地差異(用法決定,不是廠商能力差異)
三家我都只用了各自的一種模式,差異來自我怎麼接,不是模型智力:
- Codex:我用
codex exec --sandbox read-only的單次模式,讓它只「輸出」測試碼、不改檔。它其實支援--sandbox workspace-write與exec resume(可多輪、可寫檔),但我刻意把它限縮成「出題者」,讓出題與施工不同源。誤把單次 read-only 模式當施工者用,會得到看似對、實際編不過的檔案。 - Grok:我用 headless、可寫檔模式跑 write→test→fix。踩到一個參數相容性的坑:在
grok 0.2.77用grok-composer-2.5-fast傳--effort時,經該 CLI 的 API 路徑回400 Bad Request:invalid-argument: Model grok-composer-2.5-fast does not support parameter reasoningEffort,整輪空轉、零檔案寫入。這是該 model 不吃這個參數,不是 Grok CLI 的限制--grok 0.2.77本身有--effort;換支援的 model 就沒事。 - Claude:負責整合與驗收,因為它能在同一個 session 內持續持有上下文、跑工具、比對 diff。
Integration 成本比模型能力更早成為瓶頸:真正卡我的不是智力,而是一個 Zig 細節--單純 pub const x = @import("x.zig") 的 re-export,若沒被任何 test path 參照,Zig 的 lazy discovery 不會 discover 該檔的測試;要在 root 的 test {} 區塊加 _ = x; 強制 discovery。這種 integration 細節,才是 pipeline 真正的 latency 來源。
成本與失敗場景(正面之外)
- 成本是每個角色的來回,不是一次 LLM 呼叫。n=2 slices 我花了十幾次 agent 呼叫在「出題→核對→RED→施工→驗收」,其中 1 次失敗交接(下述 Grok 空轉),人工驗收(讀 diff、跑測試)每個 slice 約幾分鐘。對小功能,這比單 agent 直接寫慢。划算場景是:功能有明確測試 oracle,且你在意正確性甚於速度。(wall-clock 未逐步計時,故不列;此為已知量測缺口。)
- 不能採信施工者的自述。有一次 Grok 回報「成功」,實際上它跑在錯的目錄、測試本來就綠,它一行沒寫。獨立驗收(跑測試 + 核對 diff)不是形式,是必要防線。
- 紅燈要「可診斷」。若 stub 全部回傳
error.NotImplemented,所有測試會用同一種方式失敗--那是無資訊的 RED。每個測試必須因自己的原因失敗,施工者才知道往哪修。
適用與不適用
- 適用:有靜態型別 + 嚴格測試框架的專案(我這次是 Zig + leak-detecting allocator)、功能可切成小 slice、每個 slice 有明確斷言。測試當契約,跨 agent 交接才有意義。
- 不適用:探索性、規格未定、或「測試本身就是要設計的東西」的工作。這條 pipeline 假設測試是可先寫死的規格;當規格還在流動,強行分工只會把來回成本放大。
判斷
這不是新範式,是把單 agent 的一個內部步驟(自己出測試自己實作)拆成跨 agent 的外部契約。買到的是更早、更獨立的錯誤發現點:測試由 A 寫、實作由 B 做、驗收由 C 跑,任何一環的自欺都會在下一環被抓到。代價是 orchestration 來回,和你必須真的去驗收、而不是相信回報。
對決定要不要把多 agent 導入實際 workflow 的人:先確認你的專案有「測試能當契約」的體質。沒有這個前提,多 agent 只是把一個 agent 的不可靠乘以三。
文中失敗場景(Grok grok-composer-2.5-fast 的 reasoningEffort 400、假成功回報、Zig lazy discovery 需 _ = x;)均為本人實測,工具版本與命令見「實驗條件」。
Comments
No comments yet. Start the discussion.