agent-skills 与 skills CLI:用技能包让 AI coding agent 稳定执行 TDD 工作流
1. 从agent-skills说起为什么这个项目值得单独聊第一次看到agent-skills这个标题我脑子里蹦出来的不是某个具体工具而是一类正在快速成型的东西——给 AI coding agent 装技能包的工程化方案。过去大半年我一直在用 Claude Code 做日常开发从最初的新鲜感到后来被它乱改代码跑偏需求折磨得想砸键盘再到慢慢摸索出一套让它稳定干活的套路。这个过程里我越来越确信一件事agent 的能力上限不取决于模型本身而取决于你喂给它什么样的技能约束和上下文。agent-skills这个项目本质上就是在解决这个问题。它不是一个模型也不是一个 IDE 插件而是一套可复用的技能定义体系——把怎么写测试怎么改 bug怎么重构怎么提交代码这些重复性的工作流抽象成 agent 能理解、能执行的标准化技能模块。配合skills CLI这类命令行工具你可以像装 npm 包一样把技能装进你的 Claude Code 环境里让它在特定场景下自动调用对应的技能。这件事为什么重要因为现在大多数人用 Claude Code 的方式还停留在对话式编程——你一句我一句靠 prompt 硬撑。这种方式在简单任务上还行一旦涉及多文件改动、测试驱动开发、跨模块重构agent 就开始失忆跑偏自作主张。而agent-skills提供的思路是把工作流固化下来让 agent 按套路出牌。这跟传统软件工程里把最佳实践沉淀成脚手架是一个逻辑。这篇文章适合谁看如果你正在用或者准备用 Claude Code、Cursor、Windsurf 这类 AI coding agent并且已经过了哇好神奇的阶段开始被它的不稳定性困扰那这篇就是写给你的。如果你还没入门也没关系我会把agent-skills的核心概念、skills CLI的用法、以及怎么跟test-driven-development这类工作流结合从头讲清楚。全文基于我自己的实操经验加上对这类工具常见设计的合理推演能抄作业的地方我直接给命令和配置。2. agent-skills 到底解决了什么问题核心设计与选型逻辑2.1 传统 prompt 工程的三个死穴在聊agent-skills的设计之前得先说清楚它要替代的东西有多痛。我用 Claude Code 大半年踩过的坑基本可以归成三类第一类是上下文漂移。你在一个长对话里让 agent 改 A 文件改着改着它开始动 B 文件理由是顺便优化一下。这种自作主张在简单脚本里无所谓但在生产代码里是灾难。你没法用一句 prompt 永久约束它因为对话越长早期的约束越容易被稀释。第二类是工作流不可复用。比如你有一套固定的 TDD 流程先写失败测试 → 跑测试确认失败 → 写最小实现 → 跑测试通过 → 重构。这套流程你每次都得重新用 prompt 描述一遍而且描述得越细token 消耗越大agent 还未必严格执行。第三类是技能无法沉淀。团队里张三摸索出一套好用的重构 prompt李四不知道各写各的。没有版本管理没有复用机制全靠口口相传。agent-skills的设计思路就是针对这三点把技能从对话里的临时指令变成文件系统里的持久资产。每个技能是一个独立的定义单元有明确的触发条件、执行步骤、约束规则。agent 在遇到对应场景时加载对应技能按技能里写死的流程走。2.2 为什么是技能而不是插件或提示词模板这里有个选型问题值得展开。市面上给 agent 增强能力的方式大致有三种插件plugin、提示词模板prompt template、技能skill。agent-skills选了第三种我认为是有道理的。插件的问题在于耦合太重。插件通常要对接具体的 API、具体的运行时一旦 agent 框架升级插件就得跟着改。而且插件是代码级的扩展写起来门槛高不适合快速迭代工作流。提示词模板的问题在于太轻、太散。一个模板就是一段文本没有结构没有触发逻辑没有版本概念。你存了 50 个模板最后自己都记不清哪个是哪个。技能则介于两者之间。它比模板重——有结构化的定义触发条件、步骤、约束、示例比插件轻——通常就是 Markdown 或 YAML 文件改起来快不需要写代码。更重要的是技能是面向场景的而不是面向功能的。一个技能对应一类任务比如修复失败的测试给函数补文档做一次安全重构这种粒度刚好匹配 agent 的工作方式。2.3 skills CLI 的角色让技能可安装、可管理光有技能定义还不够得有工具来管理它们。这就是skills CLI的定位。我理解它的核心职责有三个安装从某个源本地目录、远程仓库把技能装到 agent 的技能目录里列举与检索列出当前装了哪些技能按标签、场景搜索版本与更新技能也是会迭代的CLI 负责拉取新版本、处理依赖这套设计跟 npm、pip 是一个思路——把能力变成包用包管理器来治理。这个类比很重要因为它意味着你可以像管理依赖一样管理 agent 的能力锁定版本、审计来源、按项目隔离。提示技能目录的隔离很关键。我建议按项目维度管理技能而不是全局装一堆。全局技能容易互相干扰而且不同项目的技术栈、规范差异很大一套技能打天下不现实。2.4 与 test-driven-development 的天然契合agent-skills最典型的应用场景就是跟test-driven-developmentTDD结合。原因很简单TDD 是一套步骤明确、有验证闭环的工作流特别适合固化成技能。传统 TDD 的红-绿-重构三步每一步都有明确的输入输出和验证条件。你把它写成技能agent 就没法偷懒——它必须先写测试、必须跑测试看到失败、必须写最小实现、必须跑测试看到通过。每一步都有证据要求agent 想跳过都难。这比你在对话里反复强调记得先写测试啊有效得多。因为技能是结构化的约束不是口头的叮嘱。约束会被 agent 的运行时强制执行叮嘱只会被当成建议。3. 核心细节拆解一个技能文件里到底写了什么3.1 技能的基本结构虽然agent-skills的具体格式可能因版本而异但根据这类工具的通用设计一个技能定义通常包含以下几个部分。我按最常见的结构来讲你对照自己的实际版本调整name: tdd-workflow description: 测试驱动开发的标准工作流 trigger: - 用户要求实现新功能 - 用户要求修复 bug - 代码库中存在失败的测试 steps: - 编写一个失败的测试用例 - 运行测试确认它失败 - 编写最小实现让测试通过 - 运行测试确认通过 - 重构代码保持测试通过 constraints: - 禁止在测试通过前修改实现以外的代码 - 每次只处理一个测试用例 - 重构阶段不得改变外部行为 examples: - input: 实现一个计算斐波那契数列的函数 output: 先写 test_fib.py再写 fib.py这个结构里trigger 是最容易被忽视但最重要的部分。它决定了技能什么时候被激活。写得太宽技能会到处乱触发写得太窄该用的时候用不上。我的经验是trigger 要写场景而不是关键词因为关键词匹配太脆弱。3.2 触发条件的设计让 agent 在对的时候做对的事触发条件的设计直接决定了技能体系的可用性。我见过太多人把 trigger 写成关键词列表结果 agent 一看到测试两个字就加载 TDD 技能哪怕用户只是问这个测试文件在哪。更好的做法是基于意图和上下文来触发。比如意图层面用户表达了实现修复重构这类动作意图上下文层面当前工作目录有测试框架配置、有失败的测试、有未提交的改动两者结合触发才准。这跟推荐系统的逻辑类似——光看用户点了什么不够还得看用户在什么场景下点的。注意如果你的技能体系支持优先级一定要给技能排优先级。TDD 技能和快速原型技能的触发条件可能重叠但适用场景完全不同。没有优先级agent 会随机选一个结果不可预测。3.3 步骤的粒度太粗会跑偏太细会僵化步骤的粒度是个微妙的平衡。我试过两种极端太粗只写实现功能并测试。结果 agent 直接写完实现补个测试交差完全跳过 TDD 的核心价值。太细把每一步拆成打开文件定位函数插入代码这种操作级指令。结果 agent 变成了提线木偶遇到稍微不同的场景就卡住因为它没有自主判断空间。我的经验是步骤应该停在决策点上。也就是说每一步是一个需要 agent 做判断的节点而不是一个机械操作。比如编写一个失败的测试用例是个决策点——agent 要决定测什么、怎么测而在文件第 10 行插入代码是机械操作不该写进技能。3.4 约束的写法用禁止比用应该更有效约束部分是我踩坑最多的地方。早期我写约束喜欢用应该——应该先写测试应该保持代码风格一致。结果 agent 经常应该但不做。后来我改成禁止句式效果好很多禁止在测试通过前修改实现代码禁止一次修改超过 3 个文件禁止删除已有测试用例为什么禁止更有效因为 agent 在执行时对禁止类约束的遵守度明显高于应该类。这可能是训练数据里禁止往往对应硬性规则应该对应软性建议。不管原因是什么实测下来这个规律很稳。3.5 示例的作用给 agent 一个标准答案示例部分经常被省略但我觉得它价值很高。一个具体的 input-output 对相当于给 agent 一个标准答案让它知道这个技能执行到位是什么样子。写示例有个技巧示例要覆盖边界情况。比如 TDD 技能除了给一个正常实现功能的示例还要给一个测试已经存在只需补实现的示例一个测试失败需要先修测试的示例。这样 agent 遇到变体场景时有参照物。4. 实操过程从零搭一套可用的技能体系4.1 环境准备与 skills CLI 安装假设你已经装好了 Claude Code不管是 VS Code 插件版还是终端版接下来是装skills CLI。具体命令因工具而异但通用流程是这样的# 检查 node 环境skills CLI 通常依赖 node node -v npm -v # 全局安装 skills CLI示例命令按实际包名调整 npm install -g skills-cli # 验证安装 skills --version如果你在 Ubuntu 或 macOS 上node 环境建议用 nvm 管理避免权限问题。Windows 用户建议用 WSL因为很多 CLI 工具在原生 Windows 上路径处理会有坑。提示安装前先确认你的 Claude Code 版本。技能体系对 agent 版本有要求太老的版本可能不支持技能加载。用claude --version查一下必要时先升级。4.2 初始化技能目录技能目录的位置很关键。我建议按项目初始化而不是全局# 在项目根目录初始化技能配置 cd your-project skills init # 这会生成一个 .skills 目录和配置文件 ls -la .skills/初始化后你会得到一个技能目录结构。典型的布局是这样.skills/ ├── config.yaml # 技能体系配置 ├── skills/ # 技能定义文件 │ ├── tdd.yaml │ ├── refactor.yaml │ └── debug.yaml └── cache/ # 技能缓存.skills目录建议加进.gitignore的例外——也就是说技能定义要提交到版本库但缓存不要。这样团队共享技能但各自本地缓存独立。4.3 写第一个技能TDD 工作流我们来写一个完整的 TDD 技能。这是最实用的一个也是最能体现agent-skills价值的场景。name: tdd-workflow version: 1.0.0 description: 严格的测试驱动开发工作流适用于新功能实现和 bug 修复 tags: - testing - development - quality trigger: intents: - implement_feature - fix_bug conditions: - has_test_framework: true - working_tree_clean: true priority: 100 steps: - id: write_failing_test action: 编写一个针对目标行为的失败测试 verify: 测试文件已创建或修改 - id: run_test_expect_fail action: 运行测试确认它失败 verify: 测试输出显示失败 on_fail: 停止并报告说明测试未按预期失败 - id: write_minimal_impl action: 编写让测试通过的最小实现 verify: 实现代码已修改 - id: run_test_expect_pass action: 运行测试确认通过 verify: 测试输出显示通过 on_fail: 回到 write_minimal_impl - id: refactor action: 在测试保持通过的前提下重构 verify: 重构后测试仍通过 constraints: - 禁止在 run_test_expect_fail 通过前修改实现代码 - 禁止一次处理多个测试用例 - 禁止在 refactor 阶段改变外部行为 - 禁止跳过任何 verify 步骤 examples: - input: 实现一个函数判断字符串是否为回文 output: | 1. 创建 test_palindrome.py写 test_is_palindrome 2. 运行 pytest确认失败函数不存在 3. 在 palindrome.py 写最小实现 4. 运行 pytest确认通过 5. 重构提取辅助函数再跑测试这个技能里verify 字段是灵魂。它要求 agent 在每一步都提供证据而不是声称我做完了。on_fail字段则定义了失败时的处理逻辑避免 agent 卡死或乱来。4.4 安装与激活技能技能文件写好后用 CLI 安装到当前项目# 从本地文件安装 skills install ./tdd.yaml # 或者从技能仓库安装 skills install tdd-workflow # 列出已安装技能 skills list # 查看某个技能的详情 skills info tdd-workflow安装后技能会在 agent 下次启动时加载。你可以在 Claude Code 里用自然语言触发它比如帮我实现一个回文判断函数agent 应该会自动匹配到 TDD 技能并按其流程执行。4.5 验证技能是否生效验证这一步很多人跳过结果技能没生效都不知道。我的验证方法是故意制造一个容易跑偏的场景让 agent 实现一个稍微复杂点的功能然后观察它是否先写测试而不是先写实现跑测试并展示失败输出写最小实现而不是一次性写完整跑测试并展示通过输出如果它跳过了任何一步说明技能没生效或者约束不够强。这时候要回去检查 trigger 条件是否匹配、约束是否写得太软。注意技能生效与否跟 agent 的听话程度有关。有些 agent 版本对技能的遵守度不高这时候要在技能里加更强的约束或者在项目配置里设置强制技能模式。5. 常见问题与排查技巧实录5.1 技能不触发怎么办这是最高频的问题。技能装好了但 agent 该用的时候不用。排查顺序如下排查项检查方法常见原因技能是否加载skills list看是否在列表安装路径不对trigger 是否匹配手动构造触发场景测试条件写太严优先级是否被压制看是否有更高优先级技能优先级冲突agent 版本是否支持claude --version版本过老配置是否启用检查 config.yaml技能被禁用我遇到最多的是trigger 条件写太严。比如要求working_tree_clean: true但你工作区有未提交改动技能就永远不触发。解决办法是把非核心条件改成警告而非阻断。5.2 技能触发了但 agent 不遵守步骤这种情况通常是约束不够硬。agent 加载了技能但执行时偷懒。我的处理办法把关键步骤的verify改成强制项不通过就中断在约束里加禁止跳过 verify 步骤减少单次技能覆盖的步骤数宁可拆成多个小技能还有一个技巧在技能里加自检步骤。让 agent 在完成技能后自己回顾一遍是否每步都做了。这个自检动作会显著提升遵守度因为 agent 在回顾时会重新审视自己的行为。5.3 技能之间互相干扰装了多个技能后可能出现该用 A 却用了 B的情况。根因通常是触发条件重叠。解决办法给每个技能明确的 priority数字大的优先在 trigger 里加排除条件比如 TDD 技能排除用户明确要求快速原型的场景定期用skills list --conflicts检查冲突如果 CLI 支持我个人的经验是一个项目里同时激活的技能不要超过 5 个。技能太多agent 的选择成本上升出错概率也上升。宁可按需启用不要一次装一堆。5.4 技能更新后行为变了技能也是会迭代的。更新技能后agent 的行为可能跟之前不一样。这时候要做回归验证用之前验证过的场景重新跑一遍确认行为符合预期。我建议给技能加版本号并且在项目里锁定版本。就像锁 npm 依赖一样不要盲目追新。技能的行为变化有时候比代码变化影响还大。5.5 团队协作中的技能管理团队用技能体系最大的坑是技能定义不一致。张三改了 TDD 技能李四不知道两人跑出来的结果不一样。我的做法是技能定义提交到版本库走 code review技能变更要有 changelog关键技能加锁定标记改动需要讨论定期同步技能使用情况收集反馈这套流程听起来重但比各写各的 prompt高效得多。技能一旦沉淀下来就是团队的资产新人入职直接继承不用从头摸索。6. 把技能体系用出复利一些进阶思路6.1 技能的组合与嵌套单个技能解决单类问题但真实任务往往是多类问题的组合。比如实现一个新功能并部署涉及 TDD、代码审查、构建、部署多个环节。这时候可以把技能组合起来形成一个工作流技能。组合的方式有两种串行和条件分支。串行就是按顺序执行多个技能条件分支是根据中间结果决定走哪条路。agent-skills如果支持技能引用就能实现这种组合。6.2 从个人技能到团队技能库个人用技能价值有限。真正的复利来自团队技能库。当团队把常见工作流都沉淀成技能新项目的启动成本会大幅下降。建团队技能库的关键是分类和检索。按技术栈分、按任务类型分、按质量等级分。标签体系要统一否则检索就是灾难。我建议一开始就定好标签规范哪怕初期技能少。6.3 技能与 CI/CD 的结合技能不只能给 agent 用还能给 CI 用。比如把 TDD 技能的验证逻辑抽出来在 CI 里跑一遍确保提交的代码符合 TDD 规范。这样技能就从agent 的约束升级成团队的规范。这个思路的价值在于技能定义成了单一事实来源。agent 按它执行CI 按它检查人按它 review。三方一致扯皮就少了。6.4 技能的可观测性技能执行过程最好有日志。哪些技能被触发了、执行到哪一步、哪一步失败了这些数据积累起来能帮你优化技能定义。我自己的做法是让 agent 在技能执行时输出结构化日志然后定期分析。哪些技能经常失败、哪些步骤经常被跳过一目了然。这比凭感觉改技能靠谱得多。7. 我踩过的几个坑以及给你的建议最后分享几个我实际踩过的坑都是文档里不会写的。第一个坑技能写太满。我一开始恨不得把每个细节都写进技能结果技能文件几百行agent 加载慢执行时还经常选择性遵守。后来我学乖了技能只写关键决策点和硬约束细节留给 agent 自己判断。技能是护栏不是轨道。第二个坑忽视 agent 版本差异。同一个技能在不同版本的 Claude Code 上行为可能完全不同。我遇到过升级后技能突然不触发的情况排查半天才发现是新版本改了 trigger 的匹配逻辑。所以升级 agent 前先备份技能配置升级后跑回归测试。第三个坑技能没有版本管理。早期我改技能很随意改完也不记录。结果某天发现 agent 行为变了想回滚都不知道回滚到哪。现在我的技能文件都带版本号和 changelog改动必记录。第四个坑把技能当万能药。技能能解决工作流固化的问题但解决不了模型能力的问题。如果 agent 本身理解不了你的需求再好的技能也没用。技能是放大器不是补丁。如果你刚开始搭技能体系我的建议是从一个小技能开始比如就做一个 TDD 技能用一周感受一下它带来的变化。别一上来就搭大而全的体系那样大概率半途而废。技能体系的价值是慢慢积累出来的不是一次设计出来的。这套东西后续还能怎么扩展我最近在试的是把技能和项目的代码规范文档打通——技能里引用规范文档的章节agent 执行时自动加载对应规范。这样规范和技能就不会脱节改规范等于改技能。这个方向我觉得挺有搞头等跑顺了再单独写一篇。