多步骤复合Skill设计与编排

设计强大的多步骤Skill

核心概念:复合Skill(Composite Skill)是将多个原子操作编排成一个可复用工作流的Skill类型。它通过定义步骤序列、数据传递规则和异常处理策略,将复杂任务拆解为可管理、可测试、可观测的子步骤。掌握复合Skill的设计与编排是构建可靠自动化工作流的核心能力。

一、复合Skill的设计模式

复合Skill的核心价值在于将多个原子操作组合成一个有意义的业务流程。不同的任务结构需要不同的编排模式。以下是四种最常用的设计模式:

串行模式 (Sequential)
步骤依次执行,前一步的输出作为后一步的输入。适用于有明确依赖关系的任务,如"先格式化代码,再运行测试"。串行模式是最直观、最容易调试的编排方式。
并行模式 (Parallel)
多个步骤同时执行,互不依赖。适用于无依赖关系的独立任务,如"同时运行单元测试和静态分析"。可显著缩短总执行时间,但需注意资源竞争问题。
条件分支模式 (Conditional)
根据上一步的执行结果或输出值,动态选择后续执行路径。适用于决策型工作流,如"如果测试通过则部署,否则发送告警"。需要提前定义好所有分支路径。
循环模式 (Loop/Iteration)
对多个项目重复执行相同操作,典型场景包括"批量处理文件"或"遍历目录中的所有图片并压缩"。循环模式需要定义迭代变量和终止条件以避免无限循环。
设计建议:实际项目中往往是多种模式的组合。例如,"批量处理文件"的内部是循环模式,每个文件的处理流程内部是串行模式,而不同文件之间可以并行执行。建议先在纸上画出工作流图,再确定每种模式的具体边界。

串行模式详解

串行模式是最基础也最常用的编排方式。每个步骤按顺序执行,上一步的成功是下一步的前提。典型结构如下:

Step 1: 读取配置文件 | v Step 2: 验证配置有效性 | v Step 3: 根据配置执行操作 | v Step 4: 输出执行结果

串行模式的优势在于简单可控——每个步骤的输入来自上一步的输出,数据流清晰,错误定位容易。缺点是总执行时间等于所有步骤耗时之和,各步骤间无法并行加速。

并行模式详解

并行模式的关键在于识别哪些步骤之间不存在数据依赖。使用并行模式时,需要关注以下要点:

条件分支模式详解

条件分支使复合Skill具备决策能力。常见的条件类型包括:

二、步骤间数据传递

复合Skill的各个步骤之间需要共享数据和上下文信息。数据传递机制的设计直接影响Skill的灵活性和可维护性。以下是四种主要的数据传递方式:

1. 引用上一步结果:{{OUTPUT:stepN}}

最常见的传递方式,通过模板语法引用前置步骤的输出。这种方式直观且便于追踪数据来源。

# 示例:格式化后对代码运行静态分析 Step 1: 运行代码格式化工具 command: npx prettier --write src/ Step 2: 对格式化后的代码运行 ESLint command: npx eslint {{OUTPUT:step1}} --format json # {{OUTPUT:step1}} 会被替换为 step1 输出的文件列表

2. 临时变量存储和传递

在工作流内部使用命名变量,跨步骤共享中间数据。适用于需要在多个步骤中复用同一数据的场景。

# 使用临时变量传递数据 variables: TARGET_DIR: "src/components" OUTPUT_DIR: "dist" steps: - name: 编译组件 command: npx tsc {{TARGET_DIR}} --outDir {{OUTPUT_DIR}} - name: 复制资源文件 command: cp -r {{TARGET_DIR}}/assets {{OUTPUT_DIR}}/assets - name: 打包输出 command: tar -czf build.tar.gz {{OUTPUT_DIR}}

3. 通过文件系统传递

对于大数据量或二进制数据,将中间结果写入文件,后续步骤读取该文件。这种方式不受内存限制,且便于调试(可以检查中间文件内容)。

# 通过文件传递大数据 Step 1: 导出数据库 command: pg_dump mydb > /tmp/db_backup.sql Step 2: 压缩备份 command: gzip /tmp/db_backup.sql Step 3: 上传到云存储 command: aws s3 cp /tmp/db_backup.sql.gz s3://my-backup-bucket/
注意:文件系统传递方式需要关注文件命名冲突问题。建议为每个执行实例生成唯一的工作目录(如使用时间戳或UUID命名),防止并发执行时出现文件覆盖。

4. 结构化数据(JSON)提取与传递

当步骤输出为JSON格式时,可以使用查询语法精确提取所需字段。这种方式特别适合与API交互的场景。

# 从API响应中提取数据并传递给后续步骤 Step 1: 创建GitHub Issue command: gh issue create --title "Bug report" --body "Description" --json number,url # 输出: {"number": 42, "url": "https://github.com/.../issues/42"} Step 2: 在Issue上添加标签 command: gh issue edit {{OUTPUT:step1.number}} --add-label "bug" # 使用 .number 提取JSON中的数值字段 Step 3: 发送通知 command: curl -X POST $WEBHOOK_URL \ -H "Content-Type: application/json" \ -d '{"issue_url": "{{OUTPUT:step1.url}}"}' # 使用 .url 提取JSON中的URL字段
最佳实践:选择数据传递方式时,遵循以下优先级:小数据用变量引用 → 结构化数据用JSON提取 → 大数据用文件系统。避免在多个步骤间传递过于庞大的数据,保持每个步骤的职责单一和清晰。
传递方式 适用场景 数据量级 优势 局限
引用({{OUTPUT}}) 小数据引用 KB级 直观,可追踪 数据量受限
临时变量 配置共享 KB级 跨步骤复用 需要显式声明
文件系统 大数据/二进制 MB~GB级 无内存限制 需处理文件冲突
JSON提取 API响应 KB级 精确提取 依赖JSON结构

三、错误处理和回滚

复合Skill的执行过程可能遇到各种异常情况:某步骤执行失败、输入数据不符合预期、外部服务不可用等。健壮的错误处理机制是复合Skill生产级部署的必要条件。

前置条件检查

在Skill开始执行前,验证所有前提条件是否满足。这可以避免执行到一半才发现环境不满足要求,浪费时间和资源。

# 前置条件检查示例 preconditions: - check: 命令是否存在 command: which node error_message: "Node.js 未安装,请先安装 Node.js" - check: 目录是否存在 command: test -d src/ error_message: "src/ 目录不存在" - check: 环境变量是否设置 command: test -n "$GITHUB_TOKEN" error_message: "GITHUB_TOKEN 环境变量未设置"

步骤级错误捕获与处理

为每个步骤或步骤组配置独立的错误处理策略,而不是在整个Skill级别统一处理。这样可以实现更精细的异常管理。

# 步骤级错误处理示例 steps: - name: 运行测试 command: npm test on_error: - action: retry max_retries: 3 retry_interval: 5s 条件:仅网络相关错误重试 - action: notify channel: slack message: "测试阶段失败,需要人工介入" - action: continue # 或 fail(默认) - name: 部署到生产 command: npm run deploy on_error: - action: rollback target: "上一版本"
重要:重试策略需要谨慎设计。对于幂等操作(如读取数据)可以安全重试;对于非幂等操作(如创建资源),需要先撤销已执行的操作再重试,否则可能导致重复创建。建议设置最大重试次数,避免无限重试导致资源耗尽。

部分成功状态的处理

在并行模式或批量处理场景中,可能出现部分步骤成功、部分失败的情况。需要明确的策略来应对这种部分成功状态。

回滚操作的设计

对于修改系统状态的操作,必须设计对应的回滚(Rollback)机制。回滚操作应该是幂等的——多次执行不会产生副作用。

# 带回滚操作的复合Skill示例 steps: - name: 停止旧服务 command: systemctl stop myapp rollback: command: systemctl start myapp condition: 始终执行 - name: 部署新版本 command: cp -r /tmp/new-version /opt/myapp/ rollback: command: cp -r /opt/myapp/backup /opt/myapp/ condition: 当此步骤成功时才执行 - name: 启动新服务 command: systemctl start myapp rollback: command: systemctl stop myapp condition: 始终执行 - name: 健康检查 command: curl -f http://localhost:8080/health rollback: command: | systemctl stop myapp cp -r /opt/myapp/backup /opt/myapp/ systemctl start myapp condition: 始终执行

回滚设计原则:①每个可能失败的步骤都应该有对应的回滚操作;②回滚操作必须是幂等的;③回滚的执行顺序应该与正向操作的顺序相反(LIFO,后进先出);④回滚本身也可能失败,需要记录失败日志并人工介入;⑤在执行任何修改前,先创建备份。

四、实用复合Skill示例

以下三个完整示例展示了复合Skill在实际开发工作流中的应用。这些示例可以直接作为模板使用,根据项目需求进行调整。

示例一:完整代码提交流程

一个标准化的代码提交流程,在提交前自动完成格式化、lint检查和测试,确保进入版本库的代码质量。

Step 1: 代码格式化 (Prettier) | v Step 2: 静态检查 (ESLint) | v 条件判断: Lint是否通过? ├── 是 ──→ Step 3: 运行测试 │ | │ v │ 条件判断: 测试是否通过? │ ├── 是 ──→ Step 4: Git提交 │ └── 否 ──→ 输出测试失败报告 └── 否 ──→ 输出Lint错误并中止
# 完整代码提交复合Skill name: "安全提交代码" preconditions: - command: git diff --stat error_message: "没有需要提交的更改" steps: - name: 格式化代码 command: npx prettier --write "src/**/*.{js,ts,jsx,tsx}" description: 使用Prettier统一代码风格 - name: 静态检查 command: npx eslint "src/**/*.{js,ts,jsx,tsx}" --max-warnings 0 description: ESLint检查代码质量 on_failure: action: abort message: "ESLint检查未通过,请手动修复后重试" - name: 运行测试 command: npm run test -- --coverage description: 运行单元测试并生成覆盖率报告 on_failure: action: abort message: "测试未通过,请检查测试失败原因" - name: Git提交 command: | git add . git commit -m "{{commit_message}}" description: 提交代码到本地仓库 on_success: message: "代码提交成功!" summary: - 格式化文件数: {{OUTPUT:step1.file_count}} - ESLint问题数: {{OUTPUT:step2.issue_count}} - 测试覆盖率: {{OUTPUT:step3.coverage}} - 提交哈希: {{OUTPUT:step4.commit_hash}}

示例二:项目初始化

从头初始化一个新项目,自动完成目录创建、配置文件生成、Git初始化和依赖安装的完整流程。

# 新项目初始化复合Skill name: "初始化新项目" variables: PROJECT_NAME: "{{project_name}}" PROJECT_TYPE: "{{project_type}}" # node, python, go 等 steps: - name: 创建项目目录结构 command: | mkdir -p {{PROJECT_NAME}}/src mkdir -p {{PROJECT_NAME}}/tests mkdir -p {{PROJECT_NAME}}/docs mkdir -p {{PROJECT_NAME}}/scripts description: 创建标准项目目录结构 - name: 生成配置文件 command: | case {{PROJECT_TYPE}} in node) cd {{PROJECT_NAME}} && npm init -y npm install --save-dev jest eslint prettier ;; python) cd {{PROJECT_NAME}} && python -m venv venv echo "pytest\nblack\nflake8" > requirements-dev.txt ;; go) cd {{PROJECT_NAME}} && go mod init {{PROJECT_NAME}} ;; esac description: 根据项目类型生成初始配置文件 - name: 初始化Git仓库 command: | cd {{PROJECT_NAME}} git init echo "node_modules/\nvenv/\n.env\n*.pyc\n__pycache__/" > .gitignore git add . git commit -m "初始项目结构" description: 初始化Git仓库并完成首次提交 - name: 输出项目摘要 command: | echo "=================================" echo "项目初始化完成!" echo "项目名称: {{PROJECT_NAME}}" echo "项目路径: $(pwd)/{{PROJECT_NAME}}" echo "项目类型: {{PROJECT_TYPE}}" echo "=================================" description: 输出初始化结果摘要
扩展建议:这个基础模板可以根据团队规范进一步扩展——添加CI配置文件(如.github/workflows/ci.yml)、添加Dockerfile和docker-compose.yml、创建README模板、配置commitlint和husky等Git钩子、设置代码所有者(CODEOWNERS)等。

示例三:Bug修复工作流

自动化的Bug修复流程:分析问题、定位根因、生成修复代码、运行测试验证、提交变更并创建Pull Request。

# Bug修复复合Skill name: "自动化Bug修复流程" variables: BUG_ID: "{{bug_id}}" BUG_DESCRIPTION: "{{bug_description}}" preconditions: - command: git status --porcelain error_message: "工作区不干净,请先stash当前更改" steps: - name: 创建修复分支 command: | git checkout -b fix/{{BUG_ID}} description: 从主分支创建修复分支 - name: 分析问题根因 command: | echo "开始分析 Bug #{{BUG_ID}}: {{BUG_DESCRIPTION}}" # 执行日志分析、代码搜索等操作 # ... 具体分析逻辑 description: 分析Bug根因 - name: 生成修复代码 command: | # 根据分析结果生成修复代码 # ... 修复逻辑 description: 编写修复代码 on_failure: action: abort message: "无法自动生成修复,请手动修复" - name: 运行测试验证 command: | npm run test -- --related "{{OUTPUT:step3.changed_files}}" description: 运行相关测试验证修复 on_failure: action: rollback rollback_step: 2 - name: 提交修复并创建PR command: | git add . git commit -m "fix({{BUG_ID}}): {{BUG_DESCRIPTION}}" git push origin fix/{{BUG_ID}} gh pr create \ --title "修复 Bug #{{BUG_ID}}" \ --body "## 修复内容\n\n{{BUG_DESCRIPTION}}\n\n## 测试验证\n\n- [x] 单元测试通过\n- [x] 回归测试通过" \ --label "bug" description: 提交修复代码并创建Pull Request rollback: - name: 删除修复分支 command: | git checkout main git branch -D fix/{{BUG_ID}} condition: 任何步骤失败时执行

要点总结:设计复合Skill时,应始终遵循以下原则——①每个步骤职责单一,便于测试和复用;②明确定义步骤间的数据契约(输入/输出格式);③为关键路径设计错误处理和回滚策略;④使用有意义的步骤名称和描述,使工作流自文档化;⑤添加summary/summary步骤,提供执行结果的概览信息。

复合Skill的设计本质上是"关注点分离"思想在工作流层面的实践。一个设计良好的复合Skill就像一个可靠的高级员工——你告诉它"做什么",它自己知道"怎么做",遇到问题知道"怎么处理",做完了还能给你"汇报结果"。