ease ops - 自动化接入Skill 设计

2026/10/22 探索Ease Ops

# 前言

让 Cursor / Claude Code / CodeBuddy 里的 AI,通过一句话把"当前仓库"接进 ease-ops: 建项目、识别组件、插流水线、接配置和密钥。 这篇讲的核心是 Skill 本身怎么设计,以及它带来了什么收益。

# 起点:接入这件事,值不值得做一个 Skill?

对没接入过 DevOps 平台的人来说,"把仓库接进 ease-ops"是一条又长又碎的链路:项目、环境、仓库、组件、构建规格、配置模板、流水线插入,一环扣一环。熟练工在 web 向导里点半小时,中间填错任何一步都要回退重来。

而这件事的消费者恰恰是 AI 编码工具——它们最擅长处理"有明确流程的复杂任务"。问题只有一个:你敢不敢让 AI 碰生产平台的写接口?

ease-ops-onboard 的回答是:敢,但前提是 Skill 设计得当。Skill 不是"给 AI 的一段提示词",而是一份把权限、流程、安全全部写死的作业规程。下面看这份规程的四个设计支柱。


# 支柱一:五阶段工作流 —— 每阶段有"退出条件",不许跳步

Skill 把整个接入组织成五个阶段,每个阶段定义了动作和退出条件,没达标就不能进下一阶段:

阶段 AI 在做什么 人在做什么 退出条件
0 自检 whoami 版本比对、resolve_repo 判定模式 命中多项目时选一个 模式已定
1 探测 probe_repo + 本地读 go.mod / package.json 交叉验证 — 组件候选与配置清单生成
2 规划 写计划文件 → plan → 渲染四块摘要 显式确认 用户点头 + 风险逐条回填
3 执行 apply → 缺密钥引导去 intake 页面 → 轮询续跑 在浏览器里填密钥 applied 或有明确下一步
4 交接 写状态文件、给深链、列待复核清单 知道下一步找谁 无悬空 blocker

这个结构带来三个直接收益:

  • 可预期:无论用户的对话怎么绕,AI 永远沿同一状态机走,同一个仓库今天接、明天接,产出的拓扑一致;
  • 可恢复:阶段间通过计划文件(.ease-ops/onboarding.yaml)和状态文件(onboarding.json)衔接,对话中断、密钥没填、执行部分失败,回来都能从断点续跑,而不是从头再来;
  • 可审计:每个阶段的输入输出都是平台侧有记录的对象(plan_id、apply 结果、intake 状态),出了问题能回放。

值得强调的是阶段 0 的"数据路由"设计:不支持 slash command 的客户端(Trae、Windsurf 等),靠 Skill description + resolve_repo 的返回数据也能自动路由到正确场景(新接入 / 加项目 / 加组件)。入口可以有高有低,流程只有一条。

落到实际对话里,前两个阶段是这样的(真实走查的浓缩版):

你:把这个仓库接进 ease-ops

AI [阶段 0] 你是 hyman,skill 版本校验通过 ✔;git@github.com:acme/shop.git 未被任何项目使用 → new_project

AI [阶段 1] 平台探测:monorepo,2 个可独立构建单元 —— web/(Next.js → 建议 shop-web)、api/(Go 1.23 → 建议 shop-api);.env.example 发现 7 个 key,其中 2 个疑似密钥

AI [阶段 2] 计划已写入 .ease-ops/onboarding.yaml,四块摘要(仓库与项目 / 组件与构建 / 配置与密钥 / 流程插入)。缺 1 项密钥:prod/DB_PASSWORD。确认执行?

你:执行

AI [阶段 3] apply 完成 10/10 → 打开 intake 页面补密钥,轮询到 filled 后续跑

AI [阶段 4] 已写 .ease-ops/onboarding.json;项目与流水线深链、待复核清单就绪,下一步 /ease-ops:verify 触发一次构建并自动诊断

全程用户只说了三句话:一个请求、一次"执行"、一句"填好了"。

# 支柱二:三条硬规则 —— 把安全写成协议,而不是靠自觉

Skill 正文里最醒目的是三条任何阶段不得违反的硬规则:

  1. 没有 plan_id 不执行;blockers 非空不执行;风险项未逐条确认不执行;
  2. secret 永不进入 payload / 文件 / 对话,只走独立的 intake 页面;
  3. 用户确认必须是显式肯定,"看起来可以""嗯"不算。

三条规则落到形态上,各是这样一小段:

规则 1——plan 返回的风险项,必须逐条回填才许执行:

// plan_onboarding 返回
"acknowledge_required": [
  {"code": "shared_repo",
   "summary": "该 git 已被项目 payment 使用;共用会导致凭证、分支策略、产物互相牵连"}
]

// apply 前 payload 必须回填,否则 ack_missing 拒绝
"acknowledge": ["shared_repo"]
1
2
3
4
5
6
7
8

规则 2——secret 在 payload 里只许出现名字:

configs:
  - key: DB_PASSWORD
    scope: project
    secret: true        # 出现 values 即服务端硬错误 secret_in_payload
    required: [prod]
1
2
3
4
5

规则 3——确认必须是显式指令:

AI:  确认执行?
你:  看起来可以   → 不算,AI 停下来再次请求明确指令
你:  执行         → 算,进入 apply
1
2
3

这三条规则的巧妙之处在于:它们约束的不是平台,而是 AI 自己。平台侧本来就有校验兜底,但 Skill 把"什么情况下根本不该发起调用"前置到了对话层,效果是:

  • AI 拿不到密钥,也不需要拿到。整个对话里密钥只以"缺 1 项:prod/DB_PASSWORD"的形态出现——AI 知道缺什么,从不知道值是什么。用户填完回来说"填好了",AI 轮询状态继续。零暴露不是因为加密做得好,而是因为值的通道在 AI 的可达空间之外;
  • 人审过的计划就是被执行的计划。apply 时服务端按 payload 重算指纹,AI"顺手改一个字段"直接被打回重新走确认。防 AI 漂移不靠祈祷模型听话,靠机制;
  • 确认是可审计的动作。跨项目共用 git 这类风险,plan 会返回 acknowledge_required,用户不逐条点头就 apply 不了——把"知道风险"从口头承诺变成落库记录。

对用户的体感收益是:你不需要懂这个平台的所有细节,也敢让它替你做。这是 AI 操作生产系统和"玩具 demo"的分水岭。

# 支柱三:渐进披露的文档结构 —— 250 行正文 + 四件套按需读取

Skill 的交付物不是一段长提示词,而是一个分层的信息结构:

SKILL.md(≤250 行)        → 只放"路由与阶段":何时用、硬规则、五阶段表、各阶段判定逻辑
references/payload.md      → 字段铁律 + 完整 JSON Schema + 正反例 + 易错判断
references/errors.md       → 错误码表 + 逐码话术 + 处置总则 + 禁止行为
references/clients.md      → 5 客户端能力矩阵 + 配置片段 + 排障表
references/verify.md       → 触发方式 + 轮询节奏 + 失败自动诊断对照表
1
2
3
4
5

这是按"AI 怎么读文档"设计的:正文是给所有对话的常驻路由层,细节在真正需要时才加载(阶段 1 读 payload、失败时读 errors、阶段 0 读 clients、阶段 4 读 verify)。

收益 说明
Token 经济 常驻上下文只有 250 行,而不是把 60+ tool 的参数细节全塞进去
单一真相 SKILL.md 正文与设计文档一一对应,改错误话术只动 errors.md,不用重新对齐提示词
行为一致 AI 对未知错误的第一反应是查表(errors.md 逐码话术),而不是现场编一个处置方案
人类可读 新人想了解这个 Skill 能干什么,读 250 行正文就够,不用啃全量 schema

250 行正文里装的是什么,章节骨架一目了然(与 SKILL.md 文件一一对应):

## 何时用 / 何时不用
## 三条硬规则
## 五阶段与退出条件(表格)
## 阶段 0 的判定逻辑(resolve_repo 分支:0/1/≥2 命中)
## 阶段 1 的组件切分规则
## 阶段 2 的四块摘要模板
## 阶段 3 的 intake 与 resume
## 阶段 4 的交接四件套
## 失败处置(指向 references/errors.md)
1
2
3
4
5
6
7
8
9

注意最后几行:正文对 references 的引用点恰好落在四个阶段上——阶段 1 读 payload、失败时读 errors、阶段 0 读 clients、阶段 4 读 verify。正文负责"什么时候去查",references 负责"查什么"。

配套还有一条接口纪律贯穿始终:对外只出现逻辑名,永不出现平台资源 ID;未知字段严格报错。看一小段 payload 就能感受到这份"词汇表"有多窄:

repos:
  - key: shop
    credential_ref: platform:git-acme-ro   # 引用凭证,不是用户名密码
components:
  - code: shop-api
    repo_refs: [shop]                      # 按 key 指仓库,不重复贴 URL
    build:
      runtime: go-1.23                     # 逻辑名,不是 image_version_id
1
2
3
4
5
6
7
8

这让 AI 无法引用自己不认识的东西——它连犯错的语言都不具备。

# 支柱四:安装器即产品 —— npx @ease-ops/onboard init 十分钟上手

Skill 再好,接入成本高就没人用。所以 skill 目录本身同时是一个零依赖的 npm 包:

npx @ease-ops/onboard init
  → 选客户端 → 粘贴 MCP Key(或浏览器设备码)
  → 写 skill + references → 合并 MCP 配置 → whoami 连通性验证
1
2
3

跑起来是这样(示意):

$ npx @ease-ops/onboard init
? 选择客户端: Cursor
? 粘贴 MCP Key(隐藏输入): ********
✔ 写入 .cursor/skills/ease-ops-onboard/(SKILL.md + 4 个 references)
✔ 合并 .cursor/mcp.json(只动 ease-ops 条目,原有 server 与 4 空格缩进不变)
✔ 连通性验证: hyman / 可见 2 个项目

$ npx @ease-ops/onboard init        # 重跑
✔ unchanged                         # 幂等,不产生重复条目
1
2
3
4
5
6
7
8
9

设计上有几处克制值得学:

  • 多客户端差异被适配器吸收:Cursor / Claude Code / CodeBuddy / VS Code / Trae 五家的 skill 落位、MCP 配置格式、Key 注入能力(环境变量插值 / 输入框占位 / 只能明文)全部收敛在 5 个客户端适配器里,用户只回答一个问题:"你用什么编辑器";

  • 安全分级:不同客户端的 Key 注入能力分三档,安装器按档处理——

    // A 档(如 Cursor):写变量引用,Key 不进文件,配置可放心提交
    { "url": "https://console.../mcp",
      "headers": { "Authorization": "Bearer ${env:EASE_OPS_TOKEN}" } }
    
    // B 档(如 CodeBuddy):无插值能力,只能写明文
    //   → 安装器强制 chmod 600 + 自动补 gitignore 并用 git check-ignore 复查
    { "url": "https://console.../mcp",
      "headers": { "Authorization": "Bearer eops_xxxx" } }
    
    1
    2
    3
    4
    5
    6
    7
    8

    能写引用的(A/C 档)不含 secret,可放心提交;只能写明文的(B 档)被机制保证不会进版本库;

  • 工具宁可少做,不可做错:合并 JSON 配置只改自己的那一项、保留用户缩进和顶层键序;文件含注释就拒写并打印片段供手改;init 幂等(重跑输出 unchanged);remove 按客户端定向清理,不碰用户的工作目录状态;

  • 版本漂移有告警:whoami 返回 min_skill_version,服务端升级了 payload 格式,旧版 skill 会在阶段 0 被礼貌拦下并提示更新,而不是带着过期的理解去执行。

收益很直接:使用者从"读文档 + 手工配 5 个文件"变成"跑一条命令";维护者从"逐个用户排查 MCP 配置错误"变成"让用户跑一遍 doctor"。


# 抽几行 SKILL.md 原文:规则是怎么"驯"AI 的

上面四个支柱不是 PPT 上的架构词,它们最终都落在 SKILL.md 一行行的祈使句里。全文只有 198 行,抽几句最能体现设计功力的原文:

开篇先定权责:

你负责探测与推断,平台负责校验与执行,人负责选择、确认与填密钥。

违反任意一条(硬规则)视为本次任务失败。

一句话把三边界写进 AI 的角色认知,而"任务失败"四个字给硬规则上了刑罚——不是建议,是红线。

不让 AI 做"好心的加工":

把原样输出传给工具,不要自己改写 URL(归一化由服务端负责)。

连不上 / 401 / 工具列表为空:查排障表,不要自行改 MCP 配置后重试。

AI 的"顺手加工"恰恰是漂移的主要来源:自己规范化一下 URL、自己改改配置试试——每一步都是不可控分岔。这两行的哲学是:AI 只负责搬运事实,不负责修饰事实。

人说的话和代码冲突时,以代码为准:

用户说"它只是一个服务"但仓库里明显有前后端两份 → 以代码为准,列出两个候选并说明理由。

不是无条件听话,也不是无条件自作主张——冲突时把两边都摆上桌,把裁决权交还给人,并附上理由。

默认值取最保守的那一档:

密钥判定:key 命中 *_PASSWORD|*_TOKEN|*_SECRET|*_KEY|*_DSN|*_PRIVATE

test 只自动填非密默认值;prod 一律不填。

宁可漏填一个变量让人回来补,不可多填一个值碰了不该碰的密钥——不对称风险的不对称处理。

把含糊也当作信号处理:

逐条处理 acknowledge_required:每条都要用户明确回答;即使说"不用管"也要记为明确否定。

沉默不等于同意,"不用管"也不是同意——含糊回答被当作一种信号落库,而不是被 AI 乐观地解释成默许。

给 AI 的自愈能力设上限:

可修正的错误只允许在阶段 2 重跑 plan,最多一次。

连续两次 plan 失败 → 停下来向用户说明卡点,不要继续猜。

没有这一条,AI 会陷入"猜-报错-再猜"的循环把用户刷屏。允许失败,但不允许无限失败。

最后一道保险是否定式的清单:

不要做:不创建定制镜像;不创建环境(平台自动初始化);不修改既有流程拓扑;不在用户未提及部署时启用部署;不在 payload 里写平台内部 ID。

把能力边界写成"禁止清单"而不只是"允许清单",是因为 AI 对否定指令的遵循远好于对模糊授权的理解——说清楚"哪些能碰"不够,还要说清楚"哪些永远别碰"。

这些句子没有一个在描述平台功能,全部在约束 AI 自己的行为——这才是 Skill 的真正精华:它不是说明书,是一个写满了护栏的作业现场。


# 收益盘点

把整件事放在一起看,这个 Skill 换来的东西:

视角 之前 之后
开发者 web 向导点半小时,填错回退重来 一句话,AI 全程代办,人只做三次"点头"
平台 每次接入留下明文密钥的执行记录 协议层杜绝 secret 入 payload / 文件 / 对话
运维 "AI 把我流水线改坏了"无法追责 plan_id + 指纹 + acknowledge 回填,每一步可回放
维护者 提示词越长越失控,改一处崩全身 250 行正文 + 四件套 references,分层演进
推广 每个用户手工配置 MCP + skill npx init 一条命令,幂等可卸载

还有一个容易被忽略的复利:Skill 与 web 向导共用同一套 plan/apply 校验。向导服务不写代码的人,Skill 服务写代码的人,两条入口一套规则——平台不用维护两套语义,规则演进一次两边生效。

# 设计原则的取舍:不做什么

v1 的"明确不做清单"和正文一样长,几条代表性的:

  • 不做完整拓扑编辑——只承诺"追加一条并行分支 + 检出复用",精细编排回平台 orchestrator。Skill 的职责边界是"接入",不是"替代整个流水线编辑器";
  • 不做 Connector 统一抽象——目前只有 git/ssh 两个真实用例,没有第二个实现的抽象不做;
  • 不动现有向导——skill 只做新链路,旧向导的明文脱敏另立专项。范围收敛让 P0–P5 在几个迭代内全部落地;
  • 不自动创建定制镜像——会触发镜像构建,破坏 apply 的同步语义。宁可少一个功能,不坏一个契约。

这些"不做"共同指向一条原则:Skill 的能力边界要小于平台的真实能力。AI 只在被验证过的窄路上跑,宽路留给人。


# 结语:Agent 时代,Skill 是"作业规程",不是"说明书"

回顾 ease-ops-onboard 的设计,它没有把 Skill 当作"教 AI 怎么用 API 的文档",而是当作一份作业规程:

  • 用五阶段状态机规定动作顺序;
  • 用三条硬规则划出安全红线;
  • 用渐进披露控制 AI 的注意力预算;
  • 用安装器和版本握手保证规程能被执行、能被更新。

最终的收益不是"AI 很聪明",而是"AI 可以不那么聪明"——漂移有指纹拦着,越权有 plan_id 拦着,泄密有 intake 通道绕着。当规程把犯错的空间压到足够小,一句话接入一个仓库才敢从演示视频走进生产环境。