Skip to content

第 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 的本质区别——谁决定下一步派谁

text
┌──────────────── 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 没进上下文        │
│                                                              │
└──────────────────────────────────────────────────────────────┘

三个关键点:

  1. 脚本由 Claude 写,不由你写:你描述任务,Claude 生成脚本。你通常不需要手写,但可以读、可以改、可以保存复用。
  2. 运行时与对话隔离:脚本在一个独立环境里跑,中间结果留在脚本变量,不回流 Claude 上下文。这是 workflow 能扩展到几百个 agent 的根本原因——Claude 上下文不再是瓶颈。
  3. 脚本本身是产物:每次运行都会把脚本写到 ~/.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:纯字面量

javascript
export const meta = {
  name: 'audit-routes',
  description: 'Audit every route handler for missing auth checks',
  phases: ['discover', 'review', 'verify', 'collect'],
}

硬约束:meta 必须是纯字面量对象,不能用变量、不能插值、不能调用函数。下面这样会直接报语法错误:

javascript
// 错误: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 viewundefined
phase(name)标记当前所处阶段undefined

agent() 的完整选项(基于发布说明,版本敏感):

javascript
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() 的两段式:

javascript
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 语义:

javascript
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 脚本的骨干,选错会导致性能浪费或逻辑错误。

维度pipelineparallel
拓扑每个 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 节)。

反模式:

javascript
// 反模式:用 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 可以提前进入 step2

20.5 编写实战:多维度代码审查 Workflow

下面是一个完整的 workflow 脚本示例。场景:对本次提交改动的所有 .ts/.tsx 文件做三维度(安全、性能、正确性)审查,每条发现经对抗验证后才上报,最后合并排序。

这是示例脚本(模拟,Claude 实际生成的脚本会有细节差异,但结构相似),用于让你认得 workflow 长什么样、能手动改:

javascript
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.phasespipeline 的两个 stage 把"审查"和"验证"串成流水线,每文件独立流动;parallel 嵌在 stage 1 里做三维度齐步走。中间所有 foundreviewed 都是脚本变量,Claude 上下文里看不到这些——它只在最后收到 summary

触发命令(让 Claude 写并跑这个 workflow):

text
ultracode: 对本次提交改动的所有 src/ 下的 .ts/.tsx 文件做多维度代码审查
(安全/性能/正确性),每条发现经对抗验证后才上报,最后合并排序

或自然语言:

text
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):

text
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)

验证:

text
/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 关键词

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

Claude Code 会高亮 ultracode 关键词,Claude 据此写一个 workflow 脚本而不是逐轮处理。如果你不想触发,按 Option+W(macOS)或 Alt+W(Windows/Linux)取消本次高亮,或在 /config 里关掉 "Ultracode keyword trigger"。

版本注:v2.1.160 之前的关键词是字面量 workflow;v2.1.160 起 ultracode 是主关键词,但自然语言请求在两个版本都工作。

路径二:自然语言请求

text
use a workflow to ...
run a workflow to ...

Claude 把直接的 workflow 请求当作同等 opt-in,不需要你记关键词。这是更自然的写法。

路径三:/effort ultracode——Ultracode 模式

text
/effort ultracode

Ultracode 不是一个单独的推理档,而是**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 范式最好的活样本。

text
/deep-research <question>

它的编排逻辑(官方描述):

text
┌─ Phase 1: 扇出搜索 ──────────────────────────────────────────┐
│  从多个角度并行发起 web 搜索(不同 query 变体)                  │
│  每个搜索结果由一个 agent 读取、提取 claim                      │
└──────────────────────────────────────────────────────────────┘


┌─ Phase 2: 交叉核对 ──────────────────────────────────────────┐
│  每个 claim 交给独立的验证 agent                                │
│  验证 agent 去找反证/佐证,对 claim 投票                        │
│  没通过交叉核对的 claim 被过滤掉                                │
└──────────────────────────────────────────────────────────────┘


┌─ Phase 3: 综合报告 ──────────────────────────────────────────┐
│  存活的 claim 合并成带引用的最终报告                            │
└──────────────────────────────────────────────────────────────┘

/deep-research 示范了 workflow 相比单轮研究的两个核心优势:

  1. 扇出 + 对抗验证:单轮研究里,Claude 找到 5 个来源就信了;workflow 让每个 claim 被独立 agent 投票,过滤掉经不起交叉核对的。这是"更可信"而非"更多"。
  2. 中间结果不进上下文:几十个搜索结果、几十份网页正文,全部留在脚本变量里,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 压一压;确认需要大规模才设 largeunrestricted。运行时的 16 并发 / 1000 总量上限始终生效,与 size guideline 无关。

20.8.3 成本控制

Workflow 派很多 agent,单次运行可能比对话里逐轮处理用更多 token,且计入你的 plan 用量和速率限制。控制成本的三个手段:

  1. 先跑小切片:全库审查前,先在一个子目录上跑,看 token 消耗,再决定是否扩大。/workflows 视图实时显示每个 agent 的 token 用量,可随时停止且不丢失已完成的工作。
  2. 检查 /model:大运行前确认模型。如果你平时切到小模型做常规工作,大 workflow 前切回来或显式指定 stage 用小模型(agent(prompt, {model: 'haiku'}) 给不需要强模型的 stage)。
  3. size guideline 兜底:设 medium 让 Claude 默认写 15 agent 以内的脚本,避免一次跑飞。

20.9 四原语选型决策树

Subagents、Skills、Agent Teams、Workflows 都能跑多步任务,区别在于"谁持有计划"。官方给了一张对比表,这里加上选型决策逻辑。

SubagentsSkillsAgent TeamsWorkflows
是什么Claude 派的 workerClaude 跟随的指令主 agent 监督的 peer 会话运行时执行的脚本
谁决定下一步Claude 逐轮Claude 跟随 prompt主 agent 逐轮脚本
中间结果在哪Claude 上下文Claude 上下文共享任务列表脚本变量
可复用的是什么worker 定义指令team 定义编排本身
规模每轮几个同 subagents几个长期 peer几十到几百
中断重启这一轮重启这一轮peer 继续跑同会话可恢复

选型决策树:

text
任务需要多步编排吗?

├─ 否(单步或线性几步) → 直接在主对话做,别上原语

└─ 是 → 任务规模多大?

    ├─ 几个 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 脚本资产、摸清范式边界的最好时机。


上一章:Subagents:并行探索与上下文隔离


下一章:Claude Agent SDK | 返回目录