如何编写高质量的 Agent Skill
· 1439 words · ~ 7 min read
SKILL.md 的格式不复杂:一个目录、一个入口文件,再加一些可选的脚本和参考资料。难点在内容设计。高质量 Skill 要把重复任务整理成清晰、可触发、可执行、可验证的操作手册,而不是把一大段 prompt 直接搬进文件。
先用一句话判断是否值得写成 Skill:
如果一个任务会反复出现,并且你希望 Agent 每次都按同一套方法完成,就适合写成 Skill。
一次性问题不用写 Skill。项目长期背景也不适合放进 Skill,放 AGENTS.md、CLAUDE.md、GEMINI.md 这类 instruction 文件更合适。Skill 应该面向具体任务。
Skill 解决什么问题
Skill 解决的是流程稳定性。重点不在模型是否知道某个知识点,而在它每次能不能按同一套正确方法完成任务。
它适合沉淀这些内容:
- 一组稳定步骤:例如排查 CI、审查 PR、生成周报、分析日志。
- 一套质量标准:例如代码评审 checklist、安全检查项、文档风格。
- 一些可复用资源:例如模板、示例、API 规范、团队内部约定。
- 少量确定性脚本:例如解析日志、生成报告、校验格式。
它不适合承载这些内容:
- 大而全的项目背景。
- 随时间频繁变化的事实。
- 没有明确输入输出的泛泛建议。
- 可以直接用 MCP、CLI、API 完成的底层连接能力。
可以这样划边界:MCP/工具负责“能访问什么”,Skill 负责“拿到能力后怎么做”。
最小结构
一个通用 Skill 目录通常长这样:
|
|
只有 SKILL.md 是必需的。references/、scripts/、assets/ 用来降低主文件复杂度。
SKILL.md 最小可以写成:
|
|
字段不用多,description 和正文要明确。
写好 description
description 决定 Skill 会不会被自动选中。Agent 通常先看到所有 Skill 的名字和描述,判断相关后才加载完整 SKILL.md。描述要回答两件事:
- 这个 Skill 做什么。
- 什么时候应该用,什么时候不该用。
差的写法:
|
|
好的写法:
|
|
前者范围太大,容易误触发。后者包含任务、语言、检查范围和触发词。
如果一个 Skill 有副作用,例如发布、删除、发送消息、改生产配置,要明确限制触发方式。能配置为只允许显式调用时,就不要让它自动触发;不能配置时,也要在正文第一段写清楚必须先确认。
按需加载与副作用控制
Skill 和普通 prompt 的一个重要区别是按需加载。Agent 不应该在每次会话里都背完整工作手册。它应该先看到一个很短的索引,判断相关后再读取完整流程,需要细节时再读 supporting files。
可以把一个 Skill 拆成三层:
|
|
每一层的职责不同:
description:只回答“什么时候该用这个 Skill”。它越像触发条件,自动选择越准确;越像功能说明或流程摘要,越容易误触发或被 Agent 当成捷径。SKILL.md:放任务边界、输入、输出、步骤、停止条件和验证方式。它应该是执行骨架,不应该塞满所有背景资料。- supporting files:放大段参考、检查清单、模板、领域规则。只有任务真的需要时才读。
- scripts:放确定性操作,例如收集证据、解析日志、校验格式、生成文件。不要让模型用自然语言模拟本该由脚本完成的事情。
副作用要单独处理。凡是会影响外部世界的 Skill,都不应该只靠“请小心”这种文字约束。
常见副作用包括:
- 发布、部署、回滚
- 创建 PR、push、merge
- 发送消息、评论、邮件
- 删除、覆盖、迁移数据
- 修改生产配置或权限
这类 Skill 的默认策略应该是:
- 能禁用自动触发就禁用,只允许用户显式调用。
- 执行前展示计划和影响范围。
- 真正执行外部动作前再次确认。
- 输出中明确写出做了什么、没做什么、如何回滚。
低频 Skill 也不一定值得常驻。一个实用判断:
- 高频任务:保留自动触发,但把
description写准。 - 低频且有风险的任务:保留 Skill,但只手动触发。
- 极低频任务:不要做成 Skill,放进文档,需要时再读。
这也是 Skill 治理里最容易被忽视的一点:不是所有可复用内容都应该变成 Skill。Skill 越多,触发索引越多;触发索引越吵,Agent 越容易选错。
举个例子,假设要做一个 CI 失败分析 Skill,不要这样写:
|
|
这个描述把 workflow 全写进去了。Agent 可能只看 description 就开始按自己的理解执行,反而不读完整 Skill。
更好的写法是:
|
|
然后把完整流程放进 SKILL.md:
|
|
再把检查标准拆到 supporting file:
|
|
references/flaky-checklist.md 可以只在判断 flaky 时读取:
|
|
如果日志格式复杂,再把解析逻辑做成脚本:
|
|
这样每层都很清楚:
description负责触发。SKILL.md负责流程。references/负责判断标准。scripts/负责确定性解析。
副作用 Skill 也一样。比如创建 PR 是有外部副作用的,description 可以写得窄一点:
|
|
正文里要把执行门槛写清楚:
|
|
这个例子讲的是副作用边界:读 diff、生成草稿可以自动做;push、create、merge 必须有明确授权。
主文件要短,参考资料要分层
高质量 Skill 的主文件应该像入口索引,不应该像百科全书。
建议把 SKILL.md 控制在这几类信息内:
- 触发后第一步做什么。
- 输入从哪里来。
- 输出长什么样。
- 哪些情况必须停止或询问用户。
- 需要更详细资料时读哪个文件。
大段内容放到独立文件:
- checklist 放
references/review-checklist.md - 风格指南放
references/style-guide.md - 输出模板放
assets/report-template.md - 稳定操作放
scripts/
这样才能渐进式加载:Agent 不需要一开始就把所有资料塞进上下文,只在任务需要时读取具体文件。
五种常用设计模式
1. Tool Wrapper:封装工具或框架用法
当团队有一套固定框架约定时,可以写一个 Tool Wrapper Skill。它不用替代官方文档,只需要告诉 Agent:这个项目按哪套约定使用这个工具。
适合场景:
- FastAPI、Gin、React、Terraform 等框架约定。
- 内部 SDK 或 CLI 的使用方式。
- 团队统一的错误处理、日志、测试规范。
结构建议:
|
|
SKILL.md 只写触发条件和总规则,具体约定放到 references/conventions.md。不要把整份框架文档复制进去,只保留项目真正不同于常识的部分。
2. Generator:稳定生成结构化产物
Generator 解决“每次生成格式都不一样”的问题。它应该提供模板、变量收集方式和验收标准。
适合场景:
- 生成 PR 描述。
- 生成技术方案。
- 生成故障复盘。
- 生成 API 文档。
结构建议:
|
|
关键点是:先检查输入是否完整,不完整就问;不要凭空补关键事实。
3. Reviewer:把检查标准模块化
Reviewer 适合“按标准检查”的任务。核心是把检查项从流程里拆出来,放到 checklist。
适合场景:
- 代码审查。
- 安全审计。
- 文档质量检查。
- 数据报表口径检查。
结构建议:
|
|
SKILL.md 负责规定审查流程和输出格式,review-checklist.md 负责列出具体标准。以后标准变化,只改 checklist,不必重写整个 Skill。
4. Inversion:先采访,再执行
Agent 容易在信息不足时直接开干。Inversion 模式反过来,要求 Agent 先收集上下文,再进入执行。
适合场景:
- 架构设计。
- 迁移方案。
- 新项目规划。
- 风险较高的自动化操作。
关键写法是加硬门槛:
|
|
这种 Skill 不追求快,追求少猜。
5. Pipeline:多阶段任务强制过检查点
Pipeline 适合复杂任务:把任务拆成固定阶段,并要求每阶段完成后做检查。
适合场景:
- 复杂文档生成。
- 跨文件重构。
- CI 修复闭环。
- 数据分析报告。
结构建议:
|
|
Pipeline 的重点是不要让 Agent 跳过验证。凡是会产生交付物的 Skill,都应该至少有一个 Verify 阶段。
什么时候用脚本
默认优先写说明,不要一上来就写脚本。下面这些情况才适合脚本:
- 操作需要确定性,例如解析 JSON、生成目录、检查 frontmatter。
- 操作会重复执行,手写容易错。
- 输出需要机器可校验。
- 执行脚本比让模型推理更省上下文。
不适合写脚本的情况:
- 逻辑还不稳定。
- 主要工作是判断、取舍、写作。
- 脚本需要复杂依赖,安装成本高于收益。
一个实用原则:如果失败会导致真实副作用,脚本必须可读、可测、可回滚。
写 Skill 时最常见的坑
1. 把 Skill 写成超长 prompt
长不是问题,没结构才是问题。Skill 应该让 Agent 快速找到下一步,而不是读完一整篇散文再自己总结。
2. description 太泛
description 太泛会导致误触发,太窄又会导致该用时不用。最好的写法是“任务 + 触发词 + 边界”。
3. 没有输入输出
没有输入输出的 Skill 往往会变成风格建议。每个 Skill 都应该能回答:
- 输入是什么?
- 产物是什么?
- 成功标准是什么?
4. 没有停止条件
高风险任务必须写停止条件。例如:
- 缺少生产环境信息时停止。
- 要发送外部消息时先请求确认。
- 要删除、覆盖、发布时先展示计划。
5. 混入易过期事实
版本号、价格、服务限制、API 行为都可能变化。Skill 里只放稳定原则;易变事实要让 Agent 查官方文档或本地真实配置。
从真实 Skill 里提炼的好设计
下面这些来自我自己维护的 Skill。它们不一定能直接照搬,但设计思路值得保留。
Reviewer 要控制噪音
代码审查类 Skill 最容易变成“什么都说一点”。先固定审查维度,再明确只输出高价值 findings,会稳很多。
例如 Go PR 审查可以拆成:
- 正确性
- 并发与安全
- 健壮性
- 可维护性
- 性能
- 文档与规范
每个维度只记录可能影响行为、稳定性、安全性或长期维护的问题。风格偏好、无证据猜测、无关建议都不要写进最终结果。
这个设计的关键在过滤规则,不在检查项数量。Reviewer Skill 必须告诉 Agent 什么不值得输出,否则它会为了显得认真而制造噪音。
Reviewer Skill 还应该把“角色边界”写清楚。一个审查 Skill 默认应该是只读的:
- 只审查 diff 和判断问题所需的附近上下文。
- 不修改文件。
- 不提交 commit。
- 不 push、不 merge。
- 不发布评论,除非这个 Skill 的职责就是提交 review,且用户已经明确授权。
这个边界看起来普通,但很重要。审查和修复是两类任务:审查要控制判断质量,修复要控制改动范围。把两者混在一个 Skill 里,Agent 容易一边发现问题一边顺手改,最后用户反而看不清它到底 review 了什么。
大型 review 也可以拆成几条 review lane:
- Code quality:清晰度、命名、结构、重复、错误处理、边界条件。
- Performance:重复工作、复杂度退化、过度分配、I/O 或网络放大、热点路径浪费。
- Security:注入、鉴权/越权、命令执行、敏感信息泄露、不安全默认值、信任边界。
- Documentation accuracy:行为变更是否同步到文档,注释、README、示例和配置说明是否还准确。
如果运行环境支持 subagent,可以把这些 lane 分给不同 reviewer,但这不是必须条件。更重要的是,每条 lane 都要遵守同一个输出协议:只返回 noteworthy findings;没有问题就明确说没有;每个问题尽量带文件和行号;证据不足就标成“需补充上下文”。
如果这个 Skill 真的负责把 review 评论发到 GitHub 或 GitLab,还要增加一层通知卫生:
- 先收集所有 findings。
- 按
(file, line)合并重复或重叠问题。 - 只保留自己也认可的高价值问题。
- 一次性批量提交 review,避免每条评论触发一次通知。
- 默认使用非阻塞评论,不用阻塞式的 request changes,除非团队流程明确要求。
- 在 review body 里放一个稳定 marker,方便后续识别这次自动 review。
这类规则体现的是副作用控制:分析可以细,外部动作要少、准、可追踪。
排障类 Skill 要强制证据链
CI 分析、线上排障、测试失败定位这类 Skill,首先要防止 Agent 猜。
可以加一条硬约束:每个结论至少要同时有两类证据:
- 日志证据:关键错误行、失败 job、失败测试名。
- 代码或配置证据:对应文件、脚本、配置项,以及错误如何传播到失败结果。
如果缺一类证据,就只能标成“待补证据”,不能高置信度下结论。尤其是 flaky 判断,必须有历史运行、错误类型和近期代码改动三方面支撑,不能看到一次超时就说“可能是环境问题”。
这种写法会慢一点,但结论质量更高。
Generator 必须绑定事实来源
生成 PR 标题、PR body、commit message、周报、故障复盘时,Agent 很容易写出漂亮但不准确的内容。
Generator Skill 应该明确要求先读取事实来源:
- 当前 diff
- commit 列表
- 变更文件
- 测试结果
- PR 模板
- issue 或设计文档
然后再生成结构化输出。还要写清楚:不知道的测试结果就写“未验证”,不要伪造;模板里有字段就保留字段,不要为了省事删掉。
这类 Skill 的质量不取决于文案多漂亮,而取决于它是否忠实反映真实改动。
完成前要有验证门
很多 Agent 的坏习惯是“改完就说完成”。可以加一个简单的门槛:在宣称完成、修好、通过之前,必须先执行或说明验证。
这个设计可以作为所有 Pipeline Skill 的最后一关:
- 做了什么改动。
- 跑了什么验证。
- 验证是否通过。
- 哪些验证没跑,为什么没跑。
如果没有最新验证结果,就不要说“已完成”。只能说“已修改,尚未验证”。
Skill 是辅助,不是目的
选择 Skill 本身也需要边界。好的元 Skill 不应该让每个请求都变复杂,只需要提醒自己:
- 用户明确点名某个 Skill 时优先使用。
- 当前任务明显匹配某个 Skill 时再使用。
- 简单任务直接做,不要为了走流程而走流程。
- 一次只用真正有帮助的 Skill,不要把相关 Skill 全部堆上来。
Skill 的目标是降低重复劳动和质量波动,不是把所有请求都变成流程表演。
Tool Wrapper 要把确定性部分交给脚本
抓取 X/Twitter 内容、解析日志、生成固定格式文件,这类任务不应该主要靠自然语言推理。更稳的设计是:
SKILL.md说明什么时候用、怎么调用、输出怎么看。scripts/放可执行脚本。- README 或 reference 放完整参数说明。
Agent 负责选择正确工具和解释结果,脚本负责确定性执行。这比让模型临场拼接口、猜参数稳定得多。
大型参考资料要拆到 references
Postgres、Kubernetes、云服务最佳实践这类知识很大,不适合全部塞进 SKILL.md。
更好的方式是主文件只做索引:
|
|
需要优化查询时读 query 相关规则;需要审 RLS 时读 security 相关规则。这样既能保留大量知识,又不会每次触发 Skill 都占满上下文。
复杂状态机要脚本化
如果一个 Skill 要维护游戏状态、牌张守恒、合法动作、胡牌判定,或者任何强一致状态机,纯文本约束通常不够。
这类 Skill 可以先用文字跑通交互,但长期应该把关键逻辑下沉到脚本:
- 状态初始化
- 合法动作生成
- 规则校验
- 结算
- 不变量检查
SKILL.md 只保留交互流程和调用方式。确定性逻辑越多,越应该代码化。
一个可复用模板
可以从这个模板开始:
|
|
这个模板不要原样长期保留。真正写 Skill 时,要删掉不需要的段落,把泛化词替换成具体任务。
质量检查清单
写完后可以按这张清单自查:
name是否短、小写、稳定、可读。description是否包含任务、触发场景和边界。- 这个 Skill 是否只做一类任务。
SKILL.md是否能在 1 分钟内读懂。- 是否明确输入、输出、停止条件和验证方式。
- 大段资料是否拆到了
references/或assets/。 - 确定性操作是否沉淀成脚本。
- 是否避免写入容易过期的事实。
- 是否用 2-3 个真实 prompt 测过触发是否准确。
- 是否观察过 Agent 实际会不会按预期读取文件和执行步骤。
结论
高质量 Skill 本质上是工程化的任务说明。它不该追求“什么都能做”,而要把一件重复任务稳定做好。
写 Skill 时优先想清楚四个问题:
- 什么时候触发?
- 具体做哪一件事?
- 成功结果长什么样?
- 如何验证没有跳步?
能回答这四个问题,再选择 Tool Wrapper、Generator、Reviewer、Inversion、Pipeline 中合适的模式,Skill 的质量通常就不会差。
参考: