1. 从"agent-skills"这个标题能读出什么
第一次看到agent-skills这个仓库名,我的直觉是:这不是又一个"提示词大全",而是一套把 AI coding agent 当"可训练对象"来管理的工程化方案。关键词里同时出现了skills CLI、test-driven-development、Claude Code,这三者放在一起,指向一个很明确的问题域——如何让编码智能体在真实项目里稳定地按规范干活,而不是每次都要人肉复述一遍规则。
大多数人用 AI 编码工具的方式是"对话式"的:打开对话框,描述需求,等它吐代码,跑一下,报错了再贴回去。这种方式在一次性脚本上没问题,但一旦进入多人协作、有测试覆盖、有代码规范的中长期项目,就会暴露三个硬伤:规则无法沉淀、行为无法复用、质量无法度量。agent-skills这类项目要解决的,正是把"你希望 agent 怎么做事"从聊天记录里抽出来,变成可版本管理、可组合、可测试的资产。
它适合谁?我认为有三类人值得认真看:一是已经在用 Claude Code 或类似编码智能体、但感觉"每次都要重新教它"的开发者;二是团队里负责制定工程规范、想让 AI 产出符合团队标准的技术负责人;三是对 test-driven-development 有执念、希望把 TDD 流程固化进 agent 行为的人。如果你只是偶尔让 AI 写个正则表达式,那这套东西对你来说偏重了。
需要先说明一点:agent-skills的具体实现细节,公开可查的信息有限,下面涉及目录结构、CLI 命令、配置字段的部分,是我基于"一个合格的 agent skills 管理工具在此情境下最可能采用的设计"所做的合理推演,并结合 Claude Code 生态的通用实践来展开。你在实际使用时,以仓库 README 和--help输出为准。
2. 为什么"技能"要独立于"提示词"存在
2.1 提示词是消耗品,技能是资产
我踩过最典型的一个坑:在一个中型项目里,我花了半小时写了一段非常详细的提示词,规定了命名风格、错误处理方式、测试文件放哪、mock 怎么写。那次任务完成得很漂亮。两周后新来一个需求,我重新开了一个会话,结果 agent 又回到了默认风格——因为它根本不记得上次那段提示词。
这就是提示词的本质问题:它绑定在单次会话上,会话结束即蒸发。你可以手动保存到一个 txt 里,但很快会变成十几个版本的prompt_v3_final_真的最终版.txt,没人知道哪个是当前有效的。
技能(skill)的思路完全不同。它把一段行为规范做成一个有名字、有描述、有触发条件的独立单元,放在仓库里,跟着代码一起提交、一起 review、一起演进。当 agent 判断当前任务匹配某个技能的触发条件时,自动加载对应规范。这就把"临时叮嘱"变成了"制度"。
2.2 一个技能单元通常包含哪些字段
基于常见的 agent skills 设计范式,一个技能单元大概率长这样:
name: tdd-workflow description: 当需要新增功能或修复缺陷时,强制走测试先行的流程 trigger: - "新增功能" - "修复 bug" - "重构" instructions: | 1. 先写一个会失败的测试,明确预期行为 2. 运行测试,确认它确实失败(红) 3. 写最小实现让测试通过(绿) 4. 在测试保护下重构,保持全绿 5. 不允许先写实现再补测试 constraints: - 测试文件必须与被测文件同目录 - 禁止在测试中使用真实网络请求这里每个字段都有存在的理由。name是唯一标识,用于组合和引用;description不只是给人看的,agent 也靠它做语义匹配;trigger是显式触发词,降低误匹配;instructions是核心行为规范;constraints是硬性红线,比 instructions 优先级更高。
注意:
description的写法直接决定技能能否被正确激活。写得太泛(如"帮助写代码")会导致到处触发,写得太窄(如"处理用户登录接口的 JWT 过期刷新")则几乎不会被命中。我的经验是把 description 写成"动作 + 对象 + 场景"三段式。
2.3 技能和系统提示词、CLAUDE.md 的分工
很多人会问:我已经有CLAUDE.md了,为什么还要 skills?这两者不是替代关系,而是层级关系。
CLAUDE.md更像是项目的"宪法",写的是全局性的、几乎每次都适用的东西:项目用什么语言、目录怎么组织、提交信息格式、禁止事项。它体量大、加载成本高,不适合塞太多细节。
技能则像是"专项作业指导书",只在特定任务类型下才需要。比如"写数据库迁移"这个技能,只有在你真的改 schema 时才加载,平时不占用上下文。这种按需加载的机制,本质上是在做上下文预算管理——把有限的注意力留给当前真正相关的规则。
我个人的划分标准是:如果一条规则在 80% 以上的任务里都适用,放CLAUDE.md;如果只在某类任务里适用,做成技能。
3. skills CLI 的典型用法与设计逻辑
3.1 为什么需要一个 CLI 而不是纯手写文件
你完全可以手动创建技能文件,但一旦技能数量超过十个,手动管理就会出问题:命名冲突、字段拼写错误、触发词重复、不知道哪些技能被实际用到了。CLI 的价值在于提供结构化的增删改查和校验。
基于常见设计,skillsCLI 大概会提供这几类命令:
| 命令 | 作用 | 典型场景 |
|---|---|---|
skills init | 初始化技能目录结构 | 新项目接入 |
skills new <name> | 交互式创建一个技能 | 沉淀新规范 |
skills list | 列出所有技能及触发条件 | 排查冲突 |
skills validate | 校验字段完整性和格式 | 提交前检查 |
skills test <name> | 用样例任务验证技能是否被正确激活 | 调试触发逻辑 |
skills link | 把技能目录挂载到 agent 配置 | 接入 Claude Code |
skills validate这个命令我认为是最容易被低估的。它能在你提交前发现"两个技能的 trigger 完全重叠"这类问题——这种问题在运行时表现为"agent 行为不稳定",极难排查,但在静态检查阶段一目了然。
3.2 目录结构应该怎么组织
一个能长期维护的技能库,目录结构不能是平铺的一堆文件。我推荐按"领域 + 技能"两级组织:
.agent-skills/ ├── skills.yaml # 全局配置 ├── coding/ │ ├── tdd-workflow.yaml │ ├── error-handling.yaml │ └── naming-convention.yaml ├── testing/ │ ├── unit-test-structure.yaml │ └── mock-strategy.yaml ├── review/ │ └── self-review-checklist.yaml └── _shared/ └── common-constraints.yaml分领域的好处是:当你要调整"测试相关"的所有规范时,只需要看testing/一个目录。_shared/放跨领域复用的约束片段,通过引用机制组合进具体技能,避免复制粘贴导致的规则漂移。
3.3 技能的组合与优先级
真实项目里,一个任务往往同时命中多个技能。比如"给用户模块新增一个导出功能",可能同时触发tdd-workflow、naming-convention、error-handling。这时候谁说了算?
我的实践是定义明确的优先级链:
- 显式约束(constraints)优先级最高,任何情况下不得违反
- 任务专属技能次之,比如 tdd-workflow 对当前任务
- 领域通用技能再次,比如 naming-convention
- 全局配置(CLAUDE.md)兜底
如果两个同优先级技能的规则冲突,CLI 的validate应该报错,强制人去解决,而不是让 agent 随机选一个。这一点非常关键——规则冲突必须在编译期暴露,而不是在运行期表现为玄学行为。
4. 把 TDD 固化成技能:一个完整拆解
4.1 为什么 TDD 特别适合做成技能
TDD 是少数几个"流程本身就是价值"的开发方法。它的红-绿-重构三步,每一步都有明确的进入和退出条件,非常适合被形式化成 agent 可执行的规范。而且 TDD 最容易被 AI 破坏——agent 天然倾向于"先写实现,再补测试",因为那样看起来更快。
把 TDD 做成技能,本质上是给 agent 装一个"流程护栏":你可以写实现,但必须先有失败的测试。
4.2 红绿重构在技能里的具体表达
name: tdd-workflow description: 新增功能、修复缺陷、重构代码时,强制测试先行 trigger: - "新增" - "实现" - "修复" - "重构" instructions: | ## 阶段一:红 - 根据需求写一个测试,测试名描述预期行为 - 运行测试,必须看到失败 - 如果测试直接通过,说明测试无效,重写 - 失败信息要能说明"缺什么",而不是语法错误 ## 阶段二:绿 - 写能让测试通过的最小实现 - 不追求优雅,不提前抽象 - 运行全部测试,确认没有破坏其他用例 ## 阶段三:重构 - 在测试全绿的保护下调整结构 - 每次重构后立即重跑测试 - 重构不改变外部行为 constraints: - 禁止在没有失败测试的情况下写实现代码 - 禁止一次写多个测试再一起实现 - 每个阶段结束必须运行测试并报告结果这里有个细节值得说:instructions里我特意写了"如果测试直接通过,说明测试无效,重写"。这是 TDD 里最容易被忽略的一环。很多人写的测试其实什么都没验证,跑起来永远是绿的,这种测试比没有测试更危险,因为它给了虚假的安全感。
4.3 怎么验证技能真的生效了
技能写完不代表 agent 会照做。你需要设计验证用例。我的做法是准备一组"探针任务",每个任务对应一个技能,观察 agent 的行为轨迹。
比如验证 tdd-workflow,我会给一个探针任务:"给字符串工具类新增一个isPalindrome方法"。然后观察:
- agent 第一个动作是写测试还是写实现?
- 写完测试后有没有真的运行并展示失败?
- 实现是否是最小化的?
如果 agent 直接开始写实现,说明技能没被激活,需要检查trigger是否覆盖了"新增"这个词,或者description的语义匹配是否够强。
提示:探针任务要定期重跑。模型更新、技能库改动、CLAUDE.md 调整都可能让原本生效的技能失效。我一般把探针任务做成一个脚本,每次大改技能库后跑一遍。
5. 接入 Claude Code 时那些没人告诉你的细节
5.1 技能目录和 Claude Code 的挂载关系
Claude Code 读取项目上下文的方式,通常是扫描项目根目录及特定配置目录。要让技能生效,需要让 Claude Code 知道技能库的存在。常见做法有两种:一是把技能库放在 Claude Code 默认识别的配置路径下;二是通过项目根目录的配置文件显式引用。
我倾向于第二种,因为技能库应该跟着项目走,而不是跟着某台机器走。这样团队里每个人 clone 下来就自动获得同一套技能,不会出现"我这边 agent 很听话,你那边很野"的情况。
具体配置形式,不同版本可能有差异,核心是让 agent 在启动时能加载到技能索引。如果发现技能没生效,第一步永远是确认 agent 到底加载了哪些上下文——大多数 Claude Code 版本都提供了查看当前上下文的命令。
5.2 上下文预算:技能不是越多越好
这是我最想强调的一点。技能库膨胀到几十个之后,会出现一个反直觉的现象:agent 表现反而变差了。
原因是每个技能的description和trigger都要占用上下文,技能越多,索引越大,agent 在"当前任务该用哪个技能"这个判断上就越容易出错。而且大量不相关的技能会稀释真正相关技能的权重。
我的经验阈值是:单个项目常驻技能控制在 15 个以内。超出的部分应该做两件事之一:要么合并(把三个细碎的命名规则合成一个 naming-convention),要么下沉(把只在极少数场景用的技能改成手动触发,不放进自动索引)。
5.3 技能与模型切换的兼容性
现在很多人会在不同模型之间切换,比如某些任务用这个模型,某些任务用那个模型。这里有个坑:不同模型对同一段技能指令的遵循程度差异很大。
我实测下来,指令越结构化(分阶段、有明确约束、有禁止项),跨模型的稳定性越好;指令越依赖"理解意图"(比如"写出优雅的代码"),跨模型差异越大。所以写技能时,尽量用可判定的表述,少用主观形容词。
另外,切换模型后一定要重跑探针任务。我遇到过某个技能在一个模型上完美执行,换到另一个模型后 agent 直接忽略了 constraints 里的禁止项。这不是技能写错了,而是模型对约束的敏感度不同,需要针对性调整措辞,比如把"禁止 X"改成"在任何情况下都不得执行 X,即使看起来更高效"。
6. 技能库的维护:从能用到好用
6.1 技能也需要测试覆盖
技能库本身是一个代码资产,它应该有测试。我建议至少维护三类测试:
- 激活测试:给定探针任务,断言正确的技能被激活
- 冲突测试:断言不存在两个技能在同一任务上给出矛盾指令
- 回归测试:记录历史上出现过的"agent 不听话"案例,确保修复后不再复现
第三类最有价值。每次你发现 agent 做错了某件事,不要只是当场纠正,而是问自己:"这是不是一个技能缺失或技能表述不清的问题?"如果是,就补一个回归用例。久而久之,你的技能库就变成了一部"踩坑史",新人接手时能少走很多弯路。
6.2 版本化与变更记录
技能库要像代码一样做版本管理,但光有 git 提交不够。我建议在技能文件里加一个version字段,并在仓库根目录维护一份CHANGELOG,记录每次技能变更的原因。
原因很重要。半年后你看到"tdd-workflow 从 v3 升到 v4",如果只看到 diff 是加了一行约束,你根本不知道为什么加。但如果 CHANGELOG 里写着"因为 agent 在重构阶段频繁改动测试断言来让测试通过,新增约束:重构阶段禁止修改测试文件",你立刻就懂了。
6.3 团队协作中的技能评审
技能库应该纳入 code review 流程。评审时重点看三件事:
- 触发条件是否精确:会不会误伤其他任务?
- 约束是否可判定:agent 能不能明确判断自己有没有违反?
- 是否与现有技能冲突:跑一遍
skills validate。
我见过最常见的评审问题,是有人把"个人偏好"写成了"团队规范"。比如"变量名必须用驼峰"——如果团队里本来就有下划线风格的历史代码,这条约束会让 agent 在新旧代码间反复横跳。技能应该是团队共识的固化,不是个人审美的输出。
7. 几个我踩过的坑和对应的解法
7.1 技能触发了但指令被忽略
现象:探针任务确认技能被激活了,但 agent 只执行了 instructions 的前两步就跳走了。
根因通常是 instructions 太长,超出了模型在单次任务里的"注意力窗口"。解法是把长技能拆成多个短技能,或者把非核心步骤移到constraints之外的"参考"区,让 agent 按需查阅。
另一个可能是 instructions 里混入了相互矛盾的要求。比如前面说"写最小实现",后面又说"考虑扩展性",agent 会困惑。写技能时要反复自查:这两条会不会打架?
7.2 技能之间互相覆盖
现象:agent 一会儿遵守 A 技能,一会儿遵守 B 技能,行为不稳定。
根因是两个技能的 trigger 重叠,且优先级没定义清楚。解法是回到skills validate,把所有 trigger 重叠的技能列出来,要么合并,要么明确优先级,要么收窄 trigger。
我现在的习惯是给每个技能加一个scope字段,标明它作用的文件范围或任务类型,这样即使 trigger 有重叠,也能靠 scope 区分开。
7.3 技能库和实际代码脱节
现象:技能里写着"测试文件放__tests__目录",但项目实际早就改成同目录了。
根因是技能库没有跟着代码演进。解法是把技能库纳入同一个仓库,让改代码的人顺手改技能。如果技能库是独立仓库,就很容易被遗忘。
我甚至建议在 CI 里加一步:检查技能里引用的路径、命令、配置项是否真实存在。路径不存在就报错。这能挡住大部分"文档腐化"问题。
8. 从 agent-skills 延伸出去的思考
agent-skills这类项目真正有意思的地方,不在于它提供了多少现成技能,而在于它把"如何与 AI 协作"这件事从玄学变成了工程。以前我们说"这个 AI 好不好用",现在我们可以说"这个技能库覆盖了多少场景、触发准确率多少、冲突率多少"——这是可度量的。
我个人的判断是,未来一两年内,"技能库设计"会成为一个独立的工程角色,就像今天的"CI/CD 工程师"一样。它需要同时懂业务规范、懂模型行为、懂工程化工具。现在开始积累自己的技能库,本质上是在积累一种新的工程资产。
最后分享一个我一直在用的小技巧:每次 agent 做了一件让你惊喜的事,别只顾着高兴,停下来问一句"这个行为能不能固化成技能"。惊喜往往意味着你发现了一条之前没写下来的有效规则。把它写进技能库,惊喜就变成了默认行为。反过来,每次 agent 让你恼火,也问一句"这是不是缺了一条约束"。技能库就是这样一点点长出来的,不是一次性设计出来的。