Skip to content

动态 Workflow 编排

当一次要派 20 个 agent、跑一小时、还得能断点续跑时,光靠主 loop 里发几个 Agent 调用已经不够。

什么是 Workflow

Workflow 是一段脚本化的 agent 编排代码。它介于两种熟悉的抽象之间。

比主 loop 里"临时发几个 Agent 调用"更结构化:拓扑是你写死的,不是 Claude 临场决定要不要 fan-out、fan-out 几个。

比 Skill 更细粒度:Skill 是一段引导性指令,Workflow 是一段确定性运行时,里面明确说"这一阶段并行开 5 个 worker,下一阶段汇总"。

它的核心价值是三件事:确定性拓扑(reviewer 一定跑在 finder 之后)、大规模 fan-out(一次派 20 个 agent 处理 20 个文件不吃力)、断点续跑(跑到一半崩了,从上次的位置继续,未变更的前缀直接命中缓存)。

meta 块:workflow 的身份证

每个 workflow 文件顶部有一段 meta,它是纯字面量,不允许变量插值。

typescript
export const meta = {
  name: "code-review-panel",
  description: "多视角并行审查一段代码变更并汇总",
  phases: ["Fan-out reviewers", "Aggregate verdict"],
};

phases 只用于 UI 展示当前跑到哪一阶段,不改变执行逻辑。写字面量而不是拼接的原因很朴素:它需要在不 eval 主体的情况下被读出来。

六个核心 hook

Workflow 主体里能调的核心 hook 就这六个,学会了它们,你能拼出绝大多数编排。

agent(prompt, opts) —— 派一个 subagent,等它跑完拿到结构化结果。相当于主 loop 的 Agent 调用,但在脚本里可以拿到返回值。

parallel(thunks) —— barrier 语义:等数组里所有 thunk 都完成才 resolve。适合明确的"等这批人都跑完再往下走"。

pipeline(items, ...stages) —— 每个 item 独立穿越所有 stage,item 之间没有 barrier,wall-clock 时间等于最慢那个单项链。

phase(title) —— 打一个人类可读的阶段标记,UI 上会看到。

log(msg) —— 结构化日志,写进 workflow 的运行记录。

workflow(nameOrRef, args) —— 调用另一个 workflow 作为子步骤。允许你把编排本身拆成可复用的组件。

Pipeline 和 parallel 的取舍

这两个 API 长得像,但语义完全不同,选错了会让 wall-clock 时间翻倍。

parallel 是"barrier: 等所有 thunk 完成才返回"。用它的时候你在告诉调度器:这几件事必须都做完才能进入下一步。

pipeline 是"每个 item 独立穿越 stage 链"。20 个文件、每个文件都要过 review + test + summary 三个 stage。第一个文件走到 test stage 时,第二个文件可能才刚开始 review,谁也不等谁。总时间等于最慢那一条独立链。

默认选 pipeline。 只有当你真的需要 cross-item 汇总(比如汇总所有 review 结果做投票)时才用 parallel。这个建议来自一个观察:多数 fan-out 任务其实是 item 之间独立的,用 parallel 会引入毫无必要的 barrier,让整体时间被最慢的一项拖死。

别把 pipeline 误用为顺序执行

pipeline 不是"跑完 stage 1 再跑 stage 2"。它是"每个 item 独立走完自己的 stage 链"。如果你要的是"所有人先做完 stage 1 再一起进 stage 2",那是 parallel + 顺序。

六个可以直接抄的 pattern

Adversarial verify。主 agent 写出结果,一个 fresh model 的 verifier subagent 尝试 refute 它。做事的人不该同时是打分的人,这条 Anthropic best practices 里明确讲过。

Multi-modal sweep。同一份输入用不同 lens(性能、安全、可读性)并行审查,每一路结果独立汇报,主 loop 拿到全景图。

Judge panel。给同一个方案派 3 到 5 个 judge agent 独立打分,输出多数决和分歧点,用于选型和方案对比。

Loop-until-dry。让 agent 迭代跑,每一轮拿新证据,直到 verifier 说"没新东西了"才收工。适合开放式研究和 bug 定位。

完整性 critic。一个 critic 专门检查主 agent 有没有漏做用户列出的需求。它的 prompt 里明确带着 spec 清单,只回答"漏了哪几条"。

Budget-scaling。lead agent 根据任务复杂度动态决定要不要 fan-out:简单查询 1 个 worker、对比类 2 到 4 个、复杂研究 10 个以上。Anthropic 的 Research 系统就用这条明确写在 prompt 里的规则来防止过度投入。

Resume:断点续跑的白日梦

每次跑一个 workflow 都会拿到一个 runId。用同一个 runId 再跑一次,未变更的前缀会直接命中缓存,从上次崩掉的位置往下继续。

这一点对多 agent workflow 尤其重要。想象一下你跑一个 20-worker 的 fan-out 研究,跑了 40 分钟,某个 worker 因为 API rate limit 挂掉。没有 resume 你只能整个重跑。有 resume,前 19 个 worker 的输出全部缓存命中,几秒钟内就恢复到崩掉那一步。

Anthropic 团队讲得很直接:agent 是 stateful 的,错误会 compound,重启是"expensive and frustrating for users"。所以他们内部同样做了 checkpoint 机制。

一个可以照着改的例子

下面这段展示 pipeline + 结构化输出。20 个 PR 文件,每个都要过 review 和 test,最后汇总一份 gap 清单。

typescript
import { agent, pipeline, phase, log } from "workflow";

export const meta = {
  name: "pr-multi-review",
  description: "对 PR 里每个文件并行做 review + test 检查",
  phases: ["Per-file review", "Aggregate gaps"],
};

export default async function run({ files, planPath }) {
  phase("Per-file review");
  const results = await pipeline(
    files,
    // stage 1: fresh subagent 做 review
    (file) => agent(`审查 ${file} 是否符合 ${planPath} 里的规范`, {
      subagent_type: "fresh",
      tools: ["Read", "Grep", "Glob"],
    }),
    // stage 2: 同一个 file 的 review 结果再送给测试 agent
    (review, file) => agent(`基于 review 结论跑 ${file} 相关的测试并回报`, {
      subagent_type: "fresh",
      tools: ["Bash", "Read"],
    }),
  );

  phase("Aggregate gaps");
  log(`收到 ${results.length} 份 per-file 报告`);
  return agent("综合所有 per-file 报告,输出 gap 清单和优先级", {
    subagent_type: "fork",
    input: { results },
  });
}

pipeline 里第一个 stage 是 review,第二个 stage 是 test。20 个文件同时穿越这两个 stage,谁也不等谁。最后 parallel 结束后一个 fork subagent 汇总所有报告,输出结构化的 gap 清单。

什么时候用 Workflow

Workflow 不是替代主 loop 的 Agent 调用,它俩共存。三条判断规则:

用户明确 opt-in。 主 loop 是 Claude 判断要不要派 agent,Workflow 是你写死"这里必须 fan-out 20 个 worker"。你想要确定性,就用 Workflow。

需要确定性拓扑。 比如"reviewer 一定在 finder 之后跑""所有 worker 用完才能进入 aggregation",这些结构靠主 loop 里的自然语言约束不可靠,写在 Workflow 里是硬性的。

大规模 fan-out。 主 loop 里发 5 个 Agent 调用还行,一次要 fan-out 20 个以上就该走 Workflow,顺带拿到 resume 能力。

反过来,日常的"读几个文件回答一个问题"、"派两个 agent 并行找 bug 位置"这类场景,主 loop 里的 Agent 调用已经够用,别为了用 Workflow 而用 Workflow。Anthropic 讲的原则一直是:最简单能解决问题的方案就是最好的方案。

参考来源

本教程为社区中文学习整理,非官方发布。Claude Code 属于 Anthropic。