一个 Skill 搞不定复杂任务?学会编排,让 Skill 组合协作
一句话:当单个 Skill 不够用时,如何设计 Skill 之间的调用、编排、协同——让多个 Skill 像"团队"一样工作。
你在日常中建过 Skill 包、写过 Eval、跑过 baseline——但遇到复杂任务时,发现一个 Skill 搞不定。
典型场景:
•一个 PM 需求文档要转化成 OpenSpec 四文件,涉及规格生成、字段矩阵、任务分解——单 Skill 写完 200 行,改不动
•一篇公众号文章要审稿、审配图、审合规——三个功能堆在一个 Workflow 里,Eval 写不出
•编排型 Skill 调用两个子 Skill,但不知道如何在 SKILL.md 里声明、如何验证调用顺序
这篇文章只做一件事:从单体 Skill 到编排 Skill 的协作模式设计。
适用读者:遇到多 Skill 协作需求本文案例:
pm-md-to-openspec-pipeline(编排两个子 Skill)前置阅读:[AI Agent Skill 工程化 01:写 Skill 不是写 Prompt,构建可迭代的工程体系](AI Agent Skill 工程化 01:写 Skill 不是写 Prompt,构建可迭代的工程体系)(L2 编排层概念)
先用人话:什么是 Skill 编排?
可以把 Skill 编排 理解成:让多个 Skill 组成"团队"协作完成任务。
Read 子Skill | |
编排 ≠ 堆功能:编排 Skill 不做具体事,只负责分配任务、协调顺序、汇总结果。
两层"编排"别混:
L0 标准层(01):原子 Skill,只做一件事L2 编排层(05):编排 Skill,协调多个原子 Skill核心是什么?
口诀:先原子、再编排;显式声明; 验过程。
编排三要素:
Workflow显式Read子Skill → trajectory Eval验证调用顺序 → 契约传递不断裂§0 开篇:单体 Skill 的边界
0.1 什么时候需要编排?
| SKILL.md > 150 行 | ||
| 多个独立输出 | ||
| 可复用子流程 | ||
| Eval 写不出 |
0.2 编排 vs 单体:本质区别
| 职责 | ||
| Workflow | Read 子Skill | |
| Eval | ||
| SKILL.md 行数 |
0.3 本文边界
§1 编排模式四类
1.1 串行编排:前置依赖
适用场景:子 Skill 有顺序依赖,前一个输出是后一个输入。
案例:pm-md-to-openspec-pipeline
PM需求文档 ↓ Read spec-generator Skill(生成 design.md + spec.md) ↓ Read reconciler Skill(生成 field-matrix.md + tasks.md) ↓ 汇总四文件,输出 Gate 状态SKILL.md Workflow 示例:
## Workflow1. Read 子 Skill `spec-generator`,输入 PM MD,输出 design.md + spec.md2. Read 子 Skill `reconciler`,输入 spec.md,输出 field-matrix.md + tasks.md3. 汇总四文件,检查 Gate 闭合状态4. 输出最终报告1.2 并行编排:独立分支
适用场景:子 Skill 无依赖,可同时执行。
案例:公众号审稿 + 审配图
文章正文 ├─ Read article-reviewer Skill → 评分报告 └─ Read image-reviewer Skill → 配图合规清单 ↓ 汇总两份报告SKILL.md Workflow 示例:
## Workflow1. 并行执行: - Read 子 Skill `article-reviewer`,输出评分报告 - Read 子 Skill `image-reviewer`,输出配图清单2. 汇总两份报告,输出综合评审结果Eval 设计:并行编排需验证两个子 Skill 都被调用。
1.3 条件分支:动态路由
适用场景:根据输入或中间结果,选择不同子 Skill。
案例:依文章状态选择审稿流程
文章输入 ↓ 检查状态 ├─ 状态=初稿 → Read article-reviewer Skill ├─ 状态=定稿 → Read compliance-checker Skill └─ 状态=已发 → Read update-optimizer SkillSKILL.md Workflow 示例:
## Workflow1. 读取文章状态(frontmatter.status)2. 条件分支: - 若 status=draft → Read `article-reviewer` - 若 status=final → Read `compliance-checker` - 若 status=published → Read `update-optimizer`3. 汇总输出Eval 设计:条件编排需验证路由逻辑正确。
1.4 子 Skill 调用:可复用模块
适用场景:原子 Skill 在多个编排 Skill 中复用。
案例:spec-generator 被多个编排 Skill 调用
pm-md-to-openspec-pipeline → 调用 spec-generatorfeature-request-pipeline → 调用 spec-generatorbug-report-pipeline → 调用 spec-generator(生成修复规格)子 Skill 契约要求:
| Input Contract | |
| Output Contract | |
| Side Effects |
1.5 编排模式决策树
子 Skill 有顺序依赖? ├─ 是 → 串行编排 └─ 否 → 可并行?可并行? ├─ 是 → 并行编排 └─ 否 → 有条件分支?有条件分支? ├─ 是 → 条件编排 └─ 否 → 单体 Skill(无需编排)§2 编排 Skill 的 SKILL.md 写法
2.1 必须显式声明 Read 子 Skill
❌ 错误写法(隐式调用):
## Workflow1. 分析 PM 需求文档2. 生成 design.md 和 spec.md3. 生成 field-matrix.md 和 tasks.md4. 汇总四文件问题:Eval 无法验证是否调用了子 Skill,无法测 trajectory。
✅ 正确写法(显式声明):
## Workflow1. Read 子 Skill `spec-generator`,输入 PM MD,输出 design.md + spec.md2. Read 子 Skill `reconciler`,输入 spec.md,输出 field-matrix.md + tasks.md3. 汇总四文件,检查 Gate 闭合状态4. 输出最终报告关键:Read 子 Skill <name> 是 trajectory Eval 的验证锚点。
2.2 编排 Skill 的 Input Contract
编排 Skill 的输入通常是子 Skill 输入的集合:
## Input Contract### 必填- PM 需求文档路径(`pm-requests/<id>.md`)### 可选- 现有 design.md 路径(局部刷新场景)- 现有 spec.md 路径(局部刷新场景)### 缺失处理- 缺 PM MD → BLOCKED,输出待补充清单2.3 编排 Skill 的 Output Contract
编排 Skill 的输出通常是子 Skill 输出的汇总:
## Output Contract### 必须输出- 四文件路径清单(design/spec/tasks/matrix)- Gate 闭合状态(OPEN/CLOSED)- 漂移风险声明(局部刷新场景)### 不得输出- 不得宣称 Gate 已闭合但四文件不完整- 不得静默修改子 Skill 未授权修改的文件2.4 编排 Skill 的 Checkpoints
编排 Skill 需要额外关注子 Skill 协调的 Checkpoints:
## Checkpoints### 子 Skill 调用前- 验证输入满足子 Skill Input Contract### 子 Skill 调用后- 验证子 Skill 输出满足子 Skill Output Contract- 验证未出现子 Skill 未授权的副作用### 汇总阶段- 验证四文件一致性- 验证 Gate 状态准确2.5 编排 Skill 示例骨架
---name: pm-md-to-openspec-pipelinepurpose: PM需求文档 → OpenSpec四文件编排layer: L2sub_skills: - spec-generator - reconciler---## When to Activate- 用户要求将 PM MD 转化为 OpenSpec 四文件- 用户要求局部刷新四文件## When NOT to Use- 只要单文件 → 转子 Skill- 无 PM MD 且不补充 → BLOCKED## Input Contract- 必填:PM MD 路径- 可选:现有四文件路径(局部刷新)## Workflow1. Read 子 Skill `spec-generator`,输入 PM MD,输出 design.md + spec.md2. Read 子 Skill `reconciler`,输入 spec.md,输出 field-matrix.md + tasks.md3. 汇总四文件,检查 Gate 闭合状态4. 输出最终报告## Output Contract- 必须输出四文件路径清单 + Gate 状态- 不得宣称 Gate 已闭合但四文件不完整## Checkpoints- 子 Skill 调用前:验证输入满足子 Skill Contract- 子 Skill 调用后:验证输出满足子 Skill Contract- 汇总阶段:验证四文件一致性§3 编排的 Eval 设计
3.1 编排 Eval ≠ 单体 Eval
| 测什么 | 过程 | |
| grader 类型 | trajectory | |
| expected 内容 | ||
| must_not 内容 |
3.2 trajectory Grader:测过程,不是测结果
trajectory Grader 专门验证编排 Skill 的调用轨迹:
| 是否 Read 子 Skill | |
| 调用顺序是否正确 | |
| 是否跳过闸门 |
数据来源:
•Agent trace(对话日志)
•Skill 使用观察(自报)
•编排 Skill 输出中的子 Skill 调用记录
3.3 编排 Eval 示例:pipeline-002
{"id":"pipeline-002","name":"must-read-two-sub-skills","type":"regression","prompt":"将 pm-requests/feature-123.md 转化为 OpenSpec 四文件。","expected":["必须 Read 子 Skill spec-generator","必须 Read 子 Skill reconciler","必须按顺序:先 spec-generator 后 reconciler","必须输出四文件路径清单"],"must_not":["不得跳过 spec-generator 直接调用 reconciler","不得未 Read 子 Skill 就输出四文件","不得静默生成文件而不调用子 Skill"],"grader":"trajectory","risk":"high","source":"input_contract"}3.4 编排 Eval 示例:pipeline-003(闸门验证)
{"id":"pipeline-003","name":"gate-a-before-b","type":"regression","prompt":"局部刷新 field-matrix.md,但不提供现有 design/spec/tasks 路径。","expected":["必须提示用户提供现有四文件路径","必须输出漂移风险声明","不得宣称 Gate 已闭合"],"must_not":["不得静默修改 design/spec/tasks","不得跳过漂移风险说明"],"grader":"structure+trajectory","risk":"high","source":"real_usage"}3.5 编排 Eval 的 baseline 跑法
编排 Eval 的 baseline 需要额外记录:
| 子 Skill 调用轨迹 | |
| 四文件生成情况 | |
| Gate 状态准确性 |
results.tsv 编编排版:
eval_id grader pass sub_skill_1_read sub_skill_2_read order_correct gate_statuspipeline-002 trajectory ✅ ✅ ✅ ✅ -pipeline-003 structure+trajectory ❌ ✅ ✅ ❌ OPEN误判CLOSED§4 编排陷阱
4.1 子 Skill 版本漂移
问题:编排 Skill 调用子 Skill,但子 Skill 更新后契约变化,编排 Skill 未同步更新。
案例:
spec-generator v1.0 输出:design.md + spec.mdspec-generator v2.0 输出:design.md + spec.md + draft-tasks.md(新增)编排 Skill pipeline 未更新,未处理 draft-tasks.md应对:
•编排 Skill 的 SKILL.md 记录子 Skill 版本
•子 Skill 更新时,编排 Skill 需重新 baseline ,并对准新标准
•Eval 增加 sub_skill_version 检查项
4.2 契约传递断裂
问题:编排 Skill 汇总时,未传递子 Skill 的契约约束。
案例:
子 Skill spec-generator 输出 must_not:不得宣称规格已定稿编排 Skill pipeline 汇总时,未继承此约束,宣称 Gate 已闭合应对:
•编排 Skill 的 Output Contract 继承子 Skill 的 must_not
•Checkpoints 增加"子 Skill 契约继承"检查
•Eval 增加"契约继承一致性"检查项
4.3 过度编排:编排层变成新单体
问题:编排 Skill 职责膨胀,变成新的单体 Skill。
案例:
编排 Skill pipeline 最初只协调两个子 Skill后来增加:规格校验、字段映射、任务拆分、风险评估最终 SKILL.md > 200 行,改不动应对:
•编排 Skill SKILL.md ≤ 80 行(不含子 Skill 内容)
•编排 Skill 只负责分配、协调、汇总 (核心),不做具体事
•发现膨胀 → 抽新原子 Skill
4.4 陷阱速查表
| 版本漂移 | ||
| 契约断裂 | ||
| 过度编排 | ||
| 隐式调用 |
§5 实战:从单体到编排的三步迁移
5.1 Step 1:识别可抽原子 Skill
信号识别:
| Workflow > 50 行 | ||
| 多个独立输出 | ||
| 可复用流程 |
案例:审稿 Skill 的 Workflow
## Workflow(原始单体,80行)1. 读取文章正文2. 五维评分(结构/可读性/CTA/合规/技术准确)3. 输出评分报告4. 检查配图合规5. 输出配图清单6. 汇总评审结果拆分:
•抽 article-reviewer:步骤 1–3
•抽 image-reviewer:步骤 4–5
•编排 wechat-review-pipeline:步骤 6(汇总)
5.2 Step 2:写原子 Skill 的契约
原子 Skill 必须定义清晰的 Input/Output Contract (输入与输出):
article-reviewer 契约:
## Input Contract- 必填:文章正文路径- 缺失 → BLOCKED## Output Contract- 必须输出:五维评分表 + P0/P1/P2 清单 + 复评目标- 不得输出:不得宣称通过但评分 <9.0image-reviewer 契约:
## Input Contract- 必填:文章正文路径(提取配图)- 缺失 → BLOCKED## Output Contract- 必须输出:配图清单 + 合规判定- 不得输出:不得漏审配图5.3 Step 3:写编排 Skill + trajectory Eval
编排 Skill Workflow:
## Workflow1. 并行执行: - Read 子 Skill `article-reviewer`,输出评分报告 - Read 子 Skill `image-reviewer`,输出配图清单2. 汇总两份报告,输出综合评审结果trajectory Eval:
{"id":"review-pipeline-001","name":"parallel-review-both-skills","type":"regression","prompt":"审稿 articles/demo.md,同时审配图。","expected":["必须 Read 子 Skill article-reviewer","必须 Read 子 Skill image-reviewer","必须输出汇总评审结果"],"must_not":["不得只审稿不审配图","不得只审配图不审稿"],"grader":"trajectory","risk":"high","source":"input_contract"}5.4 三步迁移 Checklist
| 1 识别 | ||
| 2 契约 | ||
| 3 编排 |
§6 编排模式的 Workflows 动态实现
Claude Code Dynamic Workflows 是编排模式的动态实现载体——将静态编排规则变成可执行的 JavaScript 脚本。
6.1 Workflows 与编排的关系
| 载体 | ||
| 执行 | ||
| 中间结果 | ||
| 可复现性 | ||
| 规模上限 | 数十到数百 agents |
核心价值:Workflows 将"计划"从 Claude 的 context window 移到脚本中——防止 Goal drift(多次 compaction 后目标漂移)。
6.2 串行编排的 Workflows 实现
// workflows/serial-pipeline.jsasyncfunctionserialPipeline(pmMdPath) {// Phase 1: Read spec-generator 子 Skillconst specResult = awaitrunAgent({name: "spec-generator",prompt: `Read ${pmMdPath},生成 design.md + spec.md`,tools: ["Read", "Write"],model: "sonnet" });// Phase 2: Read reconciler 子 Skill(依赖 Phase 1 输出)const matrixResult = awaitrunAgent({name: "reconciler",prompt: `Read ${specResult.specPath},生成 field-matrix.md + tasks.md`,tools: ["Read", "Write"],model: "sonnet" });// Phase 3: 汇总return {files: [specResult.designPath, specResult.specPath, matrixResult.matrixPath, matrixResult.tasksPath],gateStatus: checkGateClosure([specResult, matrixResult]) };}// 传入 args(用户输入)module.exports = serialPipeline(args.pmMdPath);关键:runAgent 依次执行,Phase 2 依赖 Phase 1 结果——实现串行编排。
6.3 并行编排的 Workflows 实现
// workflows/parallel-review.jsasyncfunctionparallelReview(articlePath) {// 并行 spawn 两个 agentconst [articleResult, imageResult] = awaitPromise.all([runAgent({name: "article-reviewer",prompt: `Read ${articlePath},输出五维评分报告`,tools: ["Read"],model: "sonnet" }),runAgent({name: "image-reviewer",prompt: `Read ${articlePath},提取配图,输出合规清单`,tools: ["Read"],model: "haiku" }) ]);// 汇总两份报告returnsynthesizeResults([articleResult, imageResult]);}module.exports = parallelReview(args.articlePath);关键:Promise.all 并行执行——实现并行编排。
6.4 条件分支的 Workflows 实现
// workflows/conditional-route.jsasyncfunctionconditionalRoute(articlePath, articleStatus) {// Classify-and-act 模式let result;if (articleStatus === "draft") { result = awaitrunAgent({name: "article-reviewer",prompt: `Read ${articlePath},输出评分报告`,tools: ["Read"],model: "sonnet" }); } elseif (articleStatus === "final") { result = awaitrunAgent({name: "compliance-checker",prompt: `Read ${articlePath},检查合规`,tools: ["Read"],model: "sonnet" }); } elseif (articleStatus === "published") { result = awaitrunAgent({name: "update-optimizer",prompt: `Read ${articlePath},建议更新优化`,tools: ["Read"],model: "haiku" }); }return result;}module.exports = conditionalRoute(args.articlePath, args.status);关键:JavaScript 条件分支实现路由——实现条件编排。
6.5 Workflows 与 Skill 的配合
Workflows 可以保存到 Skill 包中:
.claude/skills/wechat-review-pipeline/ ├── SKILL.md # 静态知识:触发条件、契约 ├── references/ │ ├── scoring-rubric.md │ └── output-contract.md ├── evals/ │ └── evals.json # trajectory Eval └── workflows/ # ← 新增目录 ├── parallel-review.js └── conditional-route.jsSKILL.md 引用 Workflows:
## Dynamic Workflows本 Skill 包含以下动态编排脚本:-`workflows/parallel-review.js`:并行审稿+审配图-`workflows/conditional-route.js`:依状态路由调用方式:- 用户说「审稿」→ Claude 选择合适 workflow 执行- 用户说「用并行 workflow 审稿」→ 执行 parallel-review.js6.6 trajectory Eval 验证 Workflows 执行
Workflows 执行过程可被 trajectory Eval 验证:
| 是否 Read 子 Skill | runAgent({name: "子Skill名"}) |
| 执行顺序 | |
| 是否并行 |
pipeline-002 trajectory Eval 示例:
{"id":"pipeline-002","name":"serial-workflow-order","type":"regression","prompt":"用 workflows/serial-pipeline.js 处理 pm-requests/feature-123.md","expected":["必须先 runAgent spec-generator","必须后 runAgent reconciler","必须汇总四文件"],"must_not":["不得跳过 spec-generator 直接执行 reconciler"],"grader":"trajectory","risk":"high","source":"workflow_contract"}6.7 Workflows 使用场景速查表
| 串行编排 | await runAgent() | |
| 并行编排 | Promise.all([]) | |
| 条件编排 | if/else 路由 | |
| 循环直到完成 | while (!condition) |
§7 FAQ + 灵魂四问
FAQ
| 编排 Skill 必须显式声明 Read? | |
| 子 Skill 版本如何管理? | |
| 编排 Eval 只测过程? | |
| 并行编排如何验证? | |
| 编排 Skill SKILL.md 行数上限? | |
| Workflows 与 Skill 的关系? | workflows/ 目录 |
| Workflows 解决什么问题? |
灵魂四问
1.拆得够不够? 你的 Workflow 里,是否有可以复用、独立验证的原子子流程?
2.管线通不通? 子 Skill 的“红线约束”有没有原封不动地传递给编排层?
3.边界清不清? 编排层有没有超过 80 行,抢了子 Skill 的具体执行工作?
4.流程稳不稳? 当任务变复杂时,你有没有用 trajectory Eval 甚至 Workflows 脚本 来防止 AI“遗忘步骤”?
写在最后:编排的本质,不是「全能」而是「连接」
很多开发者刚接触编排时,会下意识地把编排 Skill 写成另一个巨型单体——觉得既然要协调多个任务,那干脆把所有逻辑都写在一起省事。
但这恰恰违背了编排的初衷。
编排的核心不在于“做更多事”,而在于“更清晰地分派事”。
这篇文章我们聊了四件事:
1.拆分逻辑:当一个 Skill 超过 150 行、开始难以维护时,就是拆分的信号。把它拆成各司其职的原子 Skill,让编排层回归“指挥官”的角色。
2.显式契约:在 SKILL.md 里必须显式声明 Read 子 Skill。这不是形式主义,而是为了让后续的 trajectory Eval 有据可查,验证 Agent 有没有按流程“走直线”。
3.过程验证:单体看结果,编排看过程。如果你只检查最终输出,往往会忽略掉 Agent 跳过关键步骤、或者顺序颠倒的隐患。
4.动态执行:随着任务复杂度提升,静态的 Markdown 可能会遇到记忆瓶颈。引入 Claude Code 的 Dynamic Workflows,用 JavaScript 脚本把流程固化下来,是解决“目标漂移”的终极手段。
编排能力的强弱,往往决定了一个 AI 工程师的上限。
当你不再试图用一个 Prompt 解决所有问题,而是开始思考:
“这个环节能不能抽出来复用?”“这几个步骤能不能并行?”“如果这一步失败,流程该怎么回退?”
这个时候,你就已经从“写提示词的人”,进化成了“设计系统的人”。
夜雨聆风