2026-08-24 · 11 min read

写流程式 Skill 的最佳范式

流程式 Claude Code skill 的最佳范式——把状态从模型上下文搬到文件,router 精简、脚本固化、统一模板、分层护栏、密钥不进源码,配一个真实 skill 作贯穿示例。

Claude CodeSkill工程实践

用 Claude Code skill 串起一个多阶段、跨步骤、还要反复迭代的基础设施创建流程(建 appkey、建 bucket、建库、注册……)后,我想把这套写法沉淀下来。本文聚焦"流程式 skill"这一品类,观点先行,再用一个真实 skill 作贯穿示例。

这套写法不是凭空总结的,而是被坑出来的。在美团实习时,我要用 Claude Code skill 编排一整套 MT-Memory 集群的创建流程,跨五六个阶段、还要反复迭代。一开始我用的是导师留下的 skill,结果连踩三个坑:

  1. 模型经常遗忘 — 跑到第四步时,第二步产出的那个 sk-xxx 配置值已经记不准,要么错填、要么重新生成一个,配置文件动不动就被漏掉。
  2. skill 读起来极慢 — 所有阶段全塞在一个大文档里,每次模型都要把整份文档读进上下文,又慢又占额度。
  3. 脚本每次临时现写 — 推导命名、回填配置、转义密码这些"每次都一样"的活,模型每次都现写一段脚本,而临时脚本时不时就有 bug;一旦出错还会刷一屏日志灌进上下文,既占额度又把真正要的关键值埋没掉。

这三个坑逼出来的解法——状态外置、router 精简、脚本固化——正是下面六条范式里最核心的三条;其余几条是配套的护栏。

贯穿示例:mt-memory-cluster-creator——一个编排 0~5 阶段创建 MT-Memory 集群的 skill。

观点先行:流程式 skill 的最佳范式

一句话:把状态从模型上下文里搬出来、落到文件,其余都是围绕它的配套。

  1. 状态外置,不靠记忆 — 多阶段流程里,参数和各步产出一律落到外部文件(JSON),不靠上下文记住。上下文会遗忘、会被压缩、跨会话会丢;文件不会。
  2. router 精简,细节按需加载 — SKILL.md 只做编排和路由(<500 行);每阶段的操作细节进 reference,触发时才读。
  3. 脚本固化重复多步动作 — 推导命名、回填配置、密码编码这种"每次都一样"的活打成脚本,不交给模型每次现写。
  4. step 文档模板统一 — 入口条件→认证→操作→出口条件→回填→错误处理,让每个阶段可独立加载、独立执行。
  5. 分层确认护栏 — test/prod/破坏性三档,讲理由不堆死规则。
  6. 密钥只在 ignore 文件 — 源码里一律读、不硬编码。

下面逐条展开,最后给一张可带走的自检清单。

什么是流程式 skill,何时该用

先有个判别式,免得什么需求都往流程式里塞:

  • 纯事实(技术栈、命名约定、架构说明)→ 进 CLAUDE.md,别做成 skill。
  • 单步动作(一条命令、一个格式化)→ 普通 skill 即可,没必要编排。
  • 多阶段、有顺序、跨步骤要传状态 → 才用流程式 skill。

判别式就一条:流程的"阶段间有状态传递"。建集群这件事,step-2 产出的 embedding key 要给 step-5 注册用,step-0 推导的 srv 要给 step-1/3 用——这种跨步传值,就是流程式 skill 的典型信号。

骨架与 state 文件:为什么必须落到 JSON

这是整套范式里最反直觉、也最关键的一条。

直觉上,模型在跑流程时,把上一步的产出"记在脑子里"带到下一步最省事。但不能信任上下文记忆

  • 长流程会遗忘:跑完 step-1 建 appkey、step-2 建 key、step-3 建 bucket,到 step-4 时模型对 step-2 那个 sk-xxx 的精确值已经没把握,容易错填或重新生成一个。
  • 上下文会被压缩:对话长了,早期步骤的细节被摘要掉,精确值就丢了。
  • 跨会话彻底丢失:流程常常跑不完就要中断,第二天再来,上下文早没了。

所以这个 skill 用一个贯穿全程的状态文件 clusters/{name}.json

{
  "name": "dumbo-agent",
  "env": "prod",
  "pg_instance": "dumbo",
  "deploy_appkey": "com.sankuai.contextdb.inf.dumboagent",
  "config": {
    "EMBEDDING_API_KEY": "sk-LOTHq...",   // step-2 回填
    "S3_BUCKET": "mtmemory-dumbo-agent",   // step-3 回填
    "PG_HOST": "dumbocontextdb-rw.pg...",  // step-4 回填
    ...
  }
}

每个 step 产出后回填到 config,下一步要值就 read_file 重新拿确定值。好处不只是结构整洁,而是:流程敢中断、敢分多次跑完、敢跨会话恢复——因为状态在地上,不在模型的脑子里。

次论点:回填还顺带解决了"下一步要用的产出"的传递。step-2 的 key 值要给 step-5 用,与其让模型在脑子里搬运一串易错字符,不如落盘后读。

让流程跑顺的三个模式

a) 脚本当"推导+回填"引擎 —— derive_cluster_params.py 把三件事打包:按 name 推导所有衍生名(srv/appkey/bucket/db)、生成随机 token、--update-config 时对密码自动 URL 编码。模型只需要跑一条命令,不必每步手算名字、手填 JSON、手转义 #/|

一句提示:脚本打包默认值时,密钥别跟着进源码——读 .env,别硬编码。这条下面"密钥"再说。

另一句提示:脚本的 stdout 会原样进模型上下文,所以输出要精简——只返回最小必要的结构化信息(最终推导的名字、一个回填确认、或一句 ok),中间过程日志写到文件别打到 stdout。临时脚本最容易翻车的地方就是出错时刷一屏 traceback,既占额度又把关键值埋没。固化脚本不只是固化动作,也固化输出契约。

b) 统一的 step 文档模板 —— 每个阶段 reference 都是这个结构:

入口条件 → 认证 → 操作(curl/psql)→ 出口条件 → 回填 → 错误处理

模板统一的好处:每个阶段可独立加载、独立执行。用户只说"建个 bucket",模型只加载 step-3 跑这一段,不必把整个流程塞进上下文。错误处理表(返回码→可能原因)也固定,每步都有兜底。

c) 路由规则表 —— SKILL.md 顶部一张关键词→step 的映射:

"创建 appkey" / "服务标识"   → step-1
"创建 bucket" / "s3"         → step-3
"注册集群"                   → step-5
"创建集群" / "新建集群"      → 从 step-0 顺序跑

支持单步跳转,不必每次跑全流程。这是"按需加载"能落地的前提:先路由到对的 reference,再读它。

分层确认护栏

不要写 ALWAYS 二次确认 这种死规则——模型会要么过度谨慎(每步都问)要么漏判。改成讲理由的三档:

  • test 环境:允许用户一次确认后顺序跑完多阶段("把 0~4 都跑完")。
  • prod 环境:必须逐步确认,每个阶段单独拿到确认才执行。
  • 破坏性操作(DROP/DELETE/取消任务):无论哪个环境,单独二次确认。

讲理由比堆 ALWAYS 更有效,因为模型能顺着"为什么"判断边界情形(比如一个只读 SELECT 就不必触发二次确认)。

还有个配套习惯:把无法推导的输入前置到 step-0 集中收集。建集群时 FRIDAY_APP_ID 这种字段模型推导不出来,必须在 step-0 跟用户要。否则会一路漏到 step-5 才发现——那时前面四步已经跑完,补这个值得回头改 JSON。

自检清单

写完一个流程式 skill,对照这张表过一遍:

  • SKILL.md 是否 <500 行,只做编排和路由?
  • 有没有一个贯穿全程的 state 文件承载参数与各步产出?
  • 每步产出是否落盘回填,而非靠上下文记忆带到下一步?
  • step 文档是否用统一模板(入口/认证/操作/出口/回填/错误)?
  • 是否有路由表,支持单步跳转而不必跑全流程?
  • 确认护栏是否分层(test/prod/破坏性)并讲理由?
  • 无法推导的输入是否在流程起点集中收集?
  • 密钥是否只在 gitignore 的文件里,源码一律读取不硬编码?
  • description 是否覆盖 skill 的全部能力(包括后来新增的)?
  • 推导规则是否与既有数据一致,正文与表格是否一致?

最后两条是流程式 skill 作为"活文档"的维护成本——能力会生长,新增一个 step 要同步 description、路由表、流程表、step 文档四处。把这张表当回归检查,每次扩能力都过一遍,就不会让 skill 慢慢和自己打架。