agent-skills 实战:用 skills CLI 和 TDD 技能规范 AI 编码流程 1. 从agent-skills这个标题能读出什么第一次看到agent-skills这个仓库名我的直觉是这不是又一个提示词大全而是一套给 AI coding agent 用的能力封装规范。关键词里同时出现了skills CLI、Claude Code、test-driven-development基本可以确定它的定位——把让 AI 写代码这件事从每次靠嘴描述升级成装一个可复用的技能包。我接触过不少团队在推 AI 辅助编码最常见的失败模式不是模型不行而是上下文给得太随意。同一个需求A 同事让 AI 写出来的东西能直接进 CIB 同事让 AI 写出来的东西连编译都过不了。差别往往不在模型而在于有没有把这个项目该怎么写代码沉淀成一套 agent 能读懂、能执行的技能定义。agent-skills想解决的正是这个断层。这篇文章我会按一个真实从业者从零上手这套东西的路径来写先讲清楚 skills 到底是个什么抽象再讲 CLI 怎么用、目录怎么组织、怎么和 Claude Code 这类 coding agent 对接然后重点讲 TDD 这个技能为什么值得单独拎出来最后把我踩过的坑和排查思路完整摊开。适合两类人看一是已经在用 Claude Code 或类似工具、但觉得每次都要重新解释一遍的开发者二是想把 AI 编码流程标准化、沉淀成团队资产的 tech lead。需要先说明一点agent-skills本身是一个偏约定和脚手架性质的项目它的价值不在于代码量而在于它定义的那套技能描述格式和加载机制。理解了这套机制你完全可以自己扩展出适合自己团队的技能包。2. skills 这个抽象到底解决了什么问题2.1 从提示词到技能包的认知转变大多数人用 AI 写代码的方式是打开对话框粘贴一段需求等结果。这种方式在一次性脚本上没问题但一旦进入真实项目就会崩。原因很简单——真实项目有隐性约束目录结构、命名习惯、错误处理风格、测试框架、日志规范、依赖管理方式。这些东西你不可能每次都在提示词里重写一遍。agent-skills的核心思路是把这些约束外化成文件。一个 skill 本质上是一个目录里面包含一份描述文件通常声明这个技能叫什么、什么时候该被触发、需要哪些输入若干指令文档告诉 agent 在这个技能下应该遵循什么流程可选的辅助脚本或模板让 agent 能直接调用而不是凭空生成这跟传统的提示词模板最大的区别在于技能是可被 agent 主动发现和加载的。你不需要在每轮对话里手动粘贴agent 会根据当前任务判断我该用哪个技能。打个比方提示词像是你每次点外卖都要跟商家重新描述一遍不要香菜、少放辣技能包像是你在平台上存好的偏好设置下单时自动生效。前者靠记忆后者靠系统。2.2 为什么是 CLI 而不是纯配置文件关键词里出现了skills CLI这个设计选择值得说一下。纯配置文件比如一个 YAML 描述所有技能的问题是技能会越来越多配置会越来越臃肿而且没法做版本管理和按需安装。CLI 的好处是它把技能变成了可分发的单元。你可以从远端拉取某个技能到本地列出当前项目已启用的技能把某个技能从项目里移除查看某个技能的具体内容这套操作逻辑跟包管理器很像。我个人的理解是agent-skills想做的是 AI 编码领域的npm——技能可以被发布、被引用、被组合。这个方向我认为是对的因为团队协作里最怕的就是只有某个人知道怎么让 AI 写出对的代码。提示CLI 类工具在落地时第一件要确认的事是它把技能装到了哪个目录、agent 从哪里读取。这个路径搞错了后面所有调试都是白费。2.3 技能触发的边界什么时候该用什么时候不该用这是我在实际使用中觉得最容易被忽略的一点。技能不是越多越好。如果一个项目里装了二十个技能agent 在每轮对话里都要判断该用哪个反而会引入噪声甚至出现技能冲突——两个技能对同一件事给出了不同指令。我的经验是核心技能控制在 5 到 8 个覆盖最高频的场景即可。比如技能类型典型场景是否建议常驻测试驱动开发写新功能、修 bug强烈建议代码审查PR 前自检建议提交信息规范git commit建议文档生成公共 API 变更按需特定框架脚手架新建模块按需性能剖析排查慢查询按需常驻的技能应该是那些每次写代码都该遵守的规则按需的技能则是特定任务才触发的工具。把这两类混在一起agent 的判断准确率会明显下降。3. 把 skills CLI 跑起来环境与目录结构3.1 安装前的环境确认在动手之前有几个前置条件必须先确认否则后面会卡在一些莫名其妙的地方。第一是 Node.js 版本。绝大多数这类 CLI 工具都依赖较新的 Node 运行时我建议至少 Node 18 以上最好 20 LTS。用node -v确认一下版本太低的话先升级。第二是包管理器。npm、pnpm、yarn 都行但要注意全局安装的路径是否在 PATH 里。我见过有人npm install -g之后命令找不到排查半天发现是 npm 的全局 bin 目录没加进环境变量。第三是权限。在 Linux 或 macOS 上全局安装有时需要 sudo但我不建议直接用 sudo 装容易把权限搞乱。更稳妥的做法是配置 npm 的用户级全局目录或者用 nvm 管理 Node 版本这样全局包都装在用户目录下不需要提权。# 确认 Node 版本 node -v npm -v # 查看 npm 全局安装路径 npm config get prefix # 如果这个路径不在 PATH 里需要手动加进去 echo $PATH3.2 技能目录应该放在哪一层这是实操中第一个真正的决策点。技能目录放的位置决定了它的作用范围放在用户主目录下比如~/.agent-skills/全局生效所有项目共享。适合放那些跟具体项目无关的通用技能比如提交信息规范、通用代码审查清单。放在项目根目录下比如./.agent-skills/只对当前项目生效。适合放项目特有的约定比如这个项目的测试必须用某个特定 fixture。放在子模块目录下只对某个子模块生效。适合大型 monorepo。我的建议是两层结构全局放通用技能项目内放专属技能agent 加载时先读全局再读项目项目内的覆盖全局的。这样既避免了重复又保证了项目特异性。注意如果你把技能目录加进了.gitignore那团队其他成员就拉不到这些技能协作就断了。项目级的技能目录应该提交到版本库全局的才放本地。3.3 一个最小可用的技能目录长什么样不要一上来就搞复杂。先建一个最小技能确认整条链路能跑通再逐步扩展。一个最小技能通常包含my-skill/ ├── SKILL.md # 技能描述与指令 └── (可选的辅助文件)SKILL.md里最关键的是两部分元信息这个技能叫什么、什么时候触发和指令正文agent 该怎么做。元信息一般用 frontmatter 的形式写在文件开头指令正文用 Markdown 写。我建议第一次写的时候指令正文尽量短就写三五条最核心的规则。等确认 agent 能正确加载并执行之后再往里加细节。一次性写两百行指令出了问题你根本不知道是哪条导致的。3.4 验证技能是否被正确加载这一步很多人跳过结果后面调试时抓瞎。验证方法通常有两种一是用 CLI 自带的列表命令看当前项目识别到了哪些技能。如果列表里没有你刚建的技能说明路径不对或者格式有问题。二是直接在 agent 对话里触发。比如你建了一个测试相关的技能就让 agent 写一个函数看它是否自动按测试先行的方式来做。如果它还是老样子直接写实现说明技能没被加载或者触发条件没匹配上。我踩过的一个坑是技能文件的元信息里写了触发关键词但关键词写得太窄agent 判断当前任务不匹配就跳过了。后来我把触发条件放宽问题解决。所以触发条件宁可稍微宽一点也不要太窄。4. 和 Claude Code 对接时的关键配置4.1 Claude Code 读取技能的机制Claude Code 这类 coding agent 的工作方式是它在项目目录里运行会读取项目内的特定配置文件来了解上下文。技能要生效必须让 agent 知道去哪里找技能以及什么时候该用。这里有个容易混淆的点技能文件和项目说明文件比如 CLAUDE.md 之类不是一回事。项目说明文件是永远生效的背景信息技能是按需触发的能力包。如果你把所有东西都塞进项目说明文件会导致上下文过长agent 反而抓不住重点。正确的分工是项目说明文件写这个项目是什么、用什么技术栈、有哪些硬性约束技能文件写遇到某类任务时应该遵循什么流程4.2 在 VS Code 里的配置要点如果你是在 VS Code 里用 Claude Code 插件配置上有几个点要注意。第一是工作区根目录。插件通常以你打开的文件夹作为工作区根目录技能目录要相对于这个根目录来放。如果你打开的是子目录而不是项目根技能可能就找不到了。第二是插件的配置文件。有些插件需要在设置里显式指定技能目录的路径默认值不一定符合你的目录结构。这个要去插件的配置项里确认。第三是终端集成。Claude Code 能直接执行终端命令这是它比纯对话工具强的地方。但这也意味着技能里如果包含运行测试这类指令agent 会真的去跑命令。所以技能里的命令要写清楚别让它跑一些危险操作。// VS Code settings.json 里可能的配置项示意具体字段以插件文档为准 { claudeCode.skillsPath: ./.agent-skills, claudeCode.autoLoadSkills: true }提示配置项的具体名称会随插件版本变化不要照抄去插件文档或设置界面里找对应的项。我一般习惯先在设置界面里搜关键词比翻文档快。4.3 在 Ubuntu 上的安装与路径问题Linux 环境下装这类工具最容易出问题的是路径和权限。几个实操要点一是全局安装后命令找不到多半是 npm 全局 bin 目录没进 PATH。用npm config get prefix看路径然后确认这个路径下的bin目录在 PATH 里。二是如果用 nvm 管理 Node切换 Node 版本后全局包会消失因为不同版本的全局目录是隔离的。这时候要么在新版本下重装要么用nvm reinstall-packages迁移。三是文件权限。如果技能目录是从别处拷贝过来的可能带着原来的权限位导致 agent 读不了。用chmod -R统一一下读写权限。# 查看全局 bin 路径 npm config get prefix # 确认 PATH 包含该路径 echo $PATH | tr : \n | grep $(npm config get prefix) # 修复技能目录权限 chmod -R urw ./.agent-skills4.4 用第三方模型时的注意事项关键词里提到了用其他模型接入的场景。这里要提醒的是不同模型对技能指令的遵循程度差异很大。有些模型对结构化指令的执行很稳有些则容易自由发挥把技能里的流程抛在脑后。我的做法是换模型之后先用一个简单任务验证技能是否被正确执行。比如让 agent 写一个带测试的小函数看它是否真的先写测试。如果它跳过了说明这个模型对技能的遵循度不够要么换模型要么把技能指令写得更强硬一些比如用必须禁止这类词。另外技能里的指令要尽量具体、可验证。写好测试是模糊的先写一个会失败的测试运行确认它失败再写实现让它通过是可验证的。后者对模型的约束力明显更强。5. 把 TDD 做成一个技能为什么值得单独拎出来5.1 TDD 为什么是 AI 编码的最佳搭档关键词里test-driven-development被单独列出来我认为这不是偶然。TDD 和 AI 编码的结合点在于测试给了 AI 一个明确的、可自动验证的成功标准。你让 AI写一个解析函数它写出来的东西对不对你得自己看。你让 AI先写测试再写实现直到测试通过它就有了一个自我验证的闭环。这个闭环极大降低了AI 写了一堆看起来对但实际有 bug 的代码的概率。我在实际项目里的观察是开了 TDD 技能的 agent产出的代码返工率明显低于不开的。原因不复杂——测试先行逼着 agent 先把需求想清楚而不是上来就堆实现。5.2 一个 TDD 技能应该包含哪些指令写 TDD 技能时指令的顺序和措辞很关键。我总结的骨架是这样的先理解需求写出测试用例。明确输入、输出、边界条件。运行测试确认它失败。这一步不能省否则你不知道测试是不是真的在测东西。写最小实现让测试通过。不要提前优化不要加测试没覆盖的功能。运行全部测试确认没有回归。重构保持测试全绿。这五步里第 2 步最容易被 agent 跳过。很多 agent 写完测试就直接写实现根本不跑。所以技能指令里要明确写必须运行测试并确认失败。## 流程 1. 根据需求写出测试用例覆盖正常路径和至少一个边界条件 2. 运行测试确认测试失败如果测试直接通过说明测试没测到东西需要重写 3. 编写最小实现使测试通过 4. 运行完整测试套件确认无回归 5. 在测试全绿的前提下重构 ## 禁止 - 禁止在测试失败前编写实现 - 禁止为了让测试通过而修改测试断言 - 禁止添加测试未覆盖的功能5.3 测试框架的适配问题TDD 技能不能写死某个测试框架否则换个项目就废了。我的做法是在技能里写使用项目现有的测试框架然后让 agent 自己去项目里探测。探测的依据可以是package.json里的依赖、已有的测试文件、或者配置文件。如果项目里还没有测试框架技能里可以给一个默认建议但要说明如果项目已有框架优先用已有的。这样技能的可移植性会好很多。注意让 agent 自动探测测试框架时要确保它能读到package.json或等价文件。如果项目结构特殊最好在项目说明文件里直接写明用哪个框架省得 agent 猜。5.4 怎么判断 TDD 技能真的在起作用判断方法很直接看 agent 的操作顺序。如果它先创建了测试文件运行了测试然后才创建实现文件说明技能生效了。如果它一上来就写实现最后补个测试那技能没起作用。我一般会看两个信号一是测试文件的时间戳是否早于实现文件二是对话记录里有没有运行测试并确认失败这一步。这两个信号都满足基本可以确认 TDD 流程被正确执行了。6. 踩坑实录技能不生效的完整排查链路6.1 症状agent 完全无视技能指令这是最常见的症状。你明明建了技能agent 却像没看见一样该怎么做还怎么做。排查顺序我建议这样走第一步确认技能文件被识别。用 CLI 的列表命令看当前项目识别到哪些技能。如果列表里没有问题在加载环节跟技能内容无关。第二步确认路径正确。技能目录是否在 agent 的工作区根目录下如果 agent 的工作区是子目录而技能放在项目根那就读不到。第三步确认文件格式正确。元信息部分的格式是否符合规范frontmatter 的语法有没有错我见过因为 YAML 缩进错误导致整个技能被静默忽略的情况。第四步确认触发条件匹配。技能被识别了但当前任务没触发它。这时候要检查技能里写的触发条件是不是太窄。第五步确认模型遵循度。技能被触发了但模型没照做。这时候要么换模型要么把指令写得更强硬。这个顺序很重要因为它从最外层往最内层排查每一步都能排除掉一批可能性。很多人一上来就怀疑模型不行结果折腾半天发现是路径错了。6.2 症状技能之间互相打架装了多个技能之后agent 的行为变得混乱一会儿按这个技能做一会儿按那个技能做。根因通常是两个技能对同一件事给出了不同指令。比如一个技能说提交前必须跑 lint另一个技能说提交前只跑测试。agent 不知道该听谁的。解决办法是明确技能的优先级和边界。要么把冲突的指令合并到一个技能里要么在技能里写明如果与其他技能冲突以本技能为准。我倾向于前者——能合并就合并减少技能数量。6.3 症状技能在本地好用团队其他人拉下来就失效这是协作场景下的经典问题。原因通常有三个一是技能目录没提交到版本库。检查.gitignore有没有误伤。二是技能里用了绝对路径。比如指令里写了/Users/xxx/project/...别人机器上根本没这个路径。技能里的路径必须用相对路径。三是技能依赖了本地才有的工具或环境变量。别人没装自然跑不起来。技能里如果依赖外部工具要在描述里写明前置条件。提示技能写完后最好让一个没参与编写的同事拉下来试一遍。自己测没问题不代表别人能用环境差异往往在这种时候暴露。6.4 症状技能让 agent 变慢了有些技能指令太长导致每轮对话的上下文暴涨agent 响应变慢甚至开始遗忘前面的指令。这时候要做的是精简技能指令。把背景介绍类的文字删掉只留可执行的规则。技能不是文档不需要写得很完整它需要的是高信息密度。我的经验是单个技能的指令正文控制在 50 行以内超过就该考虑拆分了。拆分的依据是这些指令是不是总是一起出现如果两组指令经常独立使用就该拆成两个技能。7. 把技能沉淀成团队资产的几个实操建议7.1 技能也要做代码审查技能文件本质上是给 AI 看的代码它同样会影响产出质量所以应该走代码审查流程。审查的重点是指令是否清晰、是否有歧义、是否与项目实际约定一致。我见过团队把技能文件当成个人笔记谁想改就改结果技能越来越乱最后没人敢用。把技能纳入审查能有效避免这个问题。7.2 给技能写测试这听起来有点绕——技能是给 AI 用的怎么测其实可以测。方法是准备一组输入任务看 agent 在加载技能后的产出是否符合预期。比如 TDD 技能输入写一个字符串反转函数预期产出是先有测试文件测试先失败后通过。这种测试不需要自动化手动跑一遍就行。但每次修改技能后都应该跑一遍确认没有把原来的行为改坏。7.3 技能的版本管理技能会随项目演进。项目换了测试框架TDD 技能里的示例就得跟着改。所以技能应该跟代码一起做版本管理而不是散落在个人目录里。我的做法是项目级技能放在项目仓库里跟代码同生命周期全局技能单独建一个仓库管理需要时同步到各项目。这样既能共享又能追溯变更。7.4 不要过度设计最后说一个我踩过的坑一开始总想把技能设计得很完备结果写了一大堆指令agent 反而无所适从。后来我改成最小可用原则——先写最核心的三五条规则跑通了再逐步加。技能的价值在于被执行不在于写得全。一个只有五条规则但每次都被严格执行的技能比一个五十条规则但 agent 经常忽略的技能有用得多。8. 关于技能触发时机的一点个人体会用了几个月下来我最大的体会是技能的触发时机比技能内容本身更值得打磨。内容写得再好如果 agent 在该用的时候没用上等于零。而触发时机这个东西很难一次写对需要根据实际使用情况反复调整。我的做法是每次发现agent 该用技能却没用的情况就记下来回头看看是触发条件写窄了还是任务描述本身不够明确。还有一个反直觉的发现技能不是越多越好触发条件也不是越宽越好。触发条件太宽agent 会在不相关的任务上也套用技能反而添乱。找到那个刚好覆盖目标场景的宽度是个需要反复试的过程。如果你刚开始用agent-skills我的建议是先只装一个 TDD 技能用一两周把触发时机调顺了再考虑加第二个。一次加太多你根本分不清是哪个技能在起作用出了问题也无从排查。