1. 从"每次都要重新教AI"说起:agent-skills到底在解决什么
如果你最近半年深度用过 Claude Code、Cursor 这类 AI coding agent,大概率经历过这样一种循环:新开一个会话,agent 对你的项目结构、代码规范、提交习惯一无所知,你得重新贴一遍上下文,重新解释"我们团队用 pnpm 不用 npm""测试文件放在__tests__而不是test""提交信息要遵循 Conventional Commits"。解释完这一轮,会话用着用着上下文爆了,再开一个,又得从头来一遍。
这个循环的本质问题是:agent 的能力是通用的,但你的项目是具体的。通用能力靠模型本身,具体知识得靠你喂。而"喂"这件事,如果每次都靠手动粘贴,那 agent 带来的效率提升会被反复的重复劳动吃掉一大半。
agent-skills这个项目要解决的,就是把这层"项目专属知识"从一次性对话里抽出来,变成可复用、可版本管理、可被 agent 自动加载的技能包。你可以把它理解成给 AI coding agent 装的一套"岗位说明书 + 操作手册"——agent 在动手之前,先读一遍你写好的技能定义,知道这个项目里什么该做、什么不该做、按什么顺序做。
它适合谁?三类人最该关注。第一类是已经在用 Claude Code 或 Cursor 做日常开发、但还在靠"每次手动交代"的开发者;第二类是想把团队规范固化下来、让多个成员用同一套 agent 行为的团队负责人;第三类是刚接触 AI coding agent、还没建立起自己工作流的新手——从 skills 入手,比从零摸索提示词要省事得多。
需要先说清楚一点:agent-skills本身不是一个模型,也不是一个 IDE 插件,它更像是一套约定和工具链,围绕"技能(skill)"这个单位来组织 agent 的行为。下面我会从它的核心概念讲起,一路讲到怎么落地、怎么避坑。
2. 拆开 agent-skills 的核心概念:skill 到底是什么
2.1 skill 不是提示词模板,而是带触发条件的知识单元
很多人第一反应会把 skill 等同于"一段写好的提示词"。这个理解偏了。普通的提示词模板是"你贴进去,它才生效";而 skill 的关键特征是带触发条件——agent 在特定场景下会自己去查、自己去用。
一个 skill 通常包含三部分信息:什么时候用(触发描述)、用了之后做什么(操作指令)、做的时候参考什么(附带的脚本、模板、参考资料)。触发描述是灵魂,它决定了 agent 能不能在正确的时机想起这个 skill。写得好的触发描述,会让 agent 在遇到"用户要求提交代码"时自动去查提交规范 skill;写得差的,agent 根本不知道有这么个东西存在。
这里有个反直觉的点:skill 的价值不在于写得多全,而在于触发得准。我见过有人把整个项目的编码规范塞进一个 skill,结果 agent 每次加载都要吃掉大量上下文,反而拖慢了响应、挤占了真正需要推理的空间。正确的做法是按场景拆分——提交规范一个、测试写法一个、API 设计约定一个,各自独立触发。
2.2 渐进式加载:为什么 skill 不会一次性撑爆上下文
这是 agent-skills 设计里最值得琢磨的一点。如果所有 skill 在会话开始时就全部加载进上下文,那和把整个 wiki 贴进去没区别,上下文窗口很快就不够用了。
实际机制是渐进式披露(progressive disclosure):会话开始时,agent 只加载每个 skill 的元信息——也就是名字和触发描述,这部分很轻量,几十个 skill 加起来也就几百个 token。当 agent 判断当前任务命中了某个 skill 的触发条件,才去读取那个 skill 的完整内容。用完即走,不常驻。
这个设计带来的直接好处是:你可以放心地积累几十个 skill,而不用担心上下文被撑爆。代价是触发描述必须写得足够精准,否则 agent 判断不出来该不该加载。这就像图书馆的索引卡——卡片本身很短,但必须准确指向对应的书,索引写错了,书再好也找不到。
2.3 skill 和 MCP、和普通工具调用的区别
刚接触的人容易把 skill 和 MCP(Model Context Protocol)搞混。两者不是一回事,也不冲突。
MCP 解决的是"agent 能连到什么外部能力"——比如连数据库、连文件系统、连某个 API。它是能力接入层。而 skill 解决的是"agent 在特定场景下该怎么做"——它是行为知识层。一个 skill 里完全可以指导 agent 去调用某个 MCP 工具,但 skill 本身不提供工具。
打个比方:MCP 是给 agent 配的工具箱,skill 是告诉 agent"修水管的时候先关总阀、再拆接头"的操作手册。工具箱再全,没有手册,agent 也可能上来就拆接头,喷一身水。
理解了这三层关系,后面讲落地就顺了。
3. 目录结构与文件组织:skill 在磁盘上长什么样
3.1 一个 skill 的最小结构
skill 在文件系统里通常以目录形式存在,一个 skill 一个目录。最小结构长这样:
skills/ commit-convention/ SKILL.mdSKILL.md是核心文件,里面用 frontmatter 写元信息,正文写操作指令。一个典型的SKILL.md开头是这样的:
--- name: commit-convention description: 当用户要求提交代码、生成 commit message、或执行 git commit 时使用。定义本项目的提交信息格式规范。 --- # 提交信息规范 本项目遵循 Conventional Commits 规范,格式为: <type>(<scope>): <subject> type 取值:feat / fix / docs / style / refactor / test / chore ...description字段就是前面说的触发描述,它决定了 agent 什么时候会加载这个 skill。这个字段值得反复打磨,后面第 5 节会专门讲怎么写。
3.2 带附属资源的 skill 怎么组织
当 skill 需要附带脚本、模板、参考文档时,目录会扩展成:
skills/ api-design/ SKILL.md templates/ rest-endpoint.md graphql-query.md scripts/ validate-schema.sh references/ error-code-table.md这里有个重要的组织原则:SKILL.md 正文里只写"什么时候读哪个附属文件",不要把附属文件的内容抄进来。附属文件是懒加载的——agent 只有在 SKILL.md 里被明确指引时才会去读。这样即使一个 skill 附带了几十页参考资料,也不会在加载 skill 的瞬间全部灌进上下文。
我自己的习惯是把附属资源分成三类:templates/放可直接套用的模板,scripts/放可执行的校验或生成脚本,references/放查阅性质的表格和清单。分类清楚之后,SKILL.md 里的指引也更好写——"生成 REST 接口时读 templates/rest-endpoint.md"比"参考相关模板"要明确得多。
3.3 多 skill 项目的目录约定
当 skill 数量上到十几个,目录组织就开始影响可维护性了。常见的做法是按领域分组:
skills/ coding/ commit-convention/ test-writing/ error-handling/ review/ pr-review-checklist/ security-scan/ docs/ changelog-format/ api-doc-template/分组本身不影响 agent 的加载逻辑(agent 是按 description 匹配的,不是按目录层级),但影响人的维护效率。分组之后,找某个 skill 改起来快,也方便判断"这个领域我是不是覆盖全了"。
注意:不同工具对 skill 目录的默认扫描路径不一样。Claude Code 和 Cursor 各有自己的约定位置,落地前先确认你的工具从哪个目录读 skill,别写完发现根本没被扫描到。这一点在第 6 节会展开。
4. 触发机制深挖:agent 是怎么"想起"某个 skill 的
4.1 匹配发生在哪一步
理解触发时机,才能理解为什么有些 skill 死活不生效。整个流程大致是:用户发出请求 → agent 拿到请求和当前上下文 → agent 对照已加载的 skill 元信息列表,判断哪些 skill 相关 → 加载命中的 skill 完整内容 → 结合 skill 指令执行任务。
关键在第三步:判断相关性这一步是模型做的,不是规则引擎做的。这意味着触发不是精确的字符串匹配,而是语义判断。好处是灵活——用户说"帮我存一下代码"和"commit 一下"都能命中提交规范 skill;坏处是不确定——description 写得含糊,模型可能判断不出来。
4.2 为什么你的 skill 没被触发
这是实操中最高频的问题。我总结下来,skill 不触发基本逃不出这几个原因:
| 现象 | 根因 | 修法 |
|---|---|---|
| 完全不触发 | description 太抽象,没写具体场景 | 把"用于代码提交"改成"当用户要求提交代码、生成 commit message 时使用" |
| 偶尔触发 | 触发词覆盖不全 | 补上同义表达,如"提交""commit""存档""保存进度" |
| 触发太频繁 | description 范围过宽 | 收窄场景,避免"用于所有编码任务"这种写法 |
| 触发了但没用对 | SKILL.md 正文指令不清晰 | 把操作步骤写成有序列表,明确输入输出 |
我踩过最典型的一个坑:早期写了个 skill,description 写的是"帮助处理数据库相关任务"。结果 agent 几乎从不加载它——因为"数据库相关任务"太宽泛,模型判断不出具体什么时候该用。后来改成"当需要编写 SQL 查询、设计表结构、或排查慢查询时使用",命中率立刻上来了。
4.3 触发描述和正文指令的分工
一个常见的误区是把该写在正文里的操作细节塞进 description。description 的职责只有一个:让 agent 判断"现在该不该加载我"。它不该承担教学职责。
正确的分工是:description 回答"什么时候用",正文回答"怎么用"。description 里出现具体命令、代码片段、详细步骤,都是错位的——那些属于正文。description 越短越聚焦,触发判断越准。
5. 写一个高质量 skill 的实操路径
5.1 从"重复三次以上的事"开始
不要一上来就规划"我要写二十个 skill"。最务实的起点是:回顾你最近一周和 agent 的对话,找出你重复交代过三次以上的事情。那件事就是你的第一个 skill。
这个筛选标准很有效,因为它同时满足两个条件:一是高频,值得固化;二是你已经手动做过很多遍,知道正确的做法是什么,写起来不会空。反过来,那些你只做过一次、还没摸清门道的任务,先别急着写成 skill——写出来大概率是错的,还会误导 agent。
5.2 正文指令的写法:像给新人写交接文档
SKILL.md 正文的读者是 agent,但写法应该参照"给一个聪明但完全不了解你项目的新人写交接文档"。几个要点:
- 先给结论,再给细节。开头一句话说清这个 skill 管什么,别铺垫。
- 步骤用有序列表。agent 对有序步骤的执行准确率明显高于散文式描述。
- 给正例也给反例。"提交信息写成
fix: 修复登录bug"是正例,"不要写成修复了一下"是反例。反例能有效防止 agent 自由发挥。 - 明确边界。写清楚"这个 skill 不负责什么",避免 agent 越界。
举个我实际在用的例子,测试写法 skill 的正文片段:
# 测试文件写法 ## 步骤 1. 测试文件放在与被测文件同级的 `__tests__` 目录下 2. 文件名格式为 `<被测文件名>.test.ts` 3. 使用 vitest,不用 jest 4. 每个 describe 块对应一个导出函数 ## 正例 __tests__/formatDate.test.ts ## 反例 test/formatDate.spec.js (目录错、后缀错、框架错)这种写法 agent 执行起来几乎不会跑偏。
5.3 用真实任务验证,而不是"看起来对"
skill 写完,别急着收工。拿三个真实任务去跑:一个应该触发它的、一个不该触发它的、一个边界模糊的。看 agent 的实际行为是否符合预期。
我自己的验证清单是这样的:
- 明确该触发的任务,agent 是否加载了 skill 并按指令执行?
- 明确不该触发的任务,agent 是否克制住了没乱加载?
- 边界任务,agent 的判断是否和你的直觉一致?不一致的话,是 description 的问题还是你预期的问题?
第三项最有价值。很多时候你会发现,不是 skill 写错了,而是你自己都没想清楚"这件事到底该不该走这个流程"。这种时候改 skill 之前,先改自己的认知。
5.4 迭代节奏:小步改,别大重写
skill 的维护和代码一样,忌讳大重写。每次只改一个点——要么调 description,要么补一条正文指令,要么加一个反例——然后立刻验证。一次改太多,出问题了你都不知道是哪处改动导致的。
我一般会给每个 skill 在正文末尾留一个"变更记录"小节,简单记一下每次改了什么、为什么改。这个习惯在 skill 数量多了之后特别有用,能避免"这个 skill 为什么长这样"的困惑。
6. 在 Claude Code 和 Cursor 里落地:路径、配置与差异
6.1 Claude Code 的 skill 加载位置
Claude Code 对 skill 的支持是通过约定目录实现的。项目级的 skill 通常放在项目根目录下的特定文件夹里,会话启动时自动扫描。具体路径以你所用版本的文档为准——这类工具的目录约定迭代较快,写死一个路径容易过时。
落地时的关键动作是:确认扫描路径 → 把 skill 目录放进去 → 新开会话验证是否被识别。验证方法很简单,直接问 agent"你现在有哪些可用的 skill",看它列出来的清单里有没有你刚放的。
提示:项目级 skill 和用户级 skill 是两回事。项目级的跟着仓库走,团队成员拉下来就有;用户级的只在你本机生效。团队协作场景优先用项目级,个人习惯类的用用户级。
6.2 Cursor 场景下的注意事项
Cursor 的 skill 机制和 Claude Code 不完全一样,它更依赖 rules 体系和上下文注入。在 Cursor 里落地 agent-skills 的思路,通常是把 skill 的内容转成 Cursor 能识别的规则文件,或者通过项目内的约定文件让 agent 读取。
这里有个实操差异值得注意:Cursor 的规则触发更偏向文件路径和 glob 匹配,而 Claude Code 的 skill 触发更偏向语义判断。这意味着同一套 skill 内容,在两个工具里可能需要不同的触发描述写法。在 Cursor 里,你可能需要明确写"当编辑src/api/**下的文件时应用此规则",而在 Claude Code 里,语义化的"当设计 API 接口时使用"就够了。
6.3 两个工具的能力对照
| 维度 | Claude Code | Cursor |
|---|---|---|
| 触发方式 | 语义判断为主 | 路径/glob 匹配为主 |
| 加载粒度 | 按 skill 整体加载 | 按规则文件加载 |
| 附属资源 | 支持懒加载附属文件 | 依赖上下文引用 |
| 团队共享 | 项目级目录随仓库走 | 规则文件随仓库走 |
| 适合场景 | 复杂流程、多步骤任务 | 文件类型相关的规范约束 |
这张表不是绝对的,两个工具都在快速迭代。但它能帮你判断:同一份知识,在哪个工具里用什么形式表达最有效。我的经验是,流程性的知识(先做什么后做什么)在 Claude Code 里表达更自然,约束性的知识(这类文件必须怎么写)在 Cursor 里表达更直接。
6.4 跨工具复用的一份内容两份表达
如果你同时用两个工具,不必维护两套完全独立的内容。做法是:核心知识写一份,触发层各写各的。比如"API 设计规范"这份知识,正文内容两个工具共用,但 Claude Code 那边配一个语义化的 description,Cursor 那边配一个 glob 规则指向src/api/**。知识不重复,触发各适配。
7. 踩坑实录:那些让我返工的细节
7.1 description 写成了"功能说明书"
我最早写 skill 时,description 写的是"这个 skill 提供了代码格式化的能力,包括缩进、换行、命名规范等"。结果 agent 几乎不触发它。问题在于:这句话描述的是"skill 有什么功能",而不是"什么时候该用它"。模型需要的是场景信号,不是功能清单。
改成"当用户要求格式化代码、统一命名风格、或调整缩进时使用"之后,触发率立刻正常了。这个坑的本质是:站在使用者的场景角度写,而不是站在作者的介绍角度写。
7.2 一个 skill 塞了太多不相关的内容
有段时间我图省事,把"代码规范 + 提交规范 + 测试规范"全塞进一个 skill。结果是:agent 每次因为提交任务加载这个 skill,却顺带读进了一大堆代码规范和测试规范,上下文被无谓占用,而且执行提交任务时还可能被无关指令干扰。
拆成三个独立 skill 之后,不仅上下文省了,每个 skill 的指令也更聚焦、执行更准。skill 的粒度应该按"触发场景"来切,而不是按"知识领域"来切。同一个领域里,如果触发场景不同,就该拆开。
7.3 附属文件路径写成了绝对路径
skill 里的附属文件引用,一定要用相对于 skill 目录的路径,别用绝对路径。绝对路径在你本机跑得通,团队成员拉下来就全断了。这个坑很蠢,但真的常见——尤其是从本机调试直接复制粘贴的时候。
7.4 忘了处理"skill 之间的冲突"
当两个 skill 对同一件事给出不同指令时,agent 会困惑。比如一个 skill 说"测试文件放__tests__",另一个旧 skill 说"测试文件放test"。这种冲突不会报错,但会导致 agent 行为不稳定。
我的做法是定期做一次"skill 审计":把所有 skill 的正文过一遍,看有没有互相矛盾的指令。有冲突就合并或废弃旧的。skill 数量上到二十个以上,这个审计就很有必要了。
7.5 把 skill 当成了"一次性写完就完事"
skill 是活的。项目规范变了、工具版本升级了、团队习惯了改了,skill 都得跟着改。我见过团队把 skill 写完就扔在那,半年后新人拉下来用,发现里面的规范早就和实际代码对不上了,反而误导 agent。
建议把 skill 的维护纳入常规流程——比如每次代码规范变更时,顺手检查相关 skill 要不要更新。这和在改代码时顺手更新文档是一个道理。
8. 从个人用到团队用:skill 的协作与演进
8.1 把 skill 纳入版本管理
skill 是项目知识的一部分,应该和代码一起进版本库。这样带来的好处很直接:新人拉下仓库就自带一套 agent 行为规范,不用口口相传;skill 的每次变更都有记录,能追溯"为什么这条规范是这样"。
目录上,我建议把 skill 放在项目根目录下一个显眼的位置,并在 README 里说明它的作用和维护方式。别藏在某个深层目录里,否则没人会想起来维护它。
8.2 团队协作中的分工
skill 的维护不该是某一个人的事。比较顺的分工是:每个领域的负责人维护自己领域的 skill。写 API 的人维护 API 设计 skill,管发布的人维护 changelog skill。这样 skill 的内容质量有保障,也不会全压在一个人身上。
配套的机制是变更评审:skill 的修改走和代码一样的评审流程。这听起来有点重,但能有效防止"某人随手改了一条规范,结果全团队的 agent 行为都变了"这种事故。
8.3 什么时候该废弃一个 skill
skill 不是越多越好。当出现这些信号时,就该考虑废弃或合并:触发率极低(说明场景不成立)、内容和其他 skill 大量重叠(说明该合并)、规范已经过时且没人维护(说明是负担)。
废弃时别直接删,先在正文里标记 deprecated 并说明替代方案,观察一段时间再清理。这样能给还在依赖它的成员一个过渡期。
8.4 一个团队落地的真实节奏
如果让我给一个团队规划落地节奏,大概是这样:第一周,每个人梳理自己重复交代最多的事,各写一到两个 skill;第二周,团队一起过一遍,合并重复的、拆开过大的;第三周,把 skill 纳入版本库和评审流程;之后就是持续迭代。
别追求一步到位。skill 体系是长出来的,不是设计出来的。先跑起来,再优化。
9. 我个人的几条经验
用 agent-skills 这套东西大半年,最深的体会是:它的价值不在"让 agent 更聪明",而在"让 agent 更懂你"。模型能力是公共的,但项目知识是私有的,skill 就是把私有知识固化下来的载体。
几条具体的经验。第一,从痛点出发,别从体系出发。先解决那个让你最烦的重复劳动,别一上来就想着建一套完整的 skill 体系。第二,description 值得花一半的时间打磨。触发不准,正文写得再好也白搭。第三,定期审计,别让 skill 腐烂。过时的 skill 比没有 skill 更糟,因为它会主动误导 agent。
最后一个技巧:如果你不确定某个 skill 该不该拆,就问自己"这两部分内容会不会在同一个任务里同时用到"。会,就放一起;不会,就拆开。这个判断标准简单,但很准。