谁持有
plan?
Subagent、Skill、Workflow 经常被混为一谈。但官方把三者放进同一张表对比时,区分它们的其实只有一个问题:编排任务的那个 plan,到底在谁手里——是 Claude 一回合一回合临场拿主意,还是一段写好了就能重跑的代码。
不是「哪个更强」,
而是 plan 在谁手里。
“With subagents and skills, Claude is the orchestrator: it decides turn by turn what to spawn next, and every result lands in Claude's context. A workflow script holds the loop, the branching, and the intermediate results itself, so Claude's context holds only the final answer.”
可以这样记:Skill 存下来的是「指令」,Workflow 存下来的是「编排的过程本身」。两者根本不是一回事,所以 Workflow 谈不上替代 Skill,它俩各管各的。
自己切一下:plan 归谁,
中间结果往哪儿堆
在这三种做法之间切一下,盯住两点:那枚标着 PLAN 的方块这会儿滑进了谁的盒子,右边那一步步的中间结果又往哪儿堆。
Plan 持有者
中间结果落点
- 谁决定下一步
- 中间结果存在
- 规模
- 中断时
plan 的归属,正沿着列易手
这张表不该横着比谁强谁弱,而该顺着列往下看:「plan 在谁手里」是怎么从最左列一路交到最右列的。高亮的那一行,就是分界点。
| Subagents | Skills | Workflows | |
|---|---|---|---|
| 是什么 | Claude spawn 的一个 worker | Claude 遵循的指令 | runtime 执行的一段脚本 |
| 谁决定下一步跑什么 | Claude,逐回合 | Claude,跟着 prompt 走 | 脚本 |
| 中间结果存在哪 | Claude 的 context | Claude 的 context | 脚本变量 |
| 可复现的是什么 | worker 定义 | 指令 | 编排本身 |
| 规模 | 每回合几个委派 | 同 subagent | 每次 run 几十到几百个 agent |
| 中断时 | 重启该回合 | 重启该回合 | 同一会话内可 resume |
表中每一行均出自 code.claude.com/docs/en/workflows [官方]。
三份文件,分别长这样
上面那些区别听着抽象,落到磁盘上其实就是三种不同的文件。把它们摆在一起,表里「可复现的是什么」那一行立刻就具体了。
--- name: security-scout description: 隔离 context 里扫单个文件的注入风险 tools: Read, Grep model: sonnet --- 你是安全审查员。只读给定文件,找出未经校验 的输入流向危险 sink 的路径。逐条返回 { file, line, risk },不修复、不展开无关分析。
--- name: pdf-fill description: 填写 PDF 表单域;需要把数据 写进 PDF 表单时使用。 --- # 填写 PDF 表单 1. pdftk dump_data_fields 列出所有字段 2. 把用户数据映射到字段名 3. 生成 FDF,再 pdftk fill_form 回填 → 字段名对照见 references/field-map.md
export const meta = { name: 'bug-hunt', description: '全库找 bug,逐条对抗验证后再报', phases: [{ title: 'Find' }, { title: 'Verify' }], } // 各维度并行找;每条 finding 一冒头就独立验证 const found = await pipeline(DIMENSIONS, d => agent(d.prompt, { phase: 'Find', schema: BUGS }), rv => parallel(rv.bugs.map(b => () => agent(`试着推翻这条:${b.title}`, { phase: 'Verify', schema: VERDICT }) .then(v => ({ ...b, ok: v.isReal }))))) return found.flat().filter(b => b.ok) // 只留验证为真的
样本为示意:Subagent / Skill 文件格式依官方约定,Workflow 脚本依官方运行时 API(agent() / pipeline() / parallel() / meta)。
中间结果不进 context,
context 才不会腐烂
这正是 Workflow 能一口气跑上几小时、甚至几天的根本原因。用 Skill 或 Subagent 时,每个中间结果都会塞回 context window:任务越大,窗口越满,也就越容易腐化(rot)。Workflow 把这些结果留在脚本变量里,Claude 自始至终只看到最后那个答案。
“Because the coordination happens outside the conversation, the plan stays on track no matter how big the task gets.”
workflow 凭什么跑得出
单遍做不到的结果
它真正厉害的地方不在于「能跑更多 agent」,而在于把保证质量的套路直接写进了循环:让几份结论互相挑错、从几个角度各写一版再比、一轮轮改到结果稳定为止。
动态规划
你把任务说清楚,Claude 当场写出一段 JS 编排脚本(所谓 dynamic,就是针对你这个任务临时生成、而非套用现成模板),再把它拆成一个个子任务。
分头并行铺开
脚本用 parallel() / pipeline() 这些写法,把活儿摊给几十、上百个 subagent 同时干。pipeline 的妙处是:每件活各走各的流程,互不卡着,谁先干完谁先走,不用排队等最慢的那个。
互相挑错验证
每条结果在汇总之前,先过一道检查:另外几个 agent 各自上来挑刺、专门想把它推翻,被多数人否掉的就直接扔掉。再让 schema 约定好返回格式,省得事后还得去解析一堆文本。
反复跑到答案稳定
官方原话是 “the run keeps iterating until the answers converge”:答案稳定下来才算结束,而不是跑满固定的几轮。最后把这些结果拢成一个统一的答案交回给你。
两者各管各的,还能搭着用
两者根本不在一个层面上。一个 workflow 分头派出去的每个 agent,照样可以先挂上一个 skill 再干活。它们是搭配着用的,不是二选一。
改变「模型知道什么、会做什么」
把知识和指令按需一点点喂给模型,说白了就是把「怎么写提示词」做成了现成产品。官方讲得很直接:skill 的结果不保证每次一样,因为指令是交给 Claude 自己理解的,到底怎么走,还是它一回合一回合临场定。
改变「怎么把成批 agent 稳稳编排起来」
编排的逻辑从 Claude 的上下文里挪了出来,变成脚本里的 for 循环、if 分支和 pipeline() 调用。脚本一写定,「谁持有 plan」就从 Claude 手里,交到了这段写死的代码手里。
await agent(prompt, {
agentType: 'code-reviewer', // 复用 skill
schema: FINDINGS
})
什么时候用哪个
隔出一段脏活单独跑
- 想用一个干净的 context 去跑探索或搜索
- 把噪音挡在主 context 之外
- 一回合派出去几个,结果收回来你接着拿主意
把一套做法固定下来
- 手上有一套可复用的做法、规范或知识
- 希望 Claude 每次都照同一套思路来
- 能接受结果因模型的临场判断而略有出入
编排大到 context 装不下时
- 整库级别的 bug hunt 或安全审计
- 牵动上千文件的迁移与现代化
- 重要决策想让多个独立 agent 反复核两遍
Bun:Zig → Rust,11 天
这是官方专门拿出来讲的大案例。四个 workflow 一环扣一环:第一个把 Zig 代码里每处的内存生命周期理清楚,第二个逐个文件翻成 Rust、每个文件还配两名 reviewer,第三个反复跑编译和测试直到全绿,最后一个通宵跑优化、一处一处单独开 PR 等人来审。
别把它读成「随便哪个迁移都能 11 天搞定」。这个成绩背后的前提相当苛刻(结合官方的限定说明,以及 Bun 仓库里那份一手的 rust-rewrite-plan.md [第三方]):
- 还没上生产:官方原话就是 “While not yet in production”,而且 99.8% 终究不是 100%。
- 用的是「绞杀式」渐进迁移,不是推倒重来:Zig 和 Rust 始终打包在同一个程序里,按一个个类逐步开关切换。
- 每切换一处都要过几道关:跑测试、新旧结果比对(shadow-diff),还有性能不能掉超过 2%。是这些检查逼出来的结果,不是「写完就信」。
- 既有测试覆盖率本就极高,又是工具作者本人挑大梁的单人项目。
真正该记住的是:只要这块代码够重要、测试够硬、检查关卡够严,把流程写成确定的脚本、再让它反复编译测试到全绿,确实能把原本按季度估的活压进几天。所以落地的正确姿势,是先挑这么一块去试,而不是把「11 天」这个数照搬到所有项目上。