很多人的 CLAUDE.md 都有同一个毛病:从十几行长到四百多行,里面混着「事实」和「流程」两类完全不同的东西。事实(比如这个仓库用 pnpm)应该常驻上下文;流程(比如「发版要走哪五步」)只在真正做那件事时才需要。Agent Skills 就是为后者准备的打包方式:一个目录、一个 SKILL.md,平时只占一行描述,命中任务时才把正文读进来。这篇教程带你做一次真实的拆分,并让同一批技能在多个工具里都能用。
先理解:渐进式披露是它值钱的地方
一个技能加载分三层,理解这三层就理解了这个格式:
| 层 | 什么时候加载 | 装什么 |
|---|---|---|
| 元数据 | 启动时就常驻 | name、description,以及够不够判断「这个技能是否适用」的信息 |
| 指令 | 技能被触发时 | SKILL.md 的操作正文 |
| 资源 | 正文里点名需要时 | 参考资料、脚本、模板、示例、素材 |
这就是为什么你可以装几十个技能而几乎不占上下文——模型平时只看得到每个技能的名字和描述。
Step 1:判断哪些内容该被拆出来
翻一遍你的 CLAUDE.md,按这个判据分拣:
该做成技能(重复 3 次以上的流程):
· 你们团队怎么命名测试文件
· 发版要走哪几步
· 评审一次数据库迁移的检查清单
· 调试某类线上问题的固定顺序
留在 CLAUDE.md / .claude/rules/(一次性事实):
· 这个仓库用 pnpm 而不是 npm
· 主分支叫 main
· 线上数据库叫什么名字
别给一次性的任务写技能。技能的价值来自重复——一个你只会做一次的任务,写技能的时间收不回来。判断标准很直白:这件事你在对话里解释过三次以上了吗?没有就先别写。
Step 2:建目录,先写描述再写正文
.claude/skills/
└── database-migration/
├── SKILL.md
├── references/
│ └── migration-checklist.md
└── scripts/
└── verify-migration.sh
SKILL.md 开头的 YAML frontmatter 是发现层。先写 description,再写别的——它是常驻上下文的那部分,也是模型判断「要不要加载这个技能」的主要依据:
---
name: database-migration
description: Use when creating, reviewing, or verifying database
migrations. Covers schema inspection, incremental migration
authoring, type regeneration, and rollback notes.
---
1. Inspect the current schema and existing migrations.
2. Create the smallest incremental migration.
3. Regenerate types if the project requires it.
4. Run the migration verifier script.
5. Summarize data-loss risk and rollback notes.
Helps with databases. 这种描述会被直接跳过;Use when adding or changing database migrations, reviewing schema diffs, or investigating migration failures. 这种会命中。差别就在于前者说的是主题,后者说的是触发时机。Step 3:正文写成指令,长资料挪出去
这一点决定了两条写法:正文用祈使句写「做什么」,不要写「这个技能是干什么的」(后者属于 description 的职责);正文每多一句,之后每次会话都在付这笔成本。所以:
放在正文里:操作步骤、判断规则、必须遵守的顺序
放到 references/ 里:长 API 参考、示例文件、检查清单全文
然后从 SKILL.md 里用相对路径链接过去
原则:references/ 里的东西只有在正文点名时才被读进来。
正文越薄,技能越容易被高频触发而不拖慢会话。
Step 4:控制 frontmatter 的可移植性
如果你希望同一个技能能跨工具复用(Claude Code → Copilot → Cursor),frontmatter 里只用开放 Agent Skills 规范允许的字段:
规范允许(安全区,跨工具通用):
name / description / license / compatibility / metadata / allowed-tools
Claude Code 的扩展字段(写进去只有 Claude Code 认):
disable-model-invocation # 禁止模型自行触发该技能
context: fork # 让技能在子智能体里运行
argument-hint 等
只认规范的工具有个坑:遇到不认识的字段会直接报错,而不是安静忽略。实测中,把一个带 argument-hint 的技能上传到只支持规范的工具体,结果是加载失败。所以顺序应该是:先用六个安全字段把技能调通、确认可用,之后再按需加平台扩展。
Step 5:放到正确的位置
| 位置 | 作用范围 | 要不要提交到仓库 |
|---|---|---|
~/.claude/skills/<name>/ | 个人,所有项目可用 | 不要,属于个人偏好 |
.claude/skills/<name>/(项目根) | 团队,跟着代码走 | 要,它编码的是团队流程 |
如果技能来自公开仓库,也有现成安装方式:
# 一条命令装指定技能
npx skills add owner/repo
npx skills add owner/repo --skill cro ads # 只装点名的几个
# 或者走插件市场
/plugin marketplace add owner/repo
/plugin install your-skill-pack
装第三方技能前,把每个文件读一遍。技能本身不授予任何数据访问权限——它只决定 Claude「怎么做」,能拿到的还是你粘贴或上传的内容。但技能目录里可以带脚本,装一个来路不明的技能,风险等同于运行别人的 shell 脚本。最稳的入口是从官方预置技能或官方仓库开始。
Step 6:两条路径都要测
路径 A(测 description 写得好不好):
用大白话提一个应该命中该技能的问题,比如
「帮我审一下刚写的这个迁移,重点看数据丢失风险和回滚」
→ 观察它是否自动加载了技能、并在回答里体现出来
路径 B(测技能本身能否正常执行):
直接按名字调用(Claude Code 里就是 /你的技能名)
→ 确认正文步骤、引用的脚本与参考资料路径都正确
两条都过,才说明技能真的可用。
只过 B 说明 description 没写好;只过 A 说明调用名或路径有问题。
Step 7:进阶——把「对抗式评审」做成一个技能
2026 年 9 月初出现的一个思路值得借鉴:与其让主 Agent 自己确认架构决策,不如让一个技能规定它必须生成三个子代理做对抗式评审。三个关键设计点:
1. 数量固定为三个
太少没有分歧,太多只是噪声。
2. 上下文走文件,不走对话历史
把问题背景完整写进一个文件,让子代理独立读取。
这样能避免主 Agent 把自己的错误假设「锚」给评审者。
3. 把子代理的输出当作「不熟练实习生」的产出对待
明确要求:不要过度工程化。
这一条是整套协议里最重要的——
它防止主 Agent 把子代理幻觉出来的复杂方案照单全收。
常见问题速查
| 你遇到的现象 | 大概率原因 & 解决 |
|---|---|
| 技能一直不被触发 | description 写成了主题而不是触发条件,改成「Use when …」句式 |
| 上传到别的工具直接报错 | frontmatter 里有平台扩展字段,先裁到规范允许的六个字段 |
| 会话变慢、上下文吃紧 | SKILL.md 正文太长,把长资料挪到 references/ 并改成链接 |
| 技能内容没生效 | 目录位置不对。个人技能放 ~/.claude/skills/,团队技能放仓库内 .claude/skills/ |
| 技能里的脚本跑不起来 | 脚本路径要写相对技能目录的相对路径,不要写绝对路径 |