Skill 是写给 AI 看的,多数情况下你不会自己一行行敲。这篇文章不打算复述 Anthropic 的 Agent Skills 规范,而是把规范里实际容易写错的几个点拎出来讲,再说一下怎么把这件事丢给 AI 做。
Skill 是什么
一个 Skill 就是一个目录,里面至少有一个 SKILL.md:
skill-name/
├── SKILL.md # 必须有
├── scripts/ # 可选,可执行代码
├── references/ # 可选,详细资料
└── assets/ # 可选,模板/图片/数据
外形跟普通文档目录一样,关键差别在加载方式。
普通文档要么塞进 system prompt 永远占着上下文,要么压根不进上下文需要人去翻。Skill 是渐进式加载的:
- 启动时,所有 Skill 的
name加description一次性进上下文,相当于一个目录索引。总开销由所有 Skill 的 description 内容总量决定,跟安装的 Skill 数量、每个 description 写多长直接相关。 - AI 判断当前任务匹配某个 Skill 时,把那个 Skill 的
SKILL.md正文拉进来。 - 真正用到
scripts/或references/里的内容时再单独读。
理解了这个三层加载,就明白了写 Skill 时为什么要在 description、SKILL.md、references/ 三层都注意 token 用量。description 不到位 AI 不会触发它,SKILL.md 太长会撑爆上下文,references/ 没拆好 AI 不知道该读什么。
规范条款:硬约束,违反会被 validator 拒绝
Agent Skills 是 Anthropic 推出的,2025 年 12 月作为开放标准发布。规范站点在 agentskills.io/specification,配套 GitHub 仓库是 agentskills/agentskills,validator 工具叫 skills-ref。
下面三条是规范层面的硬约束,写错了 validator 会直接报错。
1. name 不能随便起
约束:
- 1 到 64 字符
- 只能小写字母、数字、连字符
- 不能以连字符开头或结尾
- 不能含连续的
-- - 必须等于父目录名
最后这条容易漏。把 Skill 复制到新目录改个名,忘改 frontmatter 里的 name,validator 会直接报错。
# 不合法
name: PDF-Processing
name: -pdf
name: pdf--processing
# 合法
name: pdf-processing
name: data-analysis
name: code-review
2. description 决定 Skill 是否能被触发
启动时 AI 看不到 SKILL.md 正文,只看 description。description 写不到位,AI 永远不会加载这个 Skill。
规范层面的硬约束只有两条:1 到 1024 字符;要写明"做什么"和"何时使用"。下面这种就属于不达标:
description: Helps with PDFs.
只说"帮你处理 PDF",没说何时用,AI 没办法把这条 Skill 跟具体提问关联起来。
下面这种就够了,符合规范:
description: |
Extracts text and tables from PDF files, fills PDF forms,
and merges multiple PDFs. Use when working with PDF documents
or when the user mentions PDFs, forms, or document extraction.
规范要求只到这里。但实战中"做什么 + 何时用"还不够,还需要补触发关键词、覆盖口语化表达,详见后面"实战建议"一节。
3. 版本号塞 metadata 里
规范本身没有独立的 version 字段,官方示例把它放在 metadata 中:
metadata:
author: your-team
version: "1.0"
团队内统一用 semver 即可。一旦 Skill 发布,name 不要再改,靠 version 演进。name 是 Skill 的唯一标识,外部引用都靠它。
实战建议:规范没要求,但写过几个 Skill 都会踩
下面这些规范层面没强制要求,但实际写下来很快就能体会到必要性。它们不会被 validator 拒,但缺了 AI 的命中率和工作效果会明显变差。
description 加触发关键词、覆盖多语言
规范只要求 description 写明做什么 + 何时用。但用户提问的话术千差万别,光靠 AI 自己语义匹配命中率不高。把可能的触发短语显式列出来效果会好很多,不分中英文:
description: |
对本地分支、PR、commit 或单个文件做自动 code review。
当用户希望对现有代码做质量、bug、坏味道分析时使用。
Triggers: "review my code", "find issues", "代码审查",
"看下这个 diff", "PR review", "审查代码", "看看这段代码有啥问题".
写 description 的实战公式:
[做什么] + [何时使用] + [按需补充 3 到 5 个触发短语,覆盖团队常用语言和口语化表达]
中英混合环境把双语都列上能减少触发漏判。纯英文或纯中文环境同样建议列触发短语,覆盖不同的提问风格(正式 / 口语 / 缩写)。
SKILL.md 体量控制在 5000 tokens 以内
这不是规范规定的硬上限,规范只说"长内容建议拆到 references"。5000 tokens 是社区实践中较常见的阈值,超过这个量级,命中后塞进上下文会明显挤占模型可用空间,效果开始下降。行数仅供粗估(中英文单行 token 差异较大,500 行只是英文环境下大致对应的体量)。
详细参考资料、边界场景、罕见用法都拆到 references/ 下,由 AI 自己决定何时去读。拆完之后,在 SKILL.md 里告诉 AI 什么场景该读哪个文件:
## Reference materials
- `references/symbolication.md`,仅当默认的 scripts/atos.sh 失败时再读
- `references/macos-signatures.md`,仅当崩溃类型是 EXC_BAD_ACCESS 或 KERN_* 时再读
- `references/edge-cases.md`,仅当标准工作流返回为空时再读
加了这种条件说明,AI 不会一股脑全读,只在需要时去拉。
references/ 目录层级按需嵌套即可
规范本身没限制 references 的目录层级。如果 reference 文件多,按 references/api/、references/errors/ 这样分类是合法的,常见做法。
实践中建议避免引用链:A 引到 B、B 又引到 C 的多跳跳转。这种情况下 AI 加载顺序难以预测,容易漏读。能直接平铺就别套娃。规范本身没禁止多跳,这条只是工程经验。
Workflow 写步骤,别写原理
反例:
## 崩溃分析的工作机制
崩溃日志包含一段调用栈,记录了崩溃瞬间各帧的状态。每一帧
对应一次函数调用……
正例:
## Workflow
1. 用 `read_file` 打开崩溃日志
2. 跑 `bash scripts/atos.sh <addr>` 做符号化
3. 用 `git blame` 找出引入这行的 commit
4. 输出 { 根因, 嫌疑 commit, 修复建议 }
教科书式的背景介绍只会消耗 token,对 AI 执行任务没帮助。
命令、路径、版本号写精确
| 模糊 | 精确 |
|---|---|
| 用最新版 pnpm | pnpm@8.15.9 |
| 跑构建脚本 | pnpm --filter editor-demo build |
| 在项目根目录下 | 含有 pnpm-lock.yaml 的那一层目录 |
模糊的指令意味着 AI 每次都得现猜,每次猜得不一样,结果就不可复现。轻量 Skill 步骤少时简单描述也能跑,但稍微复杂一点的工作流就会因为模糊出问题。
重活落到脚本里
格式转换、数据提取、调用 CLI 这类确定性操作都写成脚本,让 AI 调一行:
1. 跑 `bash scripts/extract-symbols.sh <crash-file>`,产出 JSON
2. 读取输出
3. ...
而不是:
1. 解析崩溃日志:找匹配 /^\d+\s+\w+\s+0x[0-9a-f]+/ 的行……
后者每次都得让 AI 在上下文里把这段正则重新构造一遍。脚本里的 100 行 bash 比让 AI 在上下文里现写 100 行省 token,也更可靠。
边界容易被误用时,加一段 Out of scope
两类情况下值得单独写一段 Out of scope:
- Skill 之间边界接近:比如 commit skill 和 cr skill 都跟 git diff 相关,明确各自不做什么能帮 AI 区分该用哪个。
- 单个 Skill 自身能力宽泛:比如一个"代码分析"Skill,用户可能顺手让它"顺便改一改"或者"也帮我重构下",写明 OOS 能挡住超范围请求。
## Out of scope
- 不修改生产代码
- 不动 git 历史(rebase / squash / amend 一律不做)
- 不分析内核扩展崩溃
简单功能的 Skill(比如日期格式转换、文本编码处理)边界清晰、不容易被超范围使用,不写也没问题。
工作流可能失败时,写一段 Error recovery
## Error recovery
- 如果 scripts/atos.sh 返回非 0:
读 references/symbolication.md,回退到手动符号化
- 如果 commit 不在当前分支:
告诉用户这是上游引入的,不要自动修
- 如果用户请求超出范围:
直接说,不要硬撑
不写兜底的情况下,AI 在工作流第三步卡住时会硬撑出一个错误结果给你,看起来还挺像那么回事。但纯查询类、纯文本处理类 Skill 没什么失败路径,可以不写。
涉及破坏性操作的 Skill,写一段 Safety
## Safety
- 不允许 `sudo`
- 不允许 force push 到 main / master / release/*
- 任何 `git commit` 前必须由用户确认
只在 Skill 会执行修改、提交、删除等破坏性操作时需要。纯文本处理 / 纯只读分析类 Skill 不需要这一节。
怎么指挥 AI 写 Skill
写 Skill 是高度模板化的任务,适合丢给 AI,但你得给对指令。
第一步:把需求压成一段提示词
不要直接说"帮我写个 code review 的 skill"。这种指令出来的 description 一定是 "Helps with code review" 那种东西。
把以下信息一次性给 AI:
我要写一个 Skill,承担以下职责:
- 做什么:[一句话]
- 触发场景:[列 3-5 个具体场景]
- 不做什么:[列 2-3 个邻近但应该排除的场景]
- 工作流:[列出 3-7 步具体动作,包含具体命令]
- 依赖:[需要哪些工具/版本]
- 危险操作及限制:[如果涉及修改/提交等]
请按 agentskills.io 官方规范生成 SKILL.md。规范层硬要求:
- name 小写字母/数字/连字符,等于目录名
- description 1-1024 字符,写明做什么 + 何时用
- metadata.version 用 semver
实战层建议:
- description 视情况补触发关键词、双语短语
- 工作流写具体命令而非模糊描述
- SKILL.md 主体超 5000 tokens 就考虑拆 references/
- 多 Skill 边界混淆 / 工作流可能失败 / 涉及破坏性操作时,
对应补 Out of scope / Error recovery / Safety 章节
按这个模板给指令,AI 一次过的概率会高不少。
第二步:让 AI 自我审查
写完后再喂一遍清单让它自己挑刺:
请用以下清单审查上面这个 Skill:
[ ] description 是否同时包含「做什么 / 何时用」(规范必填)
[ ] description 是否覆盖团队常用语言和口语化触发短语(实战建议)
[ ] name 是否符合命名规范(小写/连字符/无连续--/等于父目录名)
[ ] metadata.version 是否有
[ ] SKILL.md 体量是否过大(建议正文 ≤ 5000 tokens;超出考虑拆 references)
[ ] 工作流是否写了具体命令(而非"运行构建"这种模糊指令)
[ ] 是否需要补 Out of scope(多 Skill 边界容易混淆时)
[ ] 是否需要补 Error recovery(工作流可能失败时)
[ ] 是否需要补 Safety(涉及破坏性操作时)
列出不达标项并修正。
让 AI 对清单做模式匹配比让它自由"反思一下"准确。
第三步:跑 validator
skills-ref validate ./my-skill
报错就把报错复制给 AI 让它修。
第四步:实战测试
Skill 装进去后,用各种说法故意触发它:
- 标准说法:"review this PR"
- 中文:"审一下这段代码"
- 口语:"这代码有啥问题没"
- 边界:"看一下这个 diff"(diff 应该归 commit skill 还是 cr skill?)
某个该触发的说法没触发,回去补 description 关键词。不该触发的反而触发了,先看 description 写得是不是太宽泛、关键词是不是过度发散,必要时再补 Out of scope。
最小模板
下面这个模板包含规范要求的字段加上常用的实战章节。简单 Skill 删掉用不上的章节即可:
---
# === 以下为规范字段 ===
name: example-skill
description: |
一段触发文本:先说做什么,再说何时使用。
按需补充触发短语,覆盖团队常用语言和口语化表达。
Triggers: "phrase 1", "phrase 2", "中文短语".
metadata:
version: "0.1.0"
author: your-team
# compatibility 是规范定义的可选字段,多数 Skill 不需要写。
# 仅在有特殊环境依赖(如目标产品、系统包、网络要求)时填。
compatibility: Requires git, jq
---
# Example Skill
## When to use
- 具体场景 1
- 具体场景 2
## When NOT to use
- 邻近场景 1,由 other-skill 处理
- 邻近场景 2,超出本 Skill 范围
## Workflow
1. 读取上下文:定位文件 X、分支 Y
2. 执行:`bash scripts/do-thing.sh <arg>`,产出 JSON
3. 解析输出:取出 `{ field1, field2 }`
4. 汇报结果;执行任何破坏性操作前先问用户
## Reference materials
- `references/spec.md`,仅当第 2 步出现歧义时再读
- `references/edge-cases.md`,仅当第 3 步返回为空时再读
## Dependencies
- pnpm 8.x
- ripgrep ≥ 13
# === 以下章节按需保留,简单 Skill 可全部删除 ===
## Out of scope
- 不修改生产数据
- 不涉及鉴权/认证
## Safety
- 不允许 `sudo`
- 不允许 force push 到 main / master / release/*
- 任何 `git commit` 前必须由用户确认
## Error recovery
- 第 2 步失败:读 references/troubleshooting.md
- 输出不符合预期:让用户确认,不要自己猜
几个容易忽略的点
description 写的时候要想"用户会用什么话提问",而不是"这个 Skill 有多牛"。
写完先自己用一周,把遇到的问题修进去再分享。否则发出去后会持续收到"这个 Skill 触发不到"或者"总是误触发"的反馈。
写工作流时,如果发现自己开始写"原理上""一般来说""通常""推荐"这种词,停下来想想这句话能不能删。Skill 是写给 AI 当指令的,不需要解释 why,只需要告诉它 how。这条不是规范要求,是写多了会发现的经验。
复杂 Skill 或多 Skill 协同的场景下,边界决策不要让 AI 来。AI 写细节没问题,但"这个 Skill 该管什么、不该管什么"涉及到跟其他 Skill 的分工、跟生产环境的边界,这些必须人来定。极简单的工具型 Skill(比如纯文本处理、格式转换)边界清晰,让 AI 自己定也可以。