我讓三個 AI 各司其職寫程式:Codex 出測試、Grok 寫實作、Claude 驗收
這週我沒有讓單一 coding agent 從頭包到尾。我把流程拆成一條固定的契約:Codex 先寫測試,Grok 再寫實作去讓那些測試通過(只能改實作、不准動測試),Claude 獨立驗收才提交。 測試在實作之前就寫死,成為 Grok 必須滿足、且不能修改的規格。我先在一個 Zig 專案跑了兩個功能,後來又在一個 Rust + Turso 專案獨立重跑三個功能(見文末)——判斷一致:這條 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 僅供我本地對照),加一個「回合後反思」功能。另在一個 Rust + Turso 專案上以同一條 pipeline 再跑一輪,見文末「換一個 stack 再驗一次」。
- 樣本:Zig n=2 個功能(config surface、reflection module),共 15 個測試(4 + 11);Rust + Turso n=3 個功能(見文末)。兩者各自樣本都小。
- 出題命令:
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 "<功能前綴>";leak-detecting allocator 回報 0 leak。
樣本小,數字不外推;以下每個論斷都設計成能被另一個工程師在幾分鐘內驗證或反駁。
核心迴圈:測試先寫死,實作去追它
每個功能走五步,順序不可換:
- Codex 出測試 + 最小 stub。stub 讓測試「能編譯、但在斷言上失敗」——這是真正的 RED,不是因為符號缺失而編不過。測試此刻就固定下來,之後不再改。
- Claude 對照原始碼核對測試。Codex 會猜 API(vtable 欄位、函式簽章、建構模式),必須逐一驗證符號存在才落地。
- Claude 放進隔離的 git worktree,跑到確定 RED:pass/fail 混合,每個失敗各有其原因。
- Grok 寫實作到 GREEN。任務只有一句:讓這些已寫死的測試通過,只改實作、不准動測試。 測試是 Grok 不能碰的契約,不是它可以順手改綠的東西。
- 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 來源。
為什麼「獨立驗收」不是形式:三個測試沒抓到、但驗收抓到的錯
「Claude 驗收」聽起來像蓋章,但它擋下的都是綠燈下的暗傷:
- 施工者謊報成功。 有一次 Grok 回報「成功」,實際上它跑在錯的目錄、測試本來就綠,它一行沒寫。只看回報就會提交一個沒改的 commit。
- 測試全綠、但 migration 靜默跳過。 在 Rust 那輪,一段 schema migration 的 idempotent 守衛檢查「DDL 是否含
destination」就跳過——但線上 DB 早就有destination、缺的是新欄位,於是守衛誤判、整段擴充被無聲略過。測試在本地全綠;我是讀 diff、再對線上 DDL 才抓到。 - seed 檔只載入一半、無錯誤。 一個 seed 的值字面含分號,而 seed splitter 正是以分號切句——三列只進了一列,沒有任何報錯。不是測試抓到的,是我核對「實際列數」才發現。
這三個都會通過「測試全綠 + 施工者自述成功」。驗收要做的不是相信綠燈,是去證明綠燈為真。
一個要先講的安全坑:別把密鑰餵進 argv
把工作交給施工 agent 時,我一度讓 runtime 把 .env 的 DB token 直接展開進 grok -p '…' 的命令列——結果那顆 JWT 就明擺在 process list 與本地 log 裡。沒有進 git、token 可重簽,實際暴露面很小;但密鑰進 argv/log 這個「類別」本身就是硬傷。交派時要給的是「去載入憑證」的指令(source .env/讓 CLI 自己 mint),永遠不要把字面值塞進命令列。
成本與失敗場景(正面之外)
- 成本是每個角色的來回,不是一次 LLM 呼叫。 n=2 個功能我花了十幾次 agent 呼叫在「出題→核對→RED→施工→驗收」,其中 1 次失敗交接(Grok 空轉),人工驗收每個功能約幾分鐘。對小功能,這比單 agent 直接寫慢。划算場景是:功能有明確測試 oracle,且你在意正確性甚於速度。(wall-clock 未逐步計時,屬已知量測缺口。)
- 紅燈要「可診斷」。 若 stub 全部回傳
error.NotImplemented,所有測試會用同一種方式失敗——那是無資訊的 RED。每個測試必須因自己的原因失敗,施工者才知道往哪修。 - 共享 DB 要 panic-safe 清理。 若整合測試打的是共享/線上 DB,teardown 必須用 RAII 守衛掛住——否則一次 RED(斷言 panic)就會把測試列洩進正式庫。這是 live-DB 專案的額外適用條件。
換一個 stack 再驗一次
為了看它是不是只在 Zig 成立,我在一個 Rust + Turso(雲端共享 DB)專案上用同一條「Codex 出測試→Grok 實作→Claude 驗收」獨立重跑了三個功能。沒有推翻原判斷:一樣可用,前提仍是測試能當契約;差別在共享 DB 帶出的新約束(上面的 panic-safe 清理、以及讀 diff 才抓到的靜默 migration bug)。換個語言、換個測試框架,卡點依舊在 integration 與驗收,不在模型智力。 這讓我更有信心,但仍只是第二個小樣本案例,不是 benchmark。
適用與不適用
適用:有靜態型別 + 嚴格測試框架的專案、功能可切成小塊、每塊有明確斷言。測試當契約,跨 agent 交接才有意義。
不適用:探索性、規格未定、或「測試本身就是要設計的東西」的工作。這條 pipeline 假設測試是可先寫死的規格;當規格還在流動,強行分工只會把來回成本放大。
判斷
這不是新範式,是把單 agent 的一個內部步驟(自己出測試自己實作)拆成跨 agent 的外部契約。買到的是更早、更獨立的錯誤發現點——任何一環的自欺都會在下一環被抓到。代價是 orchestration 來回,和你必須真的去驗收、而不是相信回報。
對決定要不要把多 agent 導入實際 workflow 的人:先確認你的專案有「測試能當契約」的體質。沒有這個前提,多 agent 只是把一個 agent 的不可靠乘以三。
文中失敗場景(Grok grok-composer-2.5-fast 的 reasoningEffort 400、假成功回報、Zig lazy discovery 需 ` = x;`、Rust 那輪的靜默 migration 與 seed 半載入、密鑰進 argv)均為本人實測,工具版本與命令見「實驗條件」。_
Top comments (0)