AI 工程

Claude 自己寫 harness:Dynamic Workflows 怎麼調度上百個 agent,以及你明天就能用的設定

你一定遇過這種狀況:叫 Claude Code 審 50 個 API route 有沒有漏掉權限檢查,它認真做了 30 幾個,然後很有自信地說「全部檢查完畢」。或者請它自己驗證剛剛找到的 bug,它幾乎每一條都判定「確認是真的」。

這不是模型笨,是單一 context window 的結構性問題。Anthropic 在 5 月底替 Claude Code 推出 dynamic workflows(動態工作流),10 月又把同一套概念搬到 Claude Managed Agents 的伺服器端。10 月 12 日 Latent Space 刊出 Richard MacManus 的報導,整理 Anthropic 技術人員 CJ Avilla 與 Harrison Stall 在 AI Engineer New York 2026 工作坊上的分享,Stall 直接把它稱為「下一個版本的 multi-agent orchestration」。

這篇不談趨勢,只講三件事:它的機制到底是什麼、官方文件寫明的限制有哪些、你明天上班怎麼把它用起來。

一、問題:為什麼一個 agent 做大任務會翻車

Claude Code 團隊的 Thariq Shihipar 與 Sid Bidasaria 在官方部落格〈A harness for every task〉裡,把單一 agent 在長任務上的失敗歸成三類:

  1. Agentic laziness(偷懶收工):做到一部分就停。文中的例子是 50 項的安全審查只做了 35 項。
  2. Self-preferential bias(偏袒自己):讓同一個 agent 驗證自己的發現,它傾向覺得自己是對的。
  3. Goal drift(目標漂移):對話一長、context 被壓縮,原始需求裡那些「不要做 X」的邊界條件最先被丟掉。

三個問題的共同根源是:計畫、執行、驗證、中間結果全擠在同一個 context window 裡。傳統解法是你自己用 Agent SDK 或 claude -p 寫一個固定的 harness,但固定 harness 要處理所有邊界情況,結果就是很泛用、很平庸。

Dynamic workflows 的解法是:讓 Claude 針對這一次的任務,現場寫一個專屬 harness。

二、它是什麼:把「計畫」從對話搬進程式碼

官方文件(code.claude.com/docs/en/workflows)的定義很直白:dynamic workflow 是一支 JavaScript script,由 Claude 根據你描述的任務撰寫,交給 runtime 在背景執行,script 再去調度大量 subagent。

跟你已經熟悉的幾種做法比,文件給了一個很好用的判準:誰握著計畫。

Claude Code 三種多 agent 做法比較:Subagents、Agent Teams、Workflows 差在誰握著計畫

  • Subagents:Claude 逐回合決定要派誰,每個結果都回到主對話的 context。
  • Agent teams:一個 lead agent 管理幾個長駐的同伴 session,靠共享任務清單協調。
  • Workflows:迴圈、分支、中間結果都在 script 裡,Claude 的 context 只收最終答案。

這個差別看似技術細節,實際影響很大。當中間結果存在 script 變數而不是 context 裡,100 個 agent 的輸出不會把主對話塞爆;當流程寫成程式碼,它就能被重跑、被存檔、被分享。

三、運作原理:一次 run 是怎麼跑完的

Dynamic Workflows 運作流程:主 agent 寫 script、runtime 分 phase 調度 agent、只回傳驗證過的結論

1. 主 agent 寫 script,你核准

你下 prompt 之後,Claude 不再逐回合做事,而是先寫一支 workflow script。CLI 會跳出確認框,列出規劃好的 phase,選項有「Yes, run it」、「View raw script」(先看原始碼)和「No」,按 Ctrl+G 可以直接用編輯器打開 script。

2. Runtime 在背景執行

Script 的長相大概是這樣(以官方文件範例為基礎、加上驗證階段改寫的示意版):

export const meta = {
  name: 'auth-audit',
  description: 'Audit route handlers for missing auth checks, verify each finding',
  phases: [{ title: 'Discover' }, { title: 'Audit' }, { title: 'Verify' }],
}

phase('Discover')
const found = await agent('List every .ts file under src/routes/. Return paths only.', {
  model: 'haiku',
  schema: { type: 'object', required: ['files'],
    properties: { files: { type: 'array', items: { type: 'string' } } } },
})

phase('Audit')
const FINDINGS = { type: 'object', required: ['findings'], properties: {
  findings: { type: 'array', items: { type: 'object', required: ['line', 'issue'],
    properties: { line: { type: 'integer' }, issue: { type: 'string' } } } } } }

const audits = await pipeline(found.files, file =>
  agent(`Audit ${file} for routes missing authentication checks. Report only concrete issues with line numbers.`,
    { label: file, schema: FINDINGS }))

phase('Verify')
const candidates = audits.flatMap((a, i) =>
  a ? a.findings.map(f => ({ file: found.files[i], ...f })) : [])

const verdicts = await parallel(candidates.map(c => () =>
  agent(`Try to REFUTE this finding: ${c.file}:${c.line} ${c.issue}. Check middleware and router-level guards. isReal=false if auth is enforced elsewhere.`,
    { label: `verify:${c.file}:${c.line}`,
      schema: { type: 'object', required: ['isReal', 'reason'],
        properties: { isReal: { type: 'boolean' }, reason: { type: 'string' } } } })))

return candidates.filter((c, i) => verdicts[i]?.isReal)

幾個你要認得的原語:

  • agent(prompt, opts):開一個 subagent。schema 讓它回傳驗證過的 JSON;model 可指定 opus / sonnet / haiku;isolation: 'worktree' 讓它在獨立的 git worktree 裡改檔,平行改檔不打架。
  • pipeline(items, fn):清單裡每個項目跑一次,沒有柵欄,A 檔案可以已經在下一階段,B 還在前一階段。
  • parallel(tasks):一組任務同時跑,等全部完成才往下,適合當彙整前的柵欄。
  • phase(title):把後面的 agent 歸到同一組,在進度畫面上顯示。
  • args:存成指令後可以從外部傳參數進來。

3. Runtime 的幾條硬規則

文件明列的約束,理解了就知道為什麼它可靠:

  • Script 自己不碰檔案系統和 shell。讀寫檔、跑指令都是 agent 的事,script 只負責調度。也不能 import() 任何模組。
  • Date.now()、Math.random()、無參數的 new Date() 會直接拋錯。這是為了「可重播」:重跑時同樣的 agent() 呼叫順序必須一致,已完成的 agent 才能直接回傳快取結果。需要時間戳就從 args 傳進去。
  • Schema 驗證失敗會重試,最多 5 次,仍失敗就報錯(可用 MAX_STRUCTURED_OUTPUT_RETRIES 調整)。
  • agent 被停掉或遇到無法恢復的 API 錯誤時回傳 null,所以範例最後要 .filter(Boolean) 或像上面那樣判斷 a ? ... : []。

4. 中斷與續跑

這是 workflows 跟一般 subagent 最大的實務差異。Runtime 追蹤每個 agent 的結果,你在 /workflows 裡按 p 暫停再恢復即可;停掉的 run 可以請 Claude 用同一支 script 重新啟動。重播規則要搞懂,不然會白燒 token:

  • 已完成的 agent 直接回傳存檔結果。
  • 但第一個 prompt 跟上次不同的 agent,以及它之後啟動的所有 agent,都會重跑。
  • 失敗的 agent 會重跑,它之後啟動的也全部重跑。文件的例子:依序啟動 A、B、C、D,B 失敗,重啟時只有 A 走快取,B、C、D 全部重來。

結論:把便宜、穩定的步驟排在前面,容易失敗的步驟放後面,續跑時損失最小。

四、數據與限制:官方寫了什麼、沒寫什麼

Claude Code 端(官方文件)

項目 數值
預設同時執行的 agent 16(CPU 少時更低),可用 CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS 設 1–256,需 v2.1.269+
單一 parallel() / pipeline() 項目數 4,096,超過直接報錯
每次 run 的 agent 總數 1,000
Large workflow 警告門檻 排程超過 25 個 agent,或預估超過 150 萬 token(只是提醒,不會擋)
規模建議 workflowSizeGuideline small 少於 5、medium 少於 10、large 少於 50;預設 medium,Pro 方案預設 small

另外有個省錢細節:同一個 run 裡模型、工具、schema、工作目錄都相同的 agent 會共用 prompt cache 前綴。Runtime 會先放第一個 agent 出去,其他的最多等 5 秒(CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS)再一起放行,讓它們讀到快取。

Managed Agents 端(官方 API 文件,beta)

項目 數值
單一 run 同時工作的 thread 64(文件註明不保證,可能變動)
單一 run 一生啟動的 agent 1,000,超過以 thread_limit_error 結束
Run 壽命 預設 24 小時
單一 session 同時開著的 run 預設 10

案例數字,要看清前提

官方發表文提到 Bun 作者 Jarred Sumner 用 workflows 把 Bun 從 Zig 移植到 Rust:約 75 萬行 Rust、既有測試通過 99.8%、從第一個 commit 到合併 11 天。做法是一個 workflow 先替每個 struct 欄位標出 Rust lifetime,另一個逐檔對照 .zig 移植 .rs,每個檔案配兩個 reviewer,再跑修正迴圈直到 build 和測試通過。但同一篇文章也寫明這份成果還沒上 production。這是一個極端理想的場景:有完整測試套件當裁判、有一對一的檔案對應。你的專案若測試覆蓋率不高,別期待同樣效果。

成本方面,官方只說「可能比一般 session 多用很多 token」,沒有給倍數。Latent Space 報導裡 Avilla 的說法是 flows「貴很多」,但「找細節的能力也強很多」。官方部落格的面板示意圖顯示一個 14 個 agent 的 review 用了約 48 萬 token、22 個 agent 的 deep research 用了約 110 萬 token,這是示意截圖,不是基準測試,拿來抓量級就好。

五、什麼時候該用、什麼時候別用

該用的訊號:

  • 同一個動作要套到幾十、幾百個項目(檔案、endpoint、元件、issue)。
  • 結果需要獨立驗證,你不信任「自己審自己」。
  • 任務大到一個 context 撐不住,或你需要中途可以斷、可以續。
  • 這個流程你會重複做,想存成團隊共用的指令。

別用的訊號:

  • 改一個 bug、加一個欄位。官方原話是「多數日常 coding 任務不需要五個 reviewer 的評審團」。
  • 中途需要你拍板。Workflow 跑起來不接受使用者輸入(只會為權限提示或用量上限暫停),需要人工簽核就拆成多個 workflow 分段跑。
  • 測試或驗證條件模糊。沒有裁判,adversarial verification 只是多花錢吵架。

官方部落格列了六種可組合的模式,寫 prompt 時直接點名效果最好:classify-and-act(先分類再路由)、fan-out-and-synthesize(拆開平行做再彙整)、adversarial verification(另一個 agent 拿 rubric 反駁)、generate-and-filter(大量產生再篩)、tournament(多個 agent 用不同方法做同一件事,兩兩對決選贏家)、loop until done(一直派 agent 直到沒有新發現)。

六、明天就能照做的設定與 prompt

Step 1:確認開啟

Max、Team、Enterprise 與 API 用戶預設開啟;Pro 用戶到 /config 打開 Dynamic workflows。官方建議搭配 auto 權限模式。想先感受一下,直接跑內建的:

/deep-research What changed in the Node.js permission model between v20 and v22?

接著輸入 /workflows 看進度。常用鍵:Enter 鑽進 phase 和 agent、f 依狀態篩選、p 暫停、x 停掉、r 重啟卡住的 agent、s 存成指令。

Step 2:用關鍵字觸發單次 workflow

在 prompt 裡加 ultracode,或直接說「use a workflow」:

ultracode: audit every API endpoint under src/routes/ for missing auth checks

注意:關鍵字只在你親手輸入時生效。從 -p、排程任務、webhook 或 PR 留言轉進來的文字不會觸發(v2.1.210 之前會,記得升級)。

想讓整個 session 都由 Claude 自己判斷要不要開 workflow,用 /effort ultracode。但它會讓每個請求都更貴,日常工作記得 /effort ultracode off。

Step 3:把 prompt 寫成 workflow 規格

好的 workflow prompt 要講清楚四件事:怎麼拆、怎麼驗、何時停、失敗怎麼辦。官方文件的範例 prompt 都有這個結構:

use a workflow to run npx tsc --noEmit and keep fixing the reported errors
until the type check passes or two rounds in a row make no progress
use a workflow to migrate every component under src/components/ from JavaScript
to TypeScript, working on each file in its own isolated copy

自己寫時可以套這個模板:

use a workflow to <任務>.
- 拆法:每個 <檔案/模組/endpoint> 一個 agent
- 驗證:每個發現交給另一個 agent 嘗試反駁,只回報反駁失敗的
- 停止條件:<測試通過 / 連續兩輪沒有新發現 / 最多 N 輪>
- 失敗處理:單一 agent 失敗不中止整個 run,列為「未涵蓋」
- 資源:每個 agent 避免跑全量測試,只跑相關的測試檔
- 模型:探索和列清單用 haiku,判斷和修改用預設模型

最後那兩條是控制成本的關鍵。官方部落格特別提醒,平行修改時要叫 agent 避免吃資源的指令,不然機器先撐不住。

Step 4:先小範圍試跑,再放大

文件建議先在一個目錄、一個窄問題上試跑,看 /workflows 裡每個 agent 的 token 用量再決定要不要放大。團隊可以在 .claude/settings.json 先把規模壓低:

{
  "workflowSizeGuideline": "small"
}

這是給 Claude 的建議值不是硬上限,prompt 明確要求更大規模時仍會覆蓋。真的要全面關閉,設 "disableWorkflows": true 或環境變數 CLAUDE_CODE_DISABLE_WORKFLOWS=1。

Step 5:跑對了就存起來

在 /workflows 選中那次 run,按 s:

  • 存到 .claude/workflows/:跟著 repo 走,整個團隊都能 /<name> 呼叫。
  • 存到 ~/.claude/workflows/:只有你自己、所有專案都能用。

要改存好的 script,先跑 /workflow-authoring 載入撰寫參考(需 v2.1.248+),改完用 /reload-skills 重新讀取。要跨 repo 分享就包進 plugin 的 workflows/ 目錄,會以 /<plugin>:<name> 的形式出現。

Step 6(進階):在 Managed Agents 上用

如果你是用 API 跑 agent,在建立 agent 時把 multiagent.type 設為 multiagent_20261001 並啟用 workflows(這個類型預設就開著),beta header 是 managed-agents-2026-04-01:

{
  "name": "Contract Reviewer",
  "model": "claude-opus-5-5",
  "system": "You review contracts. When you're asked to review more than a few contracts, start a workflow run that reads them in parallel and combines the findings. Review one or two contracts yourself, without a run.",
  "tools": [{ "type": "agent_toolset_20260401" }],
  "multiagent": { "type": "multiagent_20261001", "workflows": { "type": "enabled" } }
}

重點在 system prompt:明確寫出什麼規模才開 run、什麼小事自己做。文件還建議補上拆法(「一份合約一個 agent,再讓第二個 agent 審每一份,不只審有發現的」)、失敗處理(「一個 agent 失敗不能讓整個 run 失敗」)和時限(「給這個 run 一小時」)。

兩個實作上容易踩的坑:一是 run 結果是 completed 不代表工作都成功,失敗的 thread 要自己去讀事件;二是同一份工作可能被建立不只一個 thread,你的工具必須能安全地被呼叫兩次(冪等)。Latent Space 報導也提到,模型執行時不知道自己的預算,Stall 說告訴模型預算會讓它「有點焦慮」,所以預算要在 session 層設定。

七、對工程團隊的意義

把這件事濃縮成一句話:multi-agent 的設計權從工程師手上,部分移交給了模型,但驗證標準仍然是你的責任。

具體可以做的事:

  1. 盤點團隊的「批次型苦工」:全 repo 的 lint 規則遷移、API deprecation、權限稽核、flaky test 追查。這些是 workflows 投報率最高的地方。
  2. 先投資裁判:workflow 的品質上限取決於「怎麼判斷做對了」。測試、型別檢查、rubric 寫得越清楚,adversarial verification 越有用。Bun 的案例能成功,99.8% 的測試通過率本身就是裁判。
  3. 把好用的 run 存進 .claude/workflows/ 進版控:讓流程變成團隊資產,而不是某個人的對話紀錄。
  4. 留意人工審查瓶頸:Avilla 在工作坊上提到,人類審查大量 agent PR 會變成瓶頸甚至斷點。產出變快之前,先想好怎麼審。

值得實測的點是:同一個稽核任務,單一 agent、手寫 subagent、workflow 三種做法的漏報率和 token 成本差多少。官方沒有給這組對照數據,你團隊自己的數字會比任何報導都有參考價值。

來源

整理:DataAgent · Coding Agent 實戰教學

文章裡這些把關做法,要在一個團隊裡真的落地、而不是只有你一個人在用,通常卡在流程與共識。我把這部分整理成企業內訓:
coding agent 導入與治理 — 企業內訓與顧問 →

發表迴響

%d 位部落客按了讚: