1. agent-skills 到底在解决什么问题
第一次看到agent-skills这个词,很多人会以为是某个新出的 AI 模型或者框架。其实它更接近一个"能力包"的概念——把 AI coding agent 需要掌握的技能,用结构化的方式组织起来,让 agent 在特定任务上表现得更稳定、更可控。
我最初接触这个概念是在折腾 Claude Code 的时候。当时遇到一个很实际的问题:默认状态下,Claude Code 能写代码、能改文件、能跑命令,但它在某些特定任务上的表现忽好忽坏。比如让它写测试,有时候它会先写实现再补测试,有时候干脆跳过测试直接给实现。这种不确定性在个人玩票时无所谓,但一旦放到真实项目里,就是灾难。
agent-skills要解决的核心问题就是这个:把"希望 agent 怎么做"变成"规定 agent 必须怎么做"。它通过一套约定好的目录结构和文件格式,把特定领域的知识、流程、约束条件打包成 skill,agent 在执行任务时会自动加载相关 skill,按照里面定义的步骤和规则来工作。
关键词里提到的test-driven-development就是一个典型的 skill 场景。TDD 的流程是固定的:先写测试,测试失败,再写实现,测试通过,重构。这个流程如果靠 prompt 里每次提醒,既啰嗦又不可靠。但把它做成一个 skill,agent 在检测到"写新功能"这类任务时就会自动套用 TDD 流程,不需要人反复强调。
从更宏观的视角看,agent-skills代表了一种趋势:AI coding agent 正在从"通用助手"向"专业化工具"演进。通用助手什么都能聊,但什么都不精;专业化工具在特定场景下表现远超通用助手。skills 就是实现这种专业化的手段之一。
适合读这篇内容的人大概分三类:一是已经在用 Claude Code 或其他 AI coding agent,想让它更听话的开发者;二是团队里在推 AI 辅助开发,需要标准化流程的技术负责人;三是对 agent 架构感兴趣,想了解 skill 机制怎么设计的技术爱好者。不管哪一类,理解agent-skills的工作方式都有实际价值。
2. skills 的目录结构与加载机制
2.1 一个 skill 长什么样
agent-skills的核心是约定优于配置。一个 skill 本质上就是一个文件夹,里面放一个SKILL.md文件,再加上可选的辅助文件。目录结构大概是这样:
skills/ test-driven-development/ SKILL.md examples/ example-test.md templates/ test-template.md code-review/ SKILL.mdSKILL.md是整个 skill 的入口,它用 YAML frontmatter 定义元信息,用 Markdown 正文描述具体内容。一个典型的SKILL.md开头是这样的:
--- name: test-driven-development description: 当需要实现新功能或修复 bug 时,按照 TDD 流程编写测试和实现 ---name是 skill 的唯一标识,description是关键——agent 会根据这个描述判断当前任务是否需要加载这个 skill。所以 description 写得准不准,直接决定了 skill 会不会在正确的时机被触发。
正文部分就是具体的指令。可以写流程步骤、可以写约束条件、可以写示例代码。Markdown 的好处是 agent 读起来自然,人读起来也清楚。
2.2 skill 是怎么被加载的
这里涉及一个很多人会忽略的细节:skill 不是一次性全部加载的。如果所有 skill 的内容都塞进 context,token 消耗会爆炸,而且 agent 的注意力会被分散。
实际的工作方式是渐进式加载。agent 启动时只读取所有 skill 的name和description,形成一个轻量的索引。当用户提出一个任务时,agent 拿任务描述去匹配这些 description,匹配上的 skill 才会被完整加载。
这个机制解释了一个常见困惑:为什么我写了一个很详细的 skill,但 agent 好像没用上?大概率是 description 没写好,匹配阶段就没被选中。description 要写得像"触发条件"而不是"功能说明"。比如写"当需要实现新功能时使用"就比写"这是一个 TDD 技能"要好得多。
2.3 为什么用 Markdown 而不是 JSON 或代码
有人会问,为什么 skill 用 Markdown 而不是结构化的 JSON 或者 Python 代码?我自己的理解是三个原因。
第一,Markdown 对 LLM 最友好。LLM 的训练数据里 Markdown 占比极高,它对 Markdown 的结构理解得最透彻。用 JSON 写指令,agent 反而容易在嵌套结构里迷失。
第二,人机双读。skill 不只是给 agent 看的,也是给人看的。团队里新来的同学想知道 TDD 流程怎么走,直接打开SKILL.md就能看懂,不需要额外的文档。
第三,修改成本低。改一个流程步骤,直接编辑 Markdown 就行,不需要动代码、不需要重新编译、不需要跑测试。这种低摩擦的迭代方式,让 skill 能快速演进。
提示:如果你的 skill 里需要包含代码示例,建议用代码块标注语言类型。agent 对带语言标注的代码块理解更准确,不容易把示例代码和实际要执行的代码搞混。
3. 从零写一个 TDD skill 的完整过程
3.1 先想清楚要约束什么
写 skill 之前,先别急着打开编辑器。我踩过的坑是:一上来就写,结果写出来的东西又长又乱,agent 根本抓不住重点。
正确的做法是先问自己:这个 skill 要解决的核心问题是什么?以 TDD 为例,核心问题是"agent 倾向于跳过测试直接写实现"。那 skill 的目标就是强制它先写测试。
接下来列出具体的约束点:
- 必须先写测试,测试要能运行且失败
- 测试失败后才能写实现
- 实现要让测试通过,不能改测试来迁就实现
- 通过后要检查是否有重构空间
这四个点就是 skill 的骨架。其他的细节都是围绕这四点展开的。
3.2 写 description 的讲究
description 是 skill 的"广告词",它的任务是让 agent 在正确的时机选中这个 skill。写的时候要注意几个点。
用触发场景而不是功能描述。对比一下:
- 差的写法:
这是一个测试驱动开发技能 - 好的写法:
当需要实现新功能、修复 bug 或重构代码时,使用此技能确保先写测试
好的写法里包含了"实现新功能""修复 bug""重构代码"这些具体场景词,agent 匹配任务时更容易命中。
控制长度。description 太长会稀释关键词的权重,太短又覆盖不全场景。我的经验是控制在 50 到 100 字之间,把最核心的触发场景说清楚就行。
避免歧义。不要用"可能""也许"这类模糊词。skill 的触发应该是确定的,模糊的描述会让 agent 在该用和不该用之间摇摆。
3.3 正文的写法:流程 + 约束 + 示例
正文部分我习惯分三块写:流程、约束、示例。
流程部分用有序列表,把步骤写清楚:
## 流程 1. 阅读需求,理解要实现的功能 2. 编写测试用例,覆盖正常路径和边界情况 3. 运行测试,确认测试失败(红) 4. 编写最小实现,让测试通过(绿) 5. 检查代码,消除重复和坏味道(重构) 6. 重复 2-5 直到功能完成约束部分用无序列表,把红线标出来:
## 约束 - 禁止在测试通过前编写实现代码 - 禁止修改测试来让实现通过 - 每次只实现一个测试用例对应的功能 - 测试必须能独立运行,不依赖执行顺序示例部分给一段具体的代码,让 agent 有参照:
# 先写测试 def test_add_two_numbers(): assert add(1, 2) == 3 # 运行,确认失败 # 再写实现 def add(a, b): return a + b这三块写下来,一个 skill 的正文大概在 300 到 500 字。太短了约束不够,太长了 agent 抓不住重点。
3.4 实测中的意外情况
写完第一个版本后,我拿几个真实任务测了一下,发现了几个问题。
问题一:agent 有时候会"假装"跑了测试。它会在回复里写"测试失败,符合预期",但实际上根本没执行测试命令。解决办法是在 skill 里明确要求"必须实际执行测试命令,并展示命令输出"。
问题二:agent 会在测试失败后直接改测试。比如测试期望add(1,2)==3,实现返回了 4,它不去改实现,反而把测试改成add(1,2)==4。这个行为很隐蔽,需要在约束里明确禁止。
问题三:skill 加载了但没生效。排查后发现是 description 写得太泛,agent 匹配到了但觉得"这个任务不需要严格走 TDD",就跳过了。后来把 description 改得更具体,问题就解决了。
这些意外情况说明一件事:skill 不是写完就完事,需要在实际使用中不断调优。第一版能覆盖 70% 的场景就不错了,剩下的 30% 靠迭代补上。
4. skill 与 Claude Code 的配合方式
4.1 Claude Code 怎么发现 skill
Claude Code 默认会扫描项目根目录下的skills/文件夹,也会扫描用户主目录下的配置目录。项目级的 skill 优先级高于用户级的,这样团队可以有自己的 skill 集,个人也可以有自己的偏好 skill。
如果你把 skill 放在非标准位置,需要在配置里显式指定路径。这个配置通常在项目的.claude/目录下,具体文件名和格式随版本变化,建议以官方文档为准。
4.2 什么时候 skill 会被触发
触发时机分两种:自动触发和手动触发。
自动触发就是前面说的 description 匹配。用户提出任务,agent 判断是否需要加载某个 skill。这种方式的好处是无感,用户不需要知道 skill 的存在。
手动触发是用户在对话里明确要求使用某个 skill。比如直接说"用 TDD 流程实现这个功能"。这种方式适合用户想强制走某个流程的场景。
两种方式可以结合。日常开发靠自动触发,关键任务靠手动触发兜底。
4.3 skill 和 CLAUDE.md 的区别
很多人会混淆 skill 和CLAUDE.md。两者都是给 agent 的指令,但定位不同。
CLAUDE.md是项目级的全局指令,每次对话都会加载。它适合放项目的整体约定,比如代码风格、目录结构、常用命令。
skill 是任务级的指令,只在相关任务时加载。它适合放特定场景的流程,比如 TDD、代码审查、发布流程。
打个比方,CLAUDE.md是员工手册,skill 是具体工种的作业指导书。员工手册人人要看,作业指导书只在干那个活的时候才翻。
注意:不要把该放 skill 的内容塞进
CLAUDE.md。CLAUDE.md每次对话都加载,塞太多东西会挤占 context,反而让 agent 抓不住重点。
4.4 多 skill 协作的场景
真实项目里往往需要多个 skill 配合。比如实现一个新功能,可能涉及 TDD skill、代码审查 skill、提交信息规范 skill。
这时候要注意 skill 之间的边界。每个 skill 管好自己的事,不要越界。TDD skill 只管测试和实现的顺序,不管代码风格;代码审查 skill 只管审查标准,不管测试怎么写。
如果两个 skill 的职责有重叠,agent 可能会困惑该听谁的。解决办法是在 description 里把触发场景区分清楚,或者在 skill 正文里明确说明"本 skill 不负责 XX,请参考 XX skill"。
5. 让 skill 真正落地的几个关键细节
5.1 description 的迭代比正文更重要
我自己的经验是,skill 写完后,80% 的调优时间花在 description 上。正文写得再好,description 匹配不上就是白搭。
调优 description 的方法很简单:拿一批真实任务,看 agent 有没有在正确的时机加载 skill。没加载的,分析任务描述和 description 的差距,把缺失的场景词补进去。加载了但不该加载的,把过于宽泛的词删掉。
这个过程需要反复几轮,但每轮都能明显提升命中率。
5.2 用示例锚定 agent 的行为
LLM 对示例的敏感度远高于对规则描述的敏感度。与其写十条"不要这样做",不如给一个"应该这样做"的示例。
在 skill 里放示例时,要注意示例的代表性。选最典型的场景,不要选边角案例。示例代码要能直接运行,不要有伪代码。
如果 skill 涉及多种情况,可以给多个示例,但要标注清楚每个示例对应的场景。比如"场景 A:新增功能"下面放一个示例,"场景 B:修复 bug"下面放另一个。
5.3 版本管理和团队协作
skill 是团队资产,应该纳入版本管理。放在项目仓库里,跟着代码一起提交、一起 review。
团队协作时要注意几点。一是 skill 的修改要经过 review,不能随便改,因为改了会影响所有人的 agent 行为。二是 skill 要有变更记录,说明每次改了什么、为什么改。三是新 skill 上线前要在小范围试用,确认没问题再推广。
我见过一个团队把 skill 当草稿纸用,谁想改就改,结果 agent 的行为越来越不可预测。后来他们引入了 review 流程,情况才好转。
5.4 常见问题排查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| skill 完全没被加载 | description 不匹配 | 检查 description 是否包含任务关键词 |
| skill 加载了但行为没变 | 正文指令不够明确 | 检查是否有明确的流程和约束 |
| agent 部分遵守 skill | 约束之间有冲突 | 检查 skill 内部和 skill 之间是否矛盾 |
| skill 加载过于频繁 | description 太宽泛 | 收窄 description 的触发场景 |
| 多个 skill 同时加载导致混乱 | 职责边界不清 | 明确各 skill 的职责范围 |
这张表是我在实际使用中总结的,大部分问题都能对应上。遇到新问题时,先往这几个方向排查,通常能快速定位。
6. 关于 agent-skills 的一些个人体会
用了一段时间agent-skills之后,我最大的感受是:它把 prompt engineering 从"一次性技巧"变成了"可积累的资产"。
以前调 prompt,调好了存在某个笔记里,下次用的时候再翻出来复制粘贴。这种方式的问题是,经验散落在各处,没法沉淀,没法复用,没法协作。
skill 机制改变了这一点。每个 skill 都是一个独立的、可版本管理的、可复用的单元。写得好就留着,写得不好就改,改好了团队都能用。这种积累效应,时间越长价值越大。
另一个体会是,skill 的粒度很关键。太粗了,一个 skill 管太多事,agent 抓不住重点;太细了,skill 数量爆炸,匹配阶段就容易出错。我的经验是,一个 skill 对应一个明确的流程或一类明确的任务,不要贪多。
最后说一个实际的小技巧。如果你不确定某个 skill 该不该拆,可以先写成一个,用一段时间,等发现里面确实有两块相对独立的内容时再拆。过早拆分反而会增加维护成本。
agent-skills这个方向还在快速演进,现在的做法过几个月可能就过时了。但底层的思路——把 agent 的能力模块化、可配置化、可积累化——应该是长期有效的。抓住这个思路,具体的实现方式怎么变都能跟上。