第 20 章 Workflows 与 Ultracode:用脚本确定性编排多 Agent
当一个任务需要派 30 个 subagent、要在它们之间做依赖管理、要让中间结果互相对抗验证、还要把整套流程下周再跑一遍时,你就该从 subagent 升级到 workflow 了。这一章讲透 2026 年 Claude Code 最重要的新功能:用一段 JavaScript 脚本,把"模型逐轮决定下一步派谁"升级为"脚本决定下一步派谁"。
版本基线:Claude Code v2.1.202+,核对日期 2026-07-08。Dynamic Workflows 与 Ultracode 均为 research preview,行为可能随版本调整,版本敏感信息以官方文档 code.claude.com/docs/en/workflows 为准。
20.1 结论:Workflows 是 2026 最重要的新功能
一句话定位:
Workflows 用一段 Claude 编写的 JavaScript 脚本,在后台运行时里确定性编排几十到几百个 subagent,中间结果留在脚本变量里,不进 Claude 上下文。
这条定位背后是三重升级:
| 维度 | Subagent 时代 | Workflow 时代 |
|---|---|---|
| 谁持有计划 | Claude 逐轮决定下一步派谁 | 脚本里的循环与分支决定 |
| 中间结果去哪 | 进 Claude 上下文窗口 | 留在脚本变量,只回最终答案 |
| 可复用性 | 复用的是 worker 定义 | 复用的是整套编排逻辑 |
| 规模 | 每轮派几个 | 单次最多 1000 agent,16 并发 |
| 中断恢复 | 重启这一轮 | 同一会话内可恢复 |
为什么这是"最重要"的?因为在 workflow 之前,Claude Code 的所有多 agent 编排——subagents、skills、agent teams——本质都是让模型当指挥官:Claude 每一轮重新决定派谁、派什么、结果怎么用。这条路有两个硬伤:一是中间结果必然回流到 Claude 上下文,规模一大就撑爆窗口;二是编排逻辑不可复现,下次同类任务 Claude 可能换种拆法。
Workflow 把计划从"模型脑子里"挪到"代码里"。代码是确定性的:同一个脚本跑两遍,拆分一致、依赖一致、验证步骤一致。这才让"每次 PR 跑一遍多维度审查""每周扫一遍全库安全"这类可重复的工程化多 agent 流程成为可能。
但 workflow 也有它的边界:research preview 阶段行为可能变、脚本调试比 prompt 调试难、agent 过多会被限流、中间结果不进上下文导致你难以中途介入。20.10 节专门讲这些。
20.2 什么是 Dynamic Workflow:发布背景与本质区别
Dynamic Workflow 于 2026-05-28 随 Opus 4.8 发布(research preview,v2.1.154+ 起,至 v2.1.202+ 已稳定可用)。它的形态很特殊:不是你手写的配置文件,而是 Claude 根据你的任务描述当场编写的一段 JavaScript 脚本,由一个独立的后台运行时执行。
理解 workflow 的关键,是看清它和 subagent 的本质区别——谁决定下一步派谁。
┌──────────────── Subagent 模式:模型逐轮决定 ─────────────────┐
│ │
│ 用户:审 30 个路由的鉴权 │
│ │ │
│ ▼ │
│ Claude(轮 1):我先派 Explore 列文件 → 收到 30 个文件 │
│ │ │
│ ▼ │
│ Claude(轮 2):文件太多,我派 5 个 subagent 各审 6 个 → 收摘要 │
│ │ │
│ ▼ │
│ Claude(轮 3):摘要里有 3 个疑似误报,我再派验证 agent → 收结果 │
│ │ (每轮的中间结果都进 Claude 上下文) │
│ ▼ │
│ Claude(轮 4):合并,输出报告 │
│ │
└──────────────────────────────────────────────────────────────┘
┌──────────────── Workflow 模式:脚本决定 ──────────────────────┐
│ │
│ 用户:ultracode 审 30 个路由的鉴权 │
│ │ │
│ ▼ │
│ Claude(只一轮):写一段脚本 → 脚本交给运行时 │
│ │ │
│ ▼ (Claude 上下文在这里就空闲了) │
│ ┌─ 运行时执行脚本 ─────────────────────────────┐ │
│ │ const files = await agent(列出文件) │ │
│ │ const audits = await pipeline(files, │ │
│ │ f => agent(审 f), │ │
│ │ r => agent(验证 r) // 对抗验证 │ │
│ │ ) │ │
│ │ return audits // 中间结果全在脚本变量里 │ │
│ └──────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Claude 只收到最终报告,30 个文件的中间 dump 没进上下文 │
│ │
└──────────────────────────────────────────────────────────────┘三个关键点:
- 脚本由 Claude 写,不由你写:你描述任务,Claude 生成脚本。你通常不需要手写,但可以读、可以改、可以保存复用。
- 运行时与对话隔离:脚本在一个独立环境里跑,中间结果留在脚本变量,不回流 Claude 上下文。这是 workflow 能扩展到几百个 agent 的根本原因——Claude 上下文不再是瓶颈。
- 脚本本身是产物:每次运行都会把脚本写到
~/.claude/projects/<session>/下的一个文件里。你可以读它、diff 它、改它再重跑、保存成命令下次直接调。
与第 19 章对照:subagent 把闭环步骤 2(建立事实模型)和步骤 4(运行验证)的部分负载挪到独立上下文;workflow 更进一步,把整个编排逻辑挪出 Claude 上下文,只把"写脚本"和"收最终答案"留给主对话。
20.3 脚本结构:meta block + agent/pipeline/parallel/log/phase
一段 workflow 脚本由两部分组成:开头的 meta block,和后面的脚本 body(标准 JavaScript,非 TypeScript,支持 top-level await)。
20.3.1 meta block:纯字面量
export const meta = {
name: 'audit-routes',
description: 'Audit every route handler for missing auth checks',
phases: ['discover', 'review', 'verify', 'collect'],
}硬约束:meta 必须是纯字面量对象,不能用变量、不能插值、不能调用函数。下面这样会直接报语法错误:
// 错误:meta 里不能有变量或插值
const dims = ['discover', 'review']
export const meta = {
name: 'audit-routes',
phases: dims, // 报错:不是字面量
description: `Audit ${target}`, // 报错:模板字符串插值
}name 是命令名(保存后变成 /audit-routes),description 告诉 Claude 何时该写这个 workflow,phases 是阶段列表(用于 progress view 展示,也用于 phase() 标记)。phases 在小脚本里可省略,但大型 workflow 建议写全,方便 /workflows 视图分阶段展示进度。
20.3.2 五个核心函数
| 函数 | 作用 | 返回 |
|---|---|---|
agent(prompt, opts) | 派一个 subagent 执行 prompt | 文本或结构化对象(看 schema) |
pipeline(items, stage1, stage2, ...) | 每个 item 独立流过所有 stage,无 barrier | 结果数组 |
parallel(thunks) | 并发执行多个 thunk,barrier 等全部完成 | 结果数组(thunk 抛错则对应位 null) |
log(msg) | 输出到 progress view | undefined |
phase(name) | 标记当前所处阶段 | undefined |
agent() 的完整选项(基于发布说明,版本敏感):
const result = await agent(prompt, {
schema: { type: 'object', required: ['x'], properties: { /* ... */ } },
label: 'audit:src/auth', // progress view 里的显示名
phase: 'review', // 归属阶段
model: 'sonnet', // 覆盖会话模型
effort: 'high', // 推理档
isolation: 'worktree', // 在独立 worktree 运行
agentType: 'security-auditor' // 用某个自定义 subagent 定义
})schema 是关键:给了 schema,agent() 返回结构化对象(可直接在脚本里 .file、.findings 取字段);不给 schema,返回文本。结构化返回让你能在脚本里做 pipeline 的下游 stage 直接消费上游 stage 的字段,不用解析字符串。
pipeline() 的两段式:
const results = await pipeline(
items,
(item) => agent(`process ${item}`), // stage 1
(stage1Result) => agent(`verify ${stage1Result}`), // stage 2
// 更多 stage...
)每个 item 独立流过所有 stage,item A 在 stage 2 时 item B 可能还在 stage 1——没有 barrier。这是 MapReduce 式的数据流,适合"每个文件先审再验证"这类每 item 独立的流水线。
parallel() 的 barrier 语义:
const [a, b, c] = await parallel([
() => agent('task A'),
() => agent('task B'),
() => agent('task C'),
])
// 三个全部完成才继续;任一 thunk 抛错,对应位是 null,不中断其他parallel 等全部完成才继续,适合"三个维度都审完才能合并"这类需要齐步走的场景。注意"thunk 抛错 resolve null"这个行为:它不抛异常给你,而是静默把出错的位置变 null。你的下游 stage 必须处理 null 输入,否则会 crash。
20.4 pipeline vs parallel:无 barrier vs barrier
这两个函数是 workflow 脚本的骨干,选错会导致性能浪费或逻辑错误。
| 维度 | pipeline | parallel |
|---|---|---|
| 拓扑 | 每个 item 流过一串 stage | 多个 thunk 同时跑 |
| Barrier | 无(默认 MapReduce 式) | 有,等全部完成 |
| 典型用途 | 每文件:审 → 验证 → 打分 | 三维度同时审,齐步走 |
| 返回 | 结果数组(每 item 一项) | 结果数组(每 thunk 一项) |
| 抛错行为 | 单 item 抛错影响该 item 链路 | 单 thunk 抛错 → 该位 null |
smell test(用哪个):
- 任务是"对一堆 item 各做同一套多步处理"?→
pipeline。例:30 个文件,每个文件先审再验证再打分。 - 任务是"做几件不同的事,但都要做完才能下一步"?→
parallel。例:同时审安全、性能、正确性三个维度,三个都完才能合并。 - 任务是"对一堆 item 各做一步,然后对全部结果做一步聚合"?→
pipeline做前面,最后用agent()做聚合(pipeline不强制最后聚合)。
组合用法的典型形态:pipeline 处理每文件的流水线,parallel 在某个 stage 内做维度扇出。比如每文件先 parallel 三维度审查(齐步走),再流到验证 stage。但注意嵌套会增加 agent 数量,要算清总量(见 20.8 节)。
反模式:
// 反模式:用 parallel 模拟 pipeline,浪费且写起来痛苦
const step1 = await parallel(items.map(i => () => agent(`process ${i}`)))
const step2 = await parallel(step1.map(r => () => agent(`verify ${r}`)))
// 问题:全部 item 必须等 step1 跑完才能开始 step2,而 pipeline 里快的 item 可以提前进入 step220.5 编写实战:多维度代码审查 Workflow
下面是一个完整的 workflow 脚本示例。场景:对本次提交改动的所有 .ts/.tsx 文件做三维度(安全、性能、正确性)审查,每条发现经对抗验证后才上报,最后合并排序。
这是示例脚本(模拟,Claude 实际生成的脚本会有细节差异,但结构相似),用于让你认得 workflow 长什么样、能手动改:
export const meta = {
name: 'multi-dim-review',
description: 'Multi-dimensional code review (security/performance/correctness) with adversarial verification',
phases: ['discover', 'review', 'verify', 'collect'],
}
// Phase 1: 发现改动文件(结构化返回)
const found = await agent(
'List every .ts/.tsx file under src/ that changed in the last commit. Return {files: string[]}.',
{
schema: {
type: 'object',
required: ['files'],
properties: { files: { type: 'array', items: { type: 'string' } } },
},
label: 'discover-changed-files',
phase: 'discover',
},
)
log(`Discovered ${found.files.length} files to review`)
phase('review')
// Phase 2 + 3: 每个文件流过 review → verify(pipeline,无 barrier)
const reviewed = await pipeline(
found.files,
// stage 1: 三维度审查(parallel 齐步走,合并成一份 per-file findings)
(file) =>
parallel([
() => agent(
`Review ${file} for SECURITY issues (auth bypass, injection, secret leak, SSRF). ` +
`Return {file, dimension, findings: [{severity, line, issue}]}.`,
{ schema: { type: 'object', required: ['file','dimension','findings'],
properties: { file: {type:'string'}, dimension: {type:'string'},
findings: { type:'array', items: { type:'object',
properties: { severity:{type:'string'}, line:{type:'number'}, issue:{type:'string'} } } } } },
label: `review-security:${file}`, phase: 'review' },
),
() => agent(
`Review ${file} for PERFORMANCE issues (N+1 query, unnecessary re-render, sync IO in hot path). ` +
`Return {file, dimension, findings: [...]}.`,
{ schema: { /* 同上,略 */ }, label: `review-perf:${file}`, phase: 'review' },
),
() => agent(
`Review ${file} for CORRECTNESS issues (off-by-one, null deref, race condition, wrong error handling). ` +
`Return {file, dimension, findings: [...]}.`,
{ schema: { /* 同上,略 */ }, label: `review-correctness:${file}`, phase: 'review' },
),
]).then(([s, p, c]) => ({
file,
findings: [s, p, c].filter(Boolean).flatMap(r => r.findings),
})),
// stage 2: 对抗验证,丢掉误报
(perFile) =>
agent(
`Adversarially verify these findings for ${perFile.file}. ` +
`For each finding, open the file at that line and check if it is a real issue. ` +
`Drop false positives. Return only confirmed findings with evidence.\n` +
`Findings: ${JSON.stringify(perFile.findings)}`,
{
schema: { type: 'object', required: ['file','confirmed'],
properties: { file: {type:'string'},
confirmed: { type:'array', items: { type:'object',
properties: { severity:{type:'string'}, line:{type:'number'},
issue:{type:'string'}, evidence:{type:'string'} } } } } },
label: `verify:${perFile.file}`, phase: 'verify',
},
),
)
phase('collect')
// Phase 4: 合并、去重、排序
const summary = await agent(
`Merge and rank these verified findings across all files by severity (CRITICAL > HIGH > MED > LOW). ` +
`Dedup findings that are the same issue across files. Return {blocked: [...], advisory: [...], total: number}.\n` +
`All verified findings: ${JSON.stringify(reviewed)}`,
{
schema: { type: 'object', required: ['blocked','advisory','total'],
properties: { blocked: { type:'array', items: {type:'object'} },
advisory: { type:'array', items: {type:'object'} },
total: { type:'number' } } },
label: 'collect-summary', phase: 'collect',
},
)
return summary怎么读这段脚本:四个阶段对应 meta.phases。pipeline 的两个 stage 把"审查"和"验证"串成流水线,每文件独立流动;parallel 嵌在 stage 1 里做三维度齐步走。中间所有 found、reviewed 都是脚本变量,Claude 上下文里看不到这些——它只在最后收到 summary。
触发命令(让 Claude 写并跑这个 workflow):
ultracode: 对本次提交改动的所有 src/ 下的 .ts/.tsx 文件做多维度代码审查
(安全/性能/正确性),每条发现经对抗验证后才上报,最后合并排序或自然语言:
use a workflow to review every changed file under src/ for security,
performance, and correctness issues, adversarially verify each finding,
then merge into one ranked summary预期输出(Claude 上下文只收到最终 summary,不是几十个文件的中间 dump):
multi-dim-review 完成(4 阶段,28 个 agent,~3m12s)
阻塞项(2):
CRITICAL src/auth/session.ts:88 refresh token 未轮换,可重放
evidence: 第 88 行直接返回旧 token,无 rotate 调用
HIGH src/api/upload.ts:42 未校验 MIME 类型
evidence: multer 无 fileFilter,直接落盘
建议项(4):
HIGH src/payment/amount.ts:12 金额从 body 直接取,未校验范围
MED src/db/query.ts:30 N+1 查询(循环内 await)
MED src/notification/webhook.ts:30 webhook URL 未做协议白名单
LOW src/utils/parse.ts:18 off-by-one in slice(1, -1)
对抗验证:丢弃 3 条误报(2 条 security 误判、1 条 correctness 已有 guard)验证:
/workflows在 /workflows 视图里看到 multi-dim-review 运行中或已完成。按 Enter 或 → 钻进每个 phase,看到 agent 计数、token 总量、耗时;再钻进单个 agent 能读它的 prompt、最近工具调用、结果。按 s 可把这次跑的脚本保存成 /multi-dim-review 命令,以后直接调。
失败边界:
- Claude 生成的脚本不一定和上面一模一样:它可能用
parallel做维度扇出而不嵌进pipeline,也可能分两个 workflow 跑。脚本结构以 Claude 实际生成为准,你读得懂即可。 parallel抛错位变null:如果某个维度 agent 出错,.filter(Boolean)是必须的,否则下游r.findings会 crash。上面脚本里做了.filter(Boolean),这是防御性写法。- agent 总量要算清:30 文件 × 3 维度 = 90 review agent + 30 verify agent + 1 discover + 1 collect = 122 agent。在 1000 上限内,但如果文件数到 300,就超限了——这时应让 Claude 分批或换更粗的拆分。
- 脚本语法错误会直接失败:meta 不是纯字面量、用了 TS 类型注解、调了
Date.now()都会让运行时报错。错误信息会指到具体行,按提示改。
20.6 触发方式:ultracode 关键词 / 自然语言 / /effort ultracode
让 Claude 写并跑一个 workflow,有三条触发路径。
路径一:prompt 里含 ultracode 关键词
ultracode: audit every API endpoint under src/routes/ for missing auth checksClaude Code 会高亮 ultracode 关键词,Claude 据此写一个 workflow 脚本而不是逐轮处理。如果你不想触发,按 Option+W(macOS)或 Alt+W(Windows/Linux)取消本次高亮,或在 /config 里关掉 "Ultracode keyword trigger"。
版本注:
v2.1.160之前的关键词是字面量workflow;v2.1.160 起ultracode是主关键词,但自然语言请求在两个版本都工作。
路径二:自然语言请求
use a workflow to ...
run a workflow to ...Claude 把直接的 workflow 请求当作同等 opt-in,不需要你记关键词。这是更自然的写法。
路径三:/effort ultracode——Ultracode 模式
/effort ultracodeUltracode 不是一个单独的推理档,而是**xhigh 推理档 + 自动 workflow 编排的结合。开启后,Claude 对本会话里每个实质任务**都自动规划 workflow,不需要你每次说 ultracode。
| 触发方式 | 作用范围 | 何时用 |
|---|---|---|
ultracode 关键词 | 单次任务 | 偶尔跑一个大任务 |
| 自然语言 "use a workflow" | 单次任务 | 同上,更自然 |
/effort ultracode | 整个会话 | 一连串大任务(如全库迁移、多阶段研究) |
Ultracode 的会话级行为:开启后,一个请求可能变成一连串 workflow——先一个 workflow 理解代码,再一个 workflow 做改动,再一个 workflow 验证。每个任务比低 effort 档用更多 token、花更长时间。Ultracode 只在当前会话生效,新会话重置;回到常规工作用 /effort high。它只在支持 xhigh 的模型上可用(Opus 4.8 / Fable 5 等)。
审批提示:在 CLI 里,每次运行前会弹出计划审批,显示规划的 phases 和选项:
- Yes, run it:开始运行
- Yes, and don't ask again for
<name>in<path>:开始,且本项目里这个 workflow 以后不再问 - View raw script:先读脚本再决定(
Ctrl+G在编辑器里打开) - No:取消
是否看到这个提示取决于权限模式:
| 权限模式 | 何时提示 |
|---|---|
| Default / acceptEdits | 每次都问,除非选了 "不再问" |
| Auto | 首次问一次,之后自动;Ultracode 开启时跳过 |
Bypass permissions / claude -p / SDK | 从不提示,直接跑 |
重要:workflow 派发的 subagent 始终在 acceptEdits 模式运行,继承你的工具 allowlist,无论你会话当前是什么模式。文件编辑自动批准;但 shell 命令、web fetch、未在 allowlist 的 MCP 工具仍可能中途提示你。长时间运行前,先把需要的命令加进 allowlist。
20.7 /deep-research 剖析:扇出搜索 + 对抗验证 + 引用报告
Claude Code 内置了一个 bundled workflow:/deep-research。它是理解 workflow 范式最好的活样本。
/deep-research <question>它的编排逻辑(官方描述):
┌─ Phase 1: 扇出搜索 ──────────────────────────────────────────┐
│ 从多个角度并行发起 web 搜索(不同 query 变体) │
│ 每个搜索结果由一个 agent 读取、提取 claim │
└──────────────────────────────────────────────────────────────┘
│
▼
┌─ Phase 2: 交叉核对 ──────────────────────────────────────────┐
│ 每个 claim 交给独立的验证 agent │
│ 验证 agent 去找反证/佐证,对 claim 投票 │
│ 没通过交叉核对的 claim 被过滤掉 │
└──────────────────────────────────────────────────────────────┘
│
▼
┌─ Phase 3: 综合报告 ──────────────────────────────────────────┐
│ 存活的 claim 合并成带引用的最终报告 │
└──────────────────────────────────────────────────────────────┘/deep-research 示范了 workflow 相比单轮研究的两个核心优势:
- 扇出 + 对抗验证:单轮研究里,Claude 找到 5 个来源就信了;workflow 让每个 claim 被独立 agent 投票,过滤掉经不起交叉核对的。这是"更可信"而非"更多"。
- 中间结果不进上下文:几十个搜索结果、几十份网页正文,全部留在脚本变量里,Claude 上下文只收到最终带引用的报告。这是为什么 workflow 能扩展到几十个来源而不撑爆窗口。
/deep-research需要 WebSearch 工具可用。如果你的环境没配 WebSearch,这个 workflow 跑不起来。
你可以照着这个范式写自己的研究型 workflow:把"web 搜索"换成"grep 代码库"、"claim"换成"潜在 bug"、"投票"换成"对抗验证"——就是 20.5 节的代码审查 workflow。范式是通用的:扇出 → 对抗验证 → 综合。
20.8 size guideline 与限制
20.8.1 运行时的硬限制
| 限制 | 值 | 原因 |
|---|---|---|
| 并发 agent | 最多 16(CPU 核少的机器更少) | 限制本地资源 |
| 单次运行 agent 总量 | 最多 1000 | 防失控循环 |
| 运行中用户输入 | 不支持 | 只能 agent 权限提示暂停 |
| 脚本直接文件/Shell 访问 | 不允许 | agent 读写跑命令,脚本只协调 |
| 脚本里的不确定性 | 禁 Date.now() / Math.random() / 无参 new Date() | 保证可复现 |
| 语言 | 标准 JavaScript,非 TypeScript | 运行时不做 TS 转译 |
"脚本不能直接访问文件系统/Shell"这条容易被忽略:脚本里只有 agent()/pipeline()/parallel()/log()/phase() 这几个函数能产生副作用。你想读文件、跑命令,都必须派一个 agent 去做,脚本只负责协调 agent。这个限制保证了脚本本身是纯协调逻辑,可复现、可 diff。
"禁 Date.now()/Math.random()"是可复现性约束:同一个脚本跑两遍应该得到同样的编排结构(哪些 agent 被派、依赖关系如何),差异只来自 agent 的实际输出。如果你需要随机性(如随机采样),让 agent 在 prompt 里自己引入,不要在脚本层引入。
20.8.2 size guideline(v2.1.202+)
/config 里的 "Dynamic workflow size" 设置给 Claude 一个建议规模,Claude Code 把它作为 advice 传给 Claude。prompt 明确要求更大规模时仍可覆盖。
| 值 | 给 Claude 的建议 |
|---|---|
unrestricted | 不设建议(默认) |
small | 目标少于 5 个 agent |
medium | 目标少于 15 个 agent |
large | 目标少于 50 个 agent |
用法:不确定任务规模时,先设 medium,跑一次看 Claude 写的脚本用了多少 agent;如果总是偏大,设 small 压一压;确认需要大规模才设 large 或 unrestricted。运行时的 16 并发 / 1000 总量上限始终生效,与 size guideline 无关。
20.8.3 成本控制
Workflow 派很多 agent,单次运行可能比对话里逐轮处理用更多 token,且计入你的 plan 用量和速率限制。控制成本的三个手段:
- 先跑小切片:全库审查前,先在一个子目录上跑,看 token 消耗,再决定是否扩大。
/workflows视图实时显示每个 agent 的 token 用量,可随时停止且不丢失已完成的工作。 - 检查
/model:大运行前确认模型。如果你平时切到小模型做常规工作,大 workflow 前切回来或显式指定 stage 用小模型(agent(prompt, {model: 'haiku'})给不需要强模型的 stage)。 - size guideline 兜底:设
medium让 Claude 默认写 15 agent 以内的脚本,避免一次跑飞。
20.9 四原语选型决策树
Subagents、Skills、Agent Teams、Workflows 都能跑多步任务,区别在于"谁持有计划"。官方给了一张对比表,这里加上选型决策逻辑。
| Subagents | Skills | Agent Teams | Workflows | |
|---|---|---|---|---|
| 是什么 | Claude 派的 worker | Claude 跟随的指令 | 主 agent 监督的 peer 会话 | 运行时执行的脚本 |
| 谁决定下一步 | Claude 逐轮 | Claude 跟随 prompt | 主 agent 逐轮 | 脚本 |
| 中间结果在哪 | Claude 上下文 | Claude 上下文 | 共享任务列表 | 脚本变量 |
| 可复用的是什么 | worker 定义 | 指令 | team 定义 | 编排本身 |
| 规模 | 每轮几个 | 同 subagents | 几个长期 peer | 几十到几百 |
| 中断 | 重启这一轮 | 重启这一轮 | peer 继续跑 | 同会话可恢复 |
选型决策树:
任务需要多步编排吗?
│
├─ 否(单步或线性几步) → 直接在主对话做,别上原语
│
└─ 是 → 任务规模多大?
│
├─ 几个 agent 就够,且每步结果你想看到
│ → Subagents(第 19 章)
│
├─ 是固定流程,想让 Claude 按既定步骤走(但规模不大)
│ → Skills(第 16 章)
│
├─ 需要几个 agent 互相协商/对话(非单向委托)
│ → Agent Teams(research preview,第 19 章 19.6.3)
│
└─ 几十到几百个 agent,且编排逻辑要可复现
→ Workflows(本章)一句话区分:
- Subagents:主对话当指挥官,逐轮派谁。适合"派几个 agent 各审一片"。
- Skills:把固定步骤写成指令,Claude 跟着走。适合"每次 PR 都按这五步审"。
- Agent Teams:几个 peer 互发消息协商。适合"前端 agent 和后端 agent 谈 API 契约"。
- Workflows:编排逻辑是代码,规模大、可复现。适合"全库扫描、大规模迁移、交叉核对研究"。
Workflows 不取代前三者,而是补上"大规模 + 可复现编排"这一格。小任务用 workflow 是杀鸡用牛刀(脚本生成与审批的开销大于收益);大任务用 subagents 会撑爆上下文。选型的核心问题是:这个任务的编排逻辑,值不值得固化成代码? 值得——workflow;不值得——subagent 或 skill。
20.10 失败边界汇总
把本章分散的失败边界集中一次,作为使用前的 checklist。
| 失败模式 | 症状 | 对策 |
|---|---|---|
| research preview 行为变动 | 升级后脚本结构、API、限制值变化 | 版本敏感,以 code.claude.com/docs/en/workflows 为准;生产流程里 pin 版本 |
| 脚本语法错误 | 运行时直接失败,指到某行 | meta 必须纯字面量;用标准 JS 不用 TS;不调 Date.now()/Math.random() |
| agent 过多被限流 | 脚本跑到一半 agent 派不出去或排队 | 16 并发硬限;1000 总量硬限;大任务分批或设 size guideline |
| 中间结果不进上下文致难调试 | 你想看某个 agent 为啥那么判断,但只看到最终摘要 | /workflows 视图钻进单个 agent 读它的 prompt/工具调用/结果;或让 agent 在返回里带 evidence 字段 |
parallel 抛错位变 null | 下游 stage 拿到 null 输入 crash | 下游必做 .filter(Boolean) 或显式判空 |
| workflow 中途不能要用户输入 | 想在 stage 之间签字,但没法 | 拆成多个独立 workflow,每个跑完你审一次再跑下一个 |
| 脚本不能直接访问文件/Shell | 脚本里写 fs.readFile 报错 | 所有副作用通过 agent() 派 agent 做,脚本只协调 |
| 成本失控 | 一次跑掉大量 token | 先跑小切片;/model 检查;设 size guideline;/workflows 实时监控,随时停 |
| subagent 模式不受会话模式控制 | 你设了 default 模式,workflow 的 subagent 还是自动改文件 | workflow subagent 始终 acceptEdits + 继承 allowlist;要拦 shell/MCP 命令,提前加 allowlist 或在 deny 里配 |
| 会话退出 workflow 丢失 | 退出 Claude Code,下次进来 workflow 没继续 | resume 只在同一会话内有效;退出后下次是 fresh start |
| Ultracode 开销大 | /effort ultracode 后每个任务都跑 workflow,慢且贵 | 只在需要时开,常规工作切回 /effort high |
20.11 核心心法
Workflows 的价值不在"能派更多 agent",而在"把编排逻辑从模型脑子里挪到代码里"。代码是确定性的、可 diff 的、可复现的——这才让多 agent 流程从"时灵时不灵的技巧"变成"可工程化的流水线"。
与第 19 章对照:subagent 解决了"单个子任务上下文隔离",workflow 解决了"整套编排逻辑隔离与复现"。前者是分身,后者是流水线。一个 30 文件的审查,用 subagent 时 Claude 要在上下文里 hold 30 份摘要、决定下一步派谁、merge 结果;用 workflow 时 Claude 只管写脚本和收最终报告,中间 30 份摘要全在脚本变量里。
但请记住第 06 章的心法:你做架构决策和关键审查,Claude 做实现和探索。 Workflow 是 Claude 用来"做探索"的最强武器,但它不替你做审查。workflow 跑出来的报告,最终还是要你用 git diff 看真实变更、用 /security-review 做最终安全判断。这两件事,不能委托给任何编排——哪怕是确定性脚本。
最后,workflow 是 research preview。它的 API、限制、触发方式都可能随版本调整。在你把某个 workflow 固化成生产流程(比如 CI 里跑)之前,确认版本、pin 住行为、留好回退路径。2026 年这个功能还在快速演进,现在押注全部工作流到它身上,为时过早;但现在是开始积累 workflow 脚本资产、摸清范式边界的最好时机。
下一章:Claude Agent SDK | 返回目录