同一个 Agent,昨天刚被夸聪明,今天换个会话就忘了你上周定的代码规范;明明在提示词里塞了三千字的流程说明,一换任务它又当没看见。做 AI Agent 开发的人,大概率都经历过这种"它明明能行,就是不稳定"的挫败感。而这两年围绕 agent skills 折腾下来,我最大的感受是:问题往往不在模型,而在我们给它喂知识的方式太糙。今天要聊的 agent-skills,说白了就是一套把"某类任务该怎么做"打包成可复用、可版本管理、可按需加载的模块化能力单元的方法论。它解决的核心痛点非常具体——上下文越塞越满、经验越写越散、跨项目复用全靠复制粘贴。不管你是在做 Claude Code、Codex 这类编码 Agent,还是在自研 Agent 框架里调教工具链,只要你有"希望它稳定执行某类固定流程"的需求,这套东西都值得认真看一遍。我会从概念边界、目录结构、从零实现、平台对比一直讲到踩坑排查,尽量把每一步背后的"为什么"都说明白。
1. 先把概念掰开:Agent 和 Skills 到底差在哪
1.1 一句话说清两者关系
我见过太多人把这两个词混着用,结果讨论半天不在一个频道上。我的定义是这样的:Agent 是"会自己决定下一步做什么的执行体",它负责规划、调用工具、处理反馈、循环推进;而 Skill 是"针对某类任务的know-how封装包",它不主动决策,只是在 Agent 需要时告诉它"这件事通常怎么做最靠谱"。
打个比方,Agent 像是一个刚入职的聪明实习生,脑子快、学东西快,但没经验;Skill 就像公司里沉淀下来的操作手册——"报销单怎么填""客户投诉按什么话术回复""线上出故障先看哪几个指标"。手册不会自己干活,但实习生翻一翻就能少踩很多坑。关键在于,手册是按需取用的,不需要在实习生上班第一天就把整本手册背下来。
这个区分为什么重要?因为它直接决定了你的优化方向。如果你的 Agent 表现不稳,先问自己:是它决策能力不行(那要去调框架、换模型、改规划策略),还是它缺某块具体知识(那应该去写 Skill)。这两个方向的修法完全不同,搞反了就是白费功夫。
1.2 为什么 Skills 会火:上下文成本的账要算清楚
Skills 这波热度不是凭空来的,根子是上下文窗口的经济学问题。早期大家调 Agent 的习惯是"什么都往系统提示词里塞"——代码规范、输出格式、常见错误、业务背景,全堆在一段超长 prompt 里。这么做有几个致命问题:
- 每次请求都在为无关知识付费:用户只是问个"这个函数干什么的",你却把整套部署流程也一起喂了进去,token 白白烧掉。
- 知识之间互相干扰:塞得越多,模型注意力越容易被稀释,反而抓不住当前任务的重点。
- 改一处动全局:想把"提交规范"单独调整一下,得在一大段文本里小心翼翼地改,极其容易误伤。
- 无法复用:换个项目、换个团队,这段巨型 prompt 基本得重写。
Skills 的思路正好反过来:把知识切成小块、每块自带触发条件、用到才加载。这就把"一锅端"变成了"点菜"。你只在做代码审查时才加载审查规范,只在写周报时才加载周报模板。上下文立刻清爽,模型注意力也集中了。实测下来,同一个 Agent 在加了几个精准 Skill 之后,任务完成的一致性提升很明显,尤其是那种"流程长、步骤多"的任务,差异肉眼可见。
1.3 Skills 和 Prompt、Tool、MCP 的边界在哪
概念要立得住,得把邻近的东西都划清楚,否则还是会乱。我用一张表来对比,这是我自己梳理时用得最顺的一版:
| 概念 | 它是什么 | 谁来决定用不用 | 典型例子 |
|---|---|---|---|
| Prompt | 单次发给模型的指令文本 | 开发者手动拼 | "把这段代码改成 TypeScript" |
| Tool | Agent 可调用的函数/接口 | 模型自主决定调用 | 读文件、执行命令、查数据库 |
| MCP | 一套把外部能力接进来的协议标准 | 配置后由模型调用 | 连数据库、连第三方服务 |
| Skill | 某类任务的方法论封装(含说明+可选脚本+资源) | 由元数据描述触发,模型按需加载 | 论文检索流程、代码审查清单 |
看这张表应该就清楚了:Tool 和 MCP 解决的是"Agent 能碰到什么",Skill 解决的是"Agent 碰到之后该怎么做"。一个是手,一个是手艺。很多人搭了很全的 MCP 工具链,Agent 却还是干不好活,原因往往就是只有手没有手艺。
至于 Skills 和"Agent 记忆"的区别,也得点一句。记忆是记录"发生过什么"(用户偏好、历史结论),Skill 是记录"该怎么做"(可复用的流程知识)。两者配合才好用:记忆提供个性化上下文,Skill 提供通用方法论。
2. Skills 的目录结构:为什么长这样
2.1 SKILL.md 的元数据设计
一个标准的 Skill,核心就是一个文件夹,里面最关键的是SKILL.md。它通常由两部分组成:顶部的元数据(YAML front matter 风格)和下面的正文说明。元数据里最不能少的是两个字段——name和description。
--- name: paper-search description: 当用户需要检索学术论文、整理文献综述、或查找某篇论文的引用来源时使用。涵盖关键词扩展、来源筛选与结果去重。 ---别看就这两行,门道不少:
name要短、要唯一、用连字符。它是索引键,写得太随意后期根本管不过来。description是整个 Skill 的"触发器",也是最容易写砸的地方。模型是否加载这个 Skill,几乎全靠这段描述。写法上要回答两个问题:什么场景下用(触发条件)+能提供什么(能力范围)。我踩过的坑是把 description 写成功能介绍——"这个 Skill 可以检索论文",结果模型经常想不起来用它。改成"当用户需要……时使用"这种场景化表述后,命中率明显好了很多。
还有一个常被忽略的细节:description 不要写得太长。它和其他 Skill 的 description 一起被预加载到上下文里,太长会挤占空间,也削弱区分度。我的经验是控制在两三句话、大约 50 到 100 个词,把最独特的触发词放前面。
2.2 渐进式披露:三层加载模型
Skills 真正精妙的地方在于它的加载机制,业内常叫"渐进式披露"(progressive disclosure)。理解这一层,你才算真的懂了 Skills 的设计哲学。
它的加载大致分三级:
- 第一级——元数据常驻:所有已安装 Skill 的
name+description会一直待在上下文里。开销极小,但让模型"知道自己有哪些技能可以召唤"。 - 第二级——正文按需加载:当模型判断某个 Skill 相关,才会把
SKILL.md的完整正文读进来。这里放具体步骤、流程、注意事项。 - 第三级——附属资源延迟加载:正文里可以引用外部文件(脚本、模板、参考文档),这些只有真正执行到那一步才会被读取。
这个设计的价值用一个数字类比你就懂了:假设你有 20 个 Skill,每个正文 2000 token。如果全量加载,就是 4 万 token 的常驻开销;而渐进式披露下,常驻的只有 20 条 description,可能才 1000 token 出头,剩下的按需来。差了两个数量级。
所以写 Skill 的时候要顺着这个机制来:元数据负责"被想到",正文负责"被用对"。别把大段参考资料硬塞进正文,而是拆成独立文件在正文里引用——这既是省 token,也是让结构更清晰。
2.3 资源文件与脚本的组织原则
一个稍微复杂点的 Skill,文件夹里通常不止SKILL.md,还会有脚本、模板、参考资料。我的组织习惯是这样的:
paper-search/ ├── SKILL.md # 主说明:元数据 + 核心流程 ├── scripts/ │ └── dedupe.py # 去重等确定性逻辑,交给脚本 ├── references/ │ └── sources.md # 来源列表等长文档 └── assets/ └── template.md # 输出模板这里有两条我反复验证过的原则:
第一,能用脚本就别用自然语言描述。凡是确定性的、重复性的逻辑(比如去重、格式转换、批量重命名),写成脚本让 Agent 调用,比用文字描述"请确保结果不重复"可靠得多。自然语言描述有歧义,脚本没有。
第二,长文档一律外置。参考知识、数据表、API 文档这类内容,放进references/目录,在正文里说明"需要时读哪个文件"。这样正文能保持精简,模型读正文时不会被无关信息干扰。
这两条合起来,其实就是一句话:把 Skill 当成一个小型工程项目来组织,而不是一段长文本。
3. 从零写一个能用的 Skill
3.1 需求定位:什么该做成 Skill,什么不该
动手前先想清楚一件事:不是所有知识都值得做成 Skill。我总结的判断标准是——如果一个流程会被反复用到、步骤相对固定、且当前 Agent 总是做不好,那它就适合做成 Skill。
反过来,这几种情况我会劝你先别急着写:
- 一次性任务:只做这一次的事,直接对话解决就行。
- 纯知识问答:模型本身就答得不错的常识,没必要封装。
- 强个性化偏好:这种更适合放记忆,而不是 Skill。
举个我自己的例子。我一开始特别想给"写周报"做个 Skill,因为每周都要写。但后来发现,我真正痛的不是"不知道周报格式",而是"懒得整理这周干了啥"。于是我把 Skill 的重点从"格式模板"转到了"从 git 提交记录和任务清单里提炼要点的流程"——这才是可复用的、Agent 确实做不好的部分。定位对了,Skill 才有价值。
3.2 撰写 SKILL.md 的实操模板
下面是我现在常用的一套模板骨架,可以直接抄去改:
--- name: code-review-checklist description: 当用户要求审查代码、检查提交、或询问某段实现是否符合团队规范时使用。提供分层审查清单与常见反模式。 --- # 代码审查清单 ## 何时使用 用户提交代码片段、请求 review、或提到"检查""规范""反模式"时。 ## 审查流程 1. 先看结构:函数职责是否单一,命名是否表意。 2. 再看边界:异常处理、空值、并发场景是否覆盖。 3. 然后看安全:输入校验、敏感信息、权限判断。 4. 最后看可维护性:注释、复杂度、重复代码。 ## 输出格式 按「问题 - 位置 - 建议」三段式列出,严重程度用 高/中/低 标注。 ## 注意事项 - 不确定的地方标注"需确认",不要臆断。 - 详见 references/antipatterns.md。几个写作要点,都是踩坑换来的:
- 流程步骤要编号,让模型能一步步跟着走,而不是自由发挥。
- 输出格式必须明确,否则每次结果长得都不一样,没法用。
- "注意事项"这一节是关键,把你希望它避免的坑直接写出来。
- 正文控制在合理长度,我一般压在一屏到两屏内,超出的部分外置。
3.3 打包、安装与验证
写好之后就是安装。不同平台的安装方式略有差异,但核心逻辑一致:把 Skill 文件夹放到平台约定的目录下,让它被扫描到。
以主流的编码 Agent 工具为例,通常有两种方式:一种是放到项目级目录(比如项目根下的.xxx/skills/),这类 Skill 只在当前项目生效;另一种是放到用户级目录,全局可用。这个区分很实用——项目专属的规范用项目级,个人通用习惯用用户级,别全塞一个地方。
安装完一定要验证,我的验证三步走:
- 看是否被识别:多数工具能列出已加载的 Skill,确认你的出现在列表里。
- 测触发:用一句符合 description 场景的话去问,看它有没有加载对应 Skill。
- 测执行:走一个完整流程,检查输出格式和步骤是否符合预期。
这三步里最容易翻车的是第二步。如果没触发,九成是 description 写得不够"场景化",回去改触发条件就行。
3.4 版本管理与团队共享
Skill 本质上是一份文档化的工程资产,那它就该享受工程资产该有的待遇——进版本控制。我现在的做法是把项目级 Skill 和代码一起提交到仓库,谁改了流程、为什么改,都留痕。这样新人拉下代码就自带团队规范,不用靠口头传承。
团队共享时我还加了一条纪律:一个 Skill 只解决一类问题。有人喜欢把"代码审查+提交规范+部署流程"揉进一个 Skill,结果就是又变成了一锅端,触发了还嫌它啰嗦。拆开之后,每个都能精准命中,维护时也互不干扰。
4. 主流平台的 Skills 生态横向对比
4.1 编码类 Agent 的 Skills 支持现状
目前 agent skills 这个概念在编码类 Agent 上落地得最成熟,几个主流工具的思路大同小异,但细节各有取舍。我按我用下来最在意的几个维度做了个对比:
| 维度 | 特点与差异 |
|---|---|
| 存放位置 | 多为项目级目录 + 用户级目录双轨,优先级不同 |
| 触发机制 | 均依赖 description 语义匹配,写法影响命中率 |
| 资源引用 | 支持正文内引用脚本与文档,实现延迟加载 |
| 自定义脚本 | 大多允许 Skill 内嵌可执行脚本 |
| 生态共享 | 可通过仓库或市场分发,质量参差不齐 |
我给的建议是:别太纠结选哪个平台,先把 Skill 的写法练熟。因为 description 怎么写、流程怎么拆、资源怎么组织,这套功夫是跨平台通用的。哪怕你明天换工具,Skill 挪过去稍改元数据就能用。真正难迁移的是那些绑定平台 API 的脚本,所以我在脚本里尽量只用通用的命令行工具。
4.2 国内工具链的 Skills 落地
国内不少 AI 编程工具也在跟进 Skills 这类机制,思路基本一致,差异主要在生态整合度上。我用下来觉得它们的优势是和本地开发环境贴合得紧,比如和一些国产 IDE、代码平台打通得比较顺;不足是公开的优质 Skill 样例还偏少,很多时候得自己写。
这里有个取巧的办法:先把开源社区里质量高的 Skill 拿来当范本读。读别人的 Skill 是提升最快的路径,你能看到别人怎么组织流程、怎么写 description、怎么设计输出格式。我前期就专门收集了十来个写得好的 Skill,拆解完再写自己的,效率高很多。
4.3 组合搭配:别把 Skills 用成孤岛
Skills 真正的威力在于组合。举个我实际在用的链条:一个"需求拆解" Skill 负责把模糊需求拆成任务清单,一个"编码规范" Skill 负责实现风格,一个"测试生成" Skill 负责补单测,一个"提交信息" Skill 负责生成规范的 commit。四个 Skill 各管一段,串起来就是一条半自动的开发工作流。
这里的关键是接口要对齐:上一个 Skill 的输出格式,要是下一个 Skill 能直接吃的。比如"需求拆解"输出的任务清单用 Markdown 列表,"编码规范"就按列表逐条处理。对齐接口这件事,比拼单个 Skill 写得多漂亮更重要。
5. 踩坑与排查实录
5.1 常见失效场景与原因
这部分是我最想分享的,因为都是真金白银踩出来的。Skills 用了这么久,翻车主要集中在几个地方:
第一种:Skill 写了但从不触发。原因几乎总是 description 太笼统或场景描述缺失。修法是把触发场景写具体,把用户可能说出的关键词覆盖进去。
第二种:触发了但输出不稳定。多半是流程步骤写得不够死,给了模型太多自由发挥空间。修法是把关键步骤编号、把输出格式模板化、把"必须"和"禁止"明确写出来。
第三种:引用文件读不到。常见于路径写错或用了相对路径但工作目录不对。修法是尽量用相对 Skill 根目录的稳定路径,并在正文里写清楚文件用途。
第四种:多个 Skill 互相打架。两个 Skill 的 description 场景重叠,模型不知道该用哪个。修法是明确边界,必要时在 description 里写"仅当……时使用,不适用于……"。
5.2 排查速查表
为方便对照,我整理了一张速查表,出问题先按这个过一遍:
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| 不触发 | description 场景模糊 | 重写 description,补触发关键词 |
| 触发但跑偏 | 流程步骤不明确 | 给步骤编号,明确禁止项 |
| 格式每次不同 | 缺输出格式约束 | 加输出模板,规定字段 |
| 资源读取失败 | 路径错误 | 检查相对路径与文件位置 |
| 冲突误用 | 多个 Skill 场景重叠 | 划清边界,加适用/不适用说明 |
| 加载很慢 | 正文或资源过大 | 外置长文档,压缩正文 |
5.3 怎么评测一个 Skill 好不好用
最后说说测评。市面上 Skill 样例越来越多,质量参差不齐,我自己有一套简单的评估维度:
- 触发准确率:给十句不同说法,看它命中几回,再看它有没有该不该触发时乱触发。
- 输出一致性:同样的输入跑三遍,输出结构与字段是否稳定。
- 边界处理:遇到模糊、缺失信息时,是硬编还是主动询问。
- 维护成本:想改一个步骤,要不要动一大片内容。
这四条里,我最看重"触发准确率"和"输出一致性"。前者决定它能不能被想起来用,后者决定它能不能被信任。一个 Skill 如果输出每次都不一样,那再聪明也是添乱。
6. 几个进阶玩法和我的个人体会
6.1 让 Skill 自我进化
Skill 不是写完就锁死的。我会在用的过程中记录"这次它哪一步做错了""这个场景它没识别出来",攒一批就去改。改的时候有个原则:只改最小必要部分。比如只是没触发,那就只动 description,别顺手把正文重写,否则容易引入新问题。这种小步迭代,比一次大改安全得多。
另外,当同一个 Skill 的正文开始变长、开始出现"如果 A 情况就……如果 B 情况就……"的分支时,这是个信号——该拆了。把它拆成两个边界清晰的 Skill,往往比继续堆条件更有效。
6.2 和记忆、工具链怎么配合
前面提过,Skill 管"怎么做",记忆管"发生过什么",工具管"能碰什么"。三者配合的最佳姿势是:工具提供能力底座,Skill 提供方法指引,记忆提供个性化上下文。
举个具体场景。用户让我"按老规矩整理这周的进展"。这里的"老规矩"如果每次都写进 prompt 就太蠢了——它应该进记忆或 Skill。我的做法是把"整理流程"做成 Skill,"个人的偏好措辞"放记忆。这样换个同事用,流程照旧,只是措辞变成他自己的。
6.3 关于学习路线的建议
如果你刚开始接触 agent skills,我建议的路线是:先读十个别人写得好的 Skill,再抄一个改成自己的,最后从自己最重复的工作里提炼第一个原创 Skill。别一上来就想着搭一套大而全的 Skill 体系,那样很容易摊子铺太大,最后一个都用不起来。
从最小的、最痛的点切入——哪怕就是"每次提交前自动检查有没有忘记删调试代码"这种小事。当你亲手写的第一个 Skill 真的帮你省了事,你自然就理解了这套东西的价值,后面扩展就是水到渠成的事。
我个人的体会是,Skills 最反直觉的地方在于:它逼着你把一个模糊的"经验"写成一个精确的"流程"。这个过程本身就很有价值——很多人写 Skill 写到一半才发现,原来自己一直以为"很明显"的步骤,其实从来没说清楚过。写 Skill 某种程度上是在给自己做知识梳理,Skill 只是顺带的产物。所以哪怕你最后不用这套机制,光是把它当成一次把经验文档化的练习,也值了。