環境與前置條件
- Claude Code v2.1.154 以上(claude --version 先確認)
- 付費方案(Pro / Max / Team / Enterprise)或 API / Amazon Bedrock / Google Vertex AI / Microsoft Foundry
- Pro 方案要先到 /config 把「Dynamic workflows」那一列打開
- 功能狀態:research preview(2026-05-28 隨 Claude Opus 4.8 一起發布),行為可能還會變
- 預設知識:你已經用過 Claude Code、知道 subagent 跟 slash command 大概是什麼
我第一次認真用 /deep-research 是想查一個 Node.js 權限模型的版本差異。我按下 Enter,然後——畫面沒有一行一行慢慢吐字,而是冒出一個背景任務面板,裡面有十幾個 agent 各自跑去搜不同角度、互相打架、把站不住腳的論點砍掉,最後丟回一份標好引用的報告。我那條對話從頭到尾還是空的、隨時能繼續打字。
那一刻我才意識到,Claude Code 的玩法被改寫了。過去 subagent 是「Claude 一輪一輪決定要派誰」,現在 Dynamic Workflows(動態工作流程) 把整個編排計畫搬進一段 JavaScript 腳本,由一個獨立 runtime 在背景跑,規模直接拉到單次最多 1,000 個 subagent。這次更新(細節見 The New Stack 的報導 )給我的整體感覺就一句話:過去那種「一次小心翼翼的單一 pass」,不再是預設玩法了。
這篇文章我會把它從頭講到尾——它到底是什麼、怎麼觸發、腳本長怎樣、pipeline 跟 parallel 到底差在哪(這裡超多人寫錯),還有那些一不小心就會燒掉一堆 token 的雷。

Workflow 到底是什麼?跟 subagent、skill 差在哪
先把名詞釐清,不然後面會一直打結。Claude Code 裡能跑「多步驟任務」的東西其實有三種:subagent、skill、workflow。它們最核心的差別,官方文件 講得很精準——差在「誰持有那個計畫(who holds the plan)」。
|
Subagents |
Skills |
Workflows |
| 本質 |
Claude 生出來的 worker |
Claude 遵循的一組指示 |
runtime 執行的腳本 |
| 誰決定下一步 |
Claude,一輪一輪 |
Claude,照著 prompt |
腳本本身 |
| 中間結果放哪 |
Claude 的 context |
Claude 的 context |
腳本變數 |
| 可重複的是什麼 |
worker 定義 |
那組指示 |
編排邏輯本身 |
| 規模 |
每輪幾個 |
同 subagent |
每次 run 數十到數百個 agent |
| 中斷怎麼辦 |
重跑那一輪 |
重跑那一輪 |
同 session 內可 resume |
用 subagent 跟 skill 的時候,Claude 自己是那個指揮官:它一輪一輪決定接下來生什麼,而且每個結果都會掉回它的 context 裡。問題是 context 是有限的,當你要掃 300 個檔案、每個都吐一份報告回來,Claude 的腦袋很快就塞爆了,夭壽。
Workflow 的解法是把那個指揮計畫——迴圈、分支、中間結果——全部寫進程式碼。腳本自己持有狀態,Claude 的 context 最後只拿到一份濃縮過的答案。這不只是「能跑更多 agent」而已,它還讓你能套用可重複的品質模式:讓幾個獨立 agent 互相對抗審查彼此的發現、或從好幾個角度各自起草一份方案再拿來比,最後得到的結果比單次 pass 可信得多。
一句話記法,幫你以後不會選錯工具:
一兩個獨立調查 → 用 subagent
know-how 要重用 → 用 skill
編排本身要重複 → 用 workflow(fan out、比較發現、重啟失敗的 agent、存起來當命令)
到底有多大規模?開發者社群流傳過一個會嚇到的個案:有人用動態工作流程把 Bun 從 Zig 移植到 Rust,據說原測試套件 99.8% 通過、約 75 萬行 Rust、十一天就 merge。這類數字我沒辦法逐一查證、純粹當茶餘飯後看,但那個量級感受得到。比較踏實、官方自己列出來的標準場景是:全庫 bug sweep、500 個檔案的大遷移、需要跨來源交叉驗證的研究、以及「值得從好幾個角度各自起草再擇一」的困難計畫。
三種觸發方式:關鍵字、deep-research、ultracode
要讓 Claude 幫你寫並跑一個 workflow,總共三條路。
第一條:prompt 裡丟 workflow 這個字。 最直接,單次觸發、不改 session 的設定。
Run a workflow to audit every API endpoint under src/routes/ for missing auth checks
Claude Code 會把那個字反白,然後改成「幫你寫一段 workflow 腳本」而不是一輪一輪手動做。如果你只是剛好打到 workflow 這個字、根本沒想觸發,按 alt+w 就能忽略這一輪。
第二條:內建的 /deep-research。 這是目前唯一的 bundled workflow,也是最好的入門體驗:
/deep-research What changed in the Node.js permission model between v20 and v22?
它會對問題從好幾個角度 fan out 網路搜尋、抓回來源互相 cross-check、對每個論點投票,最後給你一份引用完整、而且已經把站不住腳的論點濾掉的報告。
第三條:ultracode 模式。 這是把油門踩到底的玩法:
/effort ultracode
Ultracode = xhigh 推理強度 + 自動 workflow 編排。開了之後,Claude 每個實質任務都會自己判斷要不要編成 workflow,一個請求甚至會拆成好幾個連續的 workflow(一個負責理解程式碼、一個負責改、一個負責驗證)。代價就是每個任務都更燒 token、更慢,而且只在當前 session 有效,回到例行工作記得用 /effort high 降回來,不然帳單會讓你傻眼。
順帶一提,啟動時會不會跳權限確認,取決於你的 permission mode:Default / acceptEdits 每次都問(除非你選過「不再詢問這個 workflow」);Auto 只問第一次;Bypass、claude -p、Agent SDK 則直接開跑不問。有個細節很重要——workflow 生出來的 subagent 一律以 acceptEdits 模式跑、檔案編輯自動核准,但不在你 allowlist 裡的 shell / web / MCP 工具還是會在執行中跳提示。所以長 run 之前,先把 agent 會用到的指令加進 allowlist,不然跑到一半被一個權限框卡住,超雷。
腳本長怎樣:meta 加五個 API(順便校正坊間的簽名錯誤)
這一段是整篇的重點。我看過好幾篇教學把 API 簽名寫錯,照著抄一定跑不起來,所以這裡用 Claude Code 實際工具規格來校正。
先講清楚:官方那份 workflows 文件 主要描述「使用者怎麼操作」(觸發、權限、resume、成本),腳本層的 API 細節(agent / parallel / pipeline / budget / 程式化 resume 等)目前較少公開。下面這些簽名取自 Claude Code 的 workflow 執行環境(也就是 Claude 寫腳本時實際看到的規格),會隨版本演進——照抄前請以你自己 Claude Code 版本的實際行為為準。
每個 workflow 腳本必須以 export const meta = {...} 開頭,而且 meta 必須是純字面量——不能用變數、函式呼叫、展開運算子或樣板字串插值,runtime 會在你還沒跑之前就要讀它:
export const meta = {
name: 'review-changes', // 必填
description: 'Review changed files and verify findings', // 必填,權限對話會顯示這句
whenToUse: 'after a large diff', // 選填,列在 workflow 清單裡
phases: [ // 選填但建議,每個 phase() 對應一筆
{ title: 'Review' },
{ title: 'Verify' },
],
}
// 腳本本體從這裡開始,是 async context,可以直接 await
phase('Review')
const result = await agent('review src/auth.ts for bugs', { schema: FINDINGS_SCHEMA })
接著是五個核心 API,請務必看清楚參數型別:
| API |
簽名 |
重點 |
agent |
agent(prompt, opts?) |
啟一個 subagent。沒給 schema 回傳純文字字串;給了 schema 回傳驗證過的物件。opts 有 label、phase、schema、model、isolation:'worktree'、agentType。使用者中途略過會回傳 null。 |
pipeline |
pipeline(items, stage1, stage2, ...) |
每個 item 獨立流過所有 stage,stage 之間沒有 barrier。stage callback 收到 (prevResult, originalItem, index)。某個 item 在某 stage 拋錯就變 null、跳過後續。 |
parallel |
parallel(thunks) |
thunks 是函式陣列 Array<() => Promise<any>>,不是直接傳 agent。這是個 barrier,等全部完成才回傳。某個 thunk 拋錯那一格變 null(呼叫本身不會 reject),用之前先 .filter(Boolean)。 |
phase |
phase(title) |
開一個新階段,之後的 agent() 在進度面板會歸到這個標題下。 |
log |
log(message) |
對使用者吐一行進度訊息。 |
最容易寫錯的就是 parallel。 我看過不少文章寫成 parallel(agent(...), agent(...)),直接把 agent 的回傳值丟進去——這樣等於在呼叫 parallel 之前就已經把 agent 啟動了,整個並行的意義就沒了。正確寫法是傳還沒被呼叫的函式(thunk):
// ❌ 錯:直接傳 agent 的結果(簽名也錯)
const r = await parallel(agent('check a'), agent('check b'))
// ✅ 對:傳一個函式陣列,每個函式回傳一個 Promise
const r = await parallel([
() => agent('check a'),
() => agent('check b'),
])
const usable = r.filter(Boolean) // 拋錯的會是 null,先濾掉
還有一個我大力推薦的東西:schema 結構化輸出。給 agent() 傳一個 JSON Schema,subagent 會被強制呼叫 StructuredOutput 工具回傳已驗證的物件,不符合還會自動重試。從此不用自己解析一坨文字、不用祈禱它格式對:
const FINDINGS = {
type: 'object',
properties: {
findings: {
type: 'array',
items: {
type: 'object',
properties: {
title: { type: 'string' },
file: { type: 'string' },
severity: { type: 'string' },
},
required: ['title', 'file'],
},
},
},
required: ['findings'],
}
const r = await agent('find bugs in src/auth.ts', { schema: FINDINGS })
// r.findings 直接是陣列,拿了就用
最後幾個會踩到的環境限制,先講免得你撞牆:
- 腳本是純 JavaScript,不是 TypeScript。型別註記
: string[]、interface、generics 一律解析失敗。
Date.now()、Math.random()、無參數的 new Date() 會直接丟錯(因為它們會破壞 resume 機制)。要時間戳就從 args 傳進去,要亂數就靠 index 去變化 prompt。
- 腳本本身沒有檔案系統跟 shell 存取權。讀檔、寫檔、跑指令都是 agent 在做,腳本只負責調度。

pipeline 還是 parallel?這是最常踩的雷
這題我特別拉一段出來講,因為選錯的代價是白白浪費牆鐘時間。
原則一句話:預設用 pipeline,只有當「下一階段真的需要上一階段的全部結果」時才用 parallel 的 barrier。
pipeline 沒有 barrier。item A 可以已經在第三 stage,同時 item B 還卡在第一 stage。整段的牆鐘時間 = 最慢的那一條單一 item 的鏈,而不是「每個階段最慢的那個」加總。這個差異在 agent 速度落差大的時候非常明顯:
const DIMENSIONS = [
{ key: 'bugs', prompt: 'review for correctness bugs' },
{ key: 'perf', prompt: 'review for performance issues' },
]
const results = await pipeline(
DIMENSIONS,
// stage 1:審查
d => agent(d.prompt, { label: `review:${d.key}`, phase: 'Review', schema: FINDINGS }),
// stage 2:每個發現派人對抗驗證(不用等別的維度審完)
review => parallel(
review.findings.map(f => () =>
agent(`Adversarially verify: ${f.title}`, { phase: 'Verify', schema: VERDICT })
.then(v => ({ ...f, verdict: v }))
)
),
)
// 'bugs' 的發現在驗證的同時,'perf' 還在審——牆鐘時間不浪費
那什麼時候才真的該用 parallel 的 barrier?只有這幾種:下一階段要拿到全集合才能動——例如在昂貴的下游工作前先去重 / 合併全部結果、或是要提早退出(「0 個 bug 就整段跳過驗證」)、或是下一階段的 prompt 要「跟其他所有發現比較」。
// barrier 真正合理的場景:去重後才驗證
const all = await parallel(DIMENSIONS.map(d => () => agent(d.prompt, { schema: FINDINGS })))
const deduped = dedupe(all.filter(Boolean).flatMap(r => r.findings)) // 真的需要全集合
const verified = await parallel(deduped.map(f => () => agent(verifyPrompt(f), { schema: VERDICT })))
有個嗅探測試很好用:如果你寫出來的是「parallel → 一段純資料轉換(flatten / map / filter,沒有跨 item 依賴)→ parallel」,那中間那個 barrier 根本不需要,把轉換塞進 pipeline 的 stage 裡就好。猶豫的時候,選 pipeline 準沒錯。
進階品質模式:讓 agent 互相打臉
Workflow 真正比「叫一個 agent 做事」強的地方,是它能套用結構化的品質模式。這也是 Anthropic 官方部落格 一直強調的賣點。
對抗驗證(Adversarial Verify) 是其中最實用的。發現一個問題後,不是直接信它,而是派 N 個獨立的懷疑者、prompt 明確要他們反駁,多數反駁就否決。據 MarkTechPost 的報導 ,這個「其他 agent 專門去反駁前面發現」的機制是內建在 run 裡的,只有撐過反駁的論點才會送到你面前。舉個我自己常遇到的情境:當一個 subagent 宣稱某函式有 race condition,你就讓另一個 subagent 的唯一任務是想辦法推翻它——推不翻,這個 bug 才算數。
const votes = await parallel(
Array.from({ length: 3 }, () => () =>
agent(`Try to refute this claim: ${claim}. Default to refuted=true if uncertain.`,
{ schema: VERDICT }))
)
const survives = votes.filter(Boolean).filter(v => !v.refuted).length >= 2

Judge panel(法官小組) 適合解空間很寬的問題:從不同角度(MVP 優先、風險優先、使用者優先)各生一份獨立方案,並行 judge 評分,最後從贏家綜合、再把亞軍的好點子嫁接進來。比「單一方案反覆迭代」常常好得多。
Loop-until-dry(跑到枯竭) 用在未知規模的發現任務(bug、edge case):持續派 finder 直到連續 K 輪沒有新東西。這裡有個經典的坑——去重要對著 seen 集合,不是對著 confirmed,否則被否決掉的發現每一輪都會重新冒出來,永遠收斂不了:
const seen = new Set(), confirmed = []
let dry = 0
while (dry < 2) { // 連續兩輪沒新東西才停
const found = (await parallel(FINDERS.map(f => () =>
agent(f.prompt, { phase: 'Find', schema: BUGS })))).filter(Boolean).flatMap(r => r.bugs)
const fresh = found.filter(b => !seen.has(key(b)))
if (!fresh.length) { dry++; continue }
dry = 0
fresh.forEach(b => seen.add(key(b))) // 對 seen 去重,不是 confirmed
// ……對 fresh 做多 lens 評審後,把通過的 push 進 confirmed
}
還有 multi-modal sweep(多個 agent 各用不同方式搜:by-container、by-content、by-entity、by-time,補單一角度的盲區)跟 completeness critic(最後派一個 agent 專門問「漏了什麼?哪個模態沒跑、哪個論點沒驗證」)。這些模式可以自由組合,不是互斥的。
並發、budget、resume:跑大 run 之前要懂的事
規模拉大之後,有三件事一定要搞清楚,不然不是燒錢就是白做。
並發上限。 官方文件講的是「最多 16 個並行 agent,CPU 核心少的機器會更少」(確切公式官方沒講明,大致隨可用核心數遞減),超過的會排隊等空位。單次 run 的總量上限是 1,000 個 agent——這是防失控迴圈的後盾,遠高於正常用量。你還是可以丟 100 個 item 給 parallel / pipeline,它們全部都會完成,只是同一時間大概只有十個左右在跑。
Token budget。 一次 workflow run 可能比用對話做同一件事燒多很多 token,而且照樣計入你方案的用量跟速率限制。每個 agent 預設用你 session 的模型,除非腳本用 opts.model 把某個 stage 導去別的模型。所以大 run 之前先 /model 確認一下、把不需要最強腦的 stage 換成小模型。腳本裡還有個 budget 物件可以拿來動態縮放深度:
const bugs = []
while (budget.total && budget.remaining() > 50_000) {
const r = await agent('Find bugs in this codebase.', { schema: BUGS })
bugs.push(...r.bugs)
log(`${bugs.length} found, ${Math.round(budget.remaining() / 1000)}k remaining`)
}
注意那個 budget.total && 的 guard 不能省——沒設預算時 remaining() 會回 Infinity,這個迴圈會一路跑到 1,000 agent 上限才停,爆肝燒錢就是這樣來的。
Resume(暫停與恢復)。 在 /workflows 裡選中一個 run 按 p 就能暫停 / 恢復,已完成的 agent 會回傳快取結果、其餘的繼續跑。據 digitalapplied 的整理 ,workflow 可以從先前的 runId 恢復,所以你改了腳本之後,沒被動到的 agent 不會重跑——最長未變動的呼叫前綴會秒回快取,從第一個被改或新增的呼叫起才實跑。對應的程式化重跑形式(帶 scriptPath 與 resumeFromRunId)屬於前面提過的腳本層 API,官方公開文件還沒完整載明,以你的版本實際行為為準。
但有一個硬限制要記住:resume 只在同一個 Claude Code session 內有效。你只要退出 Claude Code,下次啟動時 workflow 就從頭來過。所以多日的大工程,盡量別關。

最佳實踐與踩坑清單
把前面散落的雷集中起來,這張表存著,下次寫 workflow 前掃一遍:
| 你做的事 |
後果 |
正確做法 |
parallel(agent(), agent()) |
簽名錯、根本沒並行 |
parallel 收函式陣列 [() => agent(...)] |
| 動不動就用 barrier |
快的 agent 空等慢的,浪費牆鐘 |
預設 pipeline,barrier 要有正當理由 |
loop 去重對 confirmed |
被否決的發現每輪重現,永不收斂 |
對 seen 去重 |
budget 迴圈沒 guard budget.total |
沒設預算時 Infinity,跑到 1,000 上限 |
while (budget.total && remaining() > X) |
腳本裡用 Date.now() / Math.random() |
直接丟錯、破壞 resume |
時間從 args 傳、亂數靠 index |
| 期待 subagent 自己整合彼此的工作 |
重複跟衝突一堆 |
整合交給最後的綜合階段或你自己 |
| 退出 session 後想 resume |
從頭跑、白燒一輪 |
resume 僅限同 session;或用 scriptPath + resumeFromRunId |
| 沒設明確終止條件的迴圈 |
逼近 1,000 agent 上限 |
設品質閾值或 dry-count 退出 |
幾個正面的習慣也一起列:任務邊界要講清楚(「audit src/routes/ 每個 endpoint 缺漏的 auth check,附 severity」遠勝於「improve the codebase」);用 schema 拿結構化輸出免解析;subagent 任務要可獨立驗證、輸入輸出明確、只碰有界的檔案集;規模化之前先小跑(/deep-research 或先掃 5~10 個檔)確認成本;成功的 run 記得在 /workflows 裡按 s 存成 /<name> 命令重複用——專案級存 .claude/workflows/(可進 git、整隊共用),個人級存 ~/.claude/workflows/。
至於底層模型,這次 Claude Opus 4.8 的數字 也撐得起這套玩法——據報導 SWE-bench Pro 拿到 69.2%、長上下文檢索(GraphWalks long-context F1,1M tokens)達 68.1%,誠實度也明顯提升(官方主打未回報的程式碼瑕疵大幅減少)。對於要派上百個 agent 互相審查的場景來說,底層模型誠不誠實、看不看得懂長 context,直接決定了最後那份報告能不能信。
什麼時候該用、什麼時候別用
最後給個明確的判斷,免得你拿大砲打蚊子。
該用 workflow 的場景:全庫 bug sweep 或安全審計(100+ 檔)、大規模遷移(500+ 檔)、需要多來源交叉驗證的研究、值得從多角度起草再擇一的困難計畫。據 explainx.ai 的整理 ,這類「過去要一季、現在幾天」的大工程正是它的主場。
別用的場景:單檔編輯、快速 bug 修復、簡單問答——這些用對話或一兩個 subagent 就好,動 workflow 純粹是浪費 token。know-how 想重用就寫成 skill。token 預算緊張的時候也先忍著。
說穿了,動態工作流程不是要取代你跟 Claude 的對話,而是給你一個「當任務大到一個 context 裝不下」時的逃生艙。先從 /deep-research 玩起,習慣那個背景任務面板的節奏,再試著在 prompt 裡丟一個 workflow 讓 Claude 幫你寫第一支腳本。跑順了、覺得這流程每條 branch 都會重複,就按 s 存起來——下次它就是你自己的 / 命令了。
要不要現在就開一個小的試?挑你手邊一個「想掃但一直懶得掃」的資料夾,丟一句 Run a workflow to ...,看看十幾個 agent 同時上工是什麼感覺。跑完不妨在留言區分享你燒了多少 token、值不值得。
參考資料