从 6 个真实 skill(a1、dws、mw-cli、dms、pensieve、infra-config)里反推出来的方法论。它们是同一道题的不同成熟度答案——对照着看,就知道好在哪、坏在哪、该怎么写。
--json」,而是一套带自描述契约(schema)和强制门禁(gate)的 API——只是恰好长得像命令行。
人和 Agent 用命令行的方式,根本不同。为人优化的东西,对 Agent 常常是坑。
| 维度 | 人类用户 | Agent 用户 |
|---|---|---|
| 怎么知道有哪些参数 | 翻文档、试错、Tab 补全、看报错 | 必须一次拿到机器可读的完整契约,否则只能靠训练记忆猜——而记忆会过时 |
| 看到隐式状态(当前环境/绑定) | 记在脑子里,命令行提示符也会显示 | 看不见。隐式状态 = 沉默的错误源 |
| 读输出 | 表格、颜色、对齐,一眼扫 | 要结构化 JSON;拼下一条命令时只想要那个 ID |
| 等一个长任务 | 盯着屏幕,看进度条 | 每轮轮询 = 一次模型调用,烧 token 且可能死循环 |
| 犯错后 | 看报错、改、重试,成本低 | 错一步可能连环错,且不一定意识到错了 |
| 危险操作 | 删库前会手抖、会二次确认 | 只要文档没拦住,它就真敢执行 |
同一道题的六种答卷。从右往左,是从「文档凑合」到「工程闭环」的演进。
| 能力 | dws 最成熟 | a1 成熟 | dms 中 | mw-cli 中 | infra-config 反例 |
|---|---|---|---|---|---|
| 命令契约来源 | 二进制生成的 schema,四层渐进查询 | 手写 reference ~4000 行 | 手写 reference | 手写 reference | 无,835 行单文件 |
| 安全机制放哪 | CLI 内:effect/risk/confirmation + --yes | 文档约定 | 导流到平台审批工单 | 纯文档「红线」 | 无 |
| 隐式上下文 | 强制显式 | 绑定态 + flag 可覆盖 | 显式 + 本地缓存 | 强制显式 --env --unit | 无概念 |
| 长任务原语 | 40 个 scripts 封装 | --follow/--wait-until-settled/--offset | 工单状态查询 | 无 | 无 |
| 防契约漂移 | schema 随二进制发版 + 版本声明 | 手工修(已留伤疤) | 手工 | 手工(还躺着 .bak 文件) | 手工维护记录 |
| 输出契约 | schema 定义 | -f json / -q 取 ID | 本地 JSON 落盘 | -o json | 让 Agent 抄文档 |
每条都配一正一反的真实 case。看代码比看道理快。
--help 给人,schema 给机器,两者分开做Agent 选参靠 schema,不靠训练记忆。手写文档一定会和真实 CLI 漂移。
dws 是唯一做到的:dws schema 分四层渐进查询(产品概览 → 产品 → 分组 → leaf),leaf 直接给出每个参数的 type / required / enum / constraints / examples。更关键的是它划定了事实源边界:
# 命令是否存在、当前接受哪些 flag
dws <path> --help
# Agent 选参 / required / 约束 / 风险
dws schema "calendar event create" --compact
# 三者冲突 = 「契约漂移」→ 上报,
# 不许拼接猜测、不许选更宽松的那个
# SKILL.md 开头被迫写:
⚠️ 构造命令前必须查阅完整参数
不要凭记忆猜测 flag 名
# 这条警告存在本身,就是
# 「没有机器可读契约」的病征
→ 手写文档的代价,看 a1 留下的伤疤就够了:--run 现已必填、run/retry 已废弃、没有 --all(旧版 SKILL.md 拼写错误)。这些都是「文档跟不上代码」的化石。
危险操作的拦截必须做进代码;文档拦不住一个「你确定要执行吗」都不问的 Agent。
# SKILL.md「安全红线」:
❌ 禁止 --env prod
❌ 禁止 mw config set ...
# 全靠 Agent 自觉。它完全
# 可以无视,CLI 层不拦。
# schema 里每个工具都标:
"effect": "destructive",
"confirmation": "user_required"
# → 必须先让用户确认,再加 --yes
# CLI 层强制,不是靠提示词
还有第三种更聪明的解法(dms):不自己造门禁,而是把风险导流到已有的审批链。生产环境的 DML/DDL 一律走平台工单:
order init --order-type change → 编辑 → submit → submit-approval → execute # 审批通过后才执行
→ 设计顺序应该是:先把危险操作的门禁做进 CLI(或导流到审批系统),再谈能力覆盖多少。
「有全局状态,但查不到、也盖不掉」是最差的形态。
这是样本里唯一的真分歧,两种可接受形态:
mw mq topic list \
--env daily --unit ant-daily
# 且禁止 mw config set 改全局,
# 逼每条命令自带环境,意图零歧义
a1 link status -f json # 执行前先确认绑定
a1 repo mr list # 用绑定的仓库
a1 repo mr list --repo x # 单次覆盖
→ 核心不是「有没有隐式状态」,而是「Agent 能不能 看见它、并临时推翻它」。a1 的 link status -f json 就是把不可见的状态变可见。
让 Agent 从人类表格里抠 ID,等于白送解析错误。
a1 的三档输出是范本:
| 档位 | 命令 | 面向 |
|---|---|---|
| 默认 | a1 app cr list | 人:表格/文本 |
| 结构化 | -f json → | jq | 解析字段、链式取值 |
| 纯 ID | -q | 只要 ID 去拼下一条命令 |
→ -q 这档最容易被忽略,但对 Agent 最关键:它拼下一条命令通常只需要一个 ID。list 类命令还应统一分页参数(--page-size / --offset),避免每个命令各造一套。
Agent 每轮循环 = 一次模型调用。轮询这种事必须由工具承担。
a1 app pipeline status --pipeline-id X \
--wait-until-settled # 一条命令等到结束
a1 build job log X --step Y --follow
a1 build job log X --step Y \
--offset $NEXT --limit 500
# scripts/ 下 40 个脚本,封装
# 翻页/轮询/批量导入/创建轮询
python scripts/aitable_import_via_task.py
# SKILL.md 明令:脚本优先于手写多步
nextOffset / finished / stepRunning 字段,不许用「返回空日志」当结束信号。日志 --limit 默认 500 行也是「输出预算」意识——防止一条命令灌爆上下文窗口。
表结构这类东西,读本地文件比调接口快一个量级。Agent 只需要一个能自己判断新鲜度的信号。
dms 把数据字典 sync 到本地,每个 JSON 带 synced_at:
~/dms-alibaba/db-groups/<group>/databases/<db>/
├── database.json # 连接信息 + synced_at
├── _index.json # 表清单 + synced_at
└── tables/<t>.json # 字段+索引 + synced_at
# 规则:本地优先;读前看 synced_at,过期再 sync
→ pensieve 是同一思想的极致版:整个知识库就是一个 Git 仓库,「编译一次、持续维护」,查询时读文件而非重新推导原始文档。
别让 Agent 面对「先检查安装、再检查登录、再检查配置」的多步判断树——压成一条命令 + 一张处置表。
dms-alibaba auth # 同时验证安装 + 凭证
| 输出 | 处置 |
|---|---|
| 命令不存在 | 跑安装命令 |
| 报错 | 版本旧,更新 |
| 凭证缺失 | auth --force |
| 就绪 | 下一步 |
a1 faq grep "关键词" # 内置文档可搜
a1 faq search "..." # 语义搜索
a1 feedback "标题" ... # 统一反馈通道
# 承认 Agent 用 CLI 一定会踩坑,
# 就得留一条把坑送回团队的管道
→ dms 还写明:「Agent 有权直接执行安装和修复命令,无需展示给用户手动操作」,并给了无浏览器环境的旁路(直接写 credentials.json)。自愈要连「授权」一起给足。
每多一条「⚠️ 不是 XXX」,就说明命令命名多欠一笔债。
a1 里至少 4 处强消歧,dws 有决策树 + 5 条「关键区分」+ 独立的 intent-guide.md:
devix task ≠ 项目工作项 workitempages 站点配置 ≠ 部署 pages 内容(走 ci)cr submit --pipeline-id ≠ submit-integrationpkg deploy-cr ≠ artifact mvn deploy ≠ pkg deploy-intg(三个发布路径)infra-config 是唯一没有 CLI 的 skill——835 行单文件说明书。它精确地演示了「配置说明书」冒充「能力入口」的三个结构性问题。
把 MongoDB / Redis / AgentBay / DashScope / FAI / Tavily 的连接串、SDK 安装、代码示例、维护记录、待办清单全塞进一个 SKILL.md。
| 问题 | 表现 | 对照正例 |
|---|---|---|
| 无分层 | 任何一次触发都要吞 835 行进上下文 | a1 是 SKILL.md 618 行 : references 4000+ 行 ≈ 1:7,只有路由信息进上下文 |
| 占位符会被当真 | Redis 整节是 [待填充],Agent 读到照抄进代码 | 命令不能留空:config get redis 要么返回值要么报错 |
| 没有可执行入口 | 全靠 Agent 从文档复制连接串和示例 | 应退化成一条命令 xxx config get mongodb -f json 或一个 .env |
顺序很重要。先建契约和门禁,最后才写文档——反过来做,就会变成 a1 那样用文档追着代码补。
每个命令、每个参数的 type / required / enum / 约束 / 示例 都从代码生成,随二进制发版。手写 4000 行 reference 的下场,看 a1 的 --bak 文件和「拼写错误」注释。做成分层查询(概览 → 领域 → leaf),别让 Agent 一次吞全量。
每个命令标 read / write / destructive。destructive 一律要 --yes,且默认要求先向用户确认。高危操作优先导流到已有审批系统(像 dms 走工单),而不是自己造一套确认逻辑。
-f json(结构化)+ -q(纯 ID)两档必备。list 类命令统一分页参数。给每个可能刷屏的命令设默认输出上限(如日志默认 500 行)。
--follow、--wait-until-*、--offset/--limit 增量拉取。明确定义「结束信号」字段(finished 之类),别让 Agent 靠猜。复合流程封装成脚本。
① 意图 → 命令映射表 ② 消歧规则 ③ 故障处置表。全量参数交给 schema / --help。文档跟二进制一起发版,并声明版本约束(dws 的 cli_version: ">=1.0.15")。
一个能直接抄的骨架。它刻意只保留「路由 + 门禁 + 处置」,把重活留给 schema。
---
name: my-cli
version: 1.0.0 # 每次发布必须递增(SemVer)
cli_version: ">=1.0.15" # 声明依赖的二进制版本,防漂移
description: "一句话做什么 + 一串触发词(越具体越好,覆盖用户可能的口语说法)"
---
# My CLI 使用助手
## ⚠️ 核心规则:构造命令前查契约
下文只列常用 flag。涉及任何具体选项,先跑 `my-cli <cmd> --help`
或查 schema,不要凭记忆猜 flag 名。
## 🚦 安全门禁(不可协商)
| 操作类型 | 处置 |
|---|---|
| read | 直接执行 |
| write | 执行前告知用户影响范围 |
| destructive | 先展示操作摘要 → 用户确认 → 才加 --yes |
线上/生产:<写清楚是禁止,还是必须走审批工单>
## 前置检查(自愈)
跑 `my-cli auth`(一条命令同时验证安装 + 凭证):
| 输出 | 处置(Agent 有权直接执行) |
|---|---|
| 命令不存在 | <安装命令> |
| 凭证缺失 | my-cli auth --force |
| 就绪 | 下一步 |
## 意图 → 命令映射
| 用户意图 | 命令 |
|---|---|
| 查 X 列表 | `my-cli x list -f json` |
| 创建 X | `my-cli x create --name ...` |
| ... | ... |
## ⚠️ 消歧(只在命令易混时写)
- 用户说「A」→ 用 `cmd-a`,**不是** `cmd-b`(区别:...)
## 输出格式
`-f json` 解析字段;`-q` 只取 ID 拼下一条命令;默认表格给人看。
## 长任务
- 等结束:`--wait-until-settled`;跟日志:`--follow`
- 判断结束用响应的 `finished` 字段,不要用「空输出」
## 参考文档(按需读,不要全进上下文)
- references/x-commands.md — X 的全部 flag
-f json / 取 ID 的方式吗?.bak 之类的化石不用读全文,看到这些信号就知道有问题。
| 闻到的气味 | 真正的病根 | 该怎么治 |
|---|---|---|
| SKILL.md 里写「不要凭记忆猜 flag」 | 没有机器可读契约 | 做 schema(法则 01) |
| 安全全靠「⚠️ 禁止…」文档段落 | 门禁没做进代码 | 标 effect + --yes 门禁(法则 02) |
有全局配置,但没有 xxx status 能查 | 隐式状态不可见 | 加状态查询 + flag 覆盖(法则 03) |
| Agent 需要从表格输出里正则抠 ID | 没有机器输出通道 | 加 -f json / -q(法则 04) |
| SKILL.md 教 Agent「循环调用直到…」 | 长任务没做进 CLI | 加 --wait/--follow(法则 05) |
references 目录里躺着 .bak 文件 | 文档和代码在漂移 | schema 随二进制发版(法则 01) |
| 消歧段落越写越多 | 命令命名混乱 | 收敛动词和别名(法则 08) |
| skill 本质是「一堆要 Agent 照抄的信息」 | 它还不是能力入口 | 退化成命令或 .env(第 04 节) |
| 正文动辄几百行、无分层 | 全量进上下文,挤占窗口 | SKILL.md 只留路由,细节进 references |