ease ops - 自动化接入Skill 设计
# 前言
让 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_projectAI [阶段 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 正文里最醒目的是三条任何阶段不得违反的硬规则:
- 没有
plan_id不执行;blockers 非空不执行;风险项未逐条确认不执行; - secret 永不进入 payload / 文件 / 对话,只走独立的 intake 页面;
- 用户确认必须是显式肯定,"看起来可以""嗯"不算。
三条规则落到形态上,各是这样一小段:
规则 1——plan 返回的风险项,必须逐条回填才许执行:
// plan_onboarding 返回
"acknowledge_required": [
{"code": "shared_repo",
"summary": "该 git 已被项目 payment 使用;共用会导致凭证、分支策略、产物互相牵连"}
]
// apply 前 payload 必须回填,否则 ack_missing 拒绝
"acknowledge": ["shared_repo"]
2
3
4
5
6
7
8
规则 2——secret 在 payload 里只许出现名字:
configs:
- key: DB_PASSWORD
scope: project
secret: true # 出现 values 即服务端硬错误 secret_in_payload
required: [prod]
2
3
4
5
规则 3——确认必须是显式指令:
AI: 确认执行?
你: 看起来可以 → 不算,AI 停下来再次请求明确指令
你: 执行 → 算,进入 apply
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 → 触发方式 + 轮询节奏 + 失败自动诊断对照表
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)
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
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 连通性验证
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 # 幂等,不产生重复条目
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 通道绕着。当规程把犯错的空间压到足够小,一句话接入一个仓库才敢从演示视频走进生产环境。