ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

agent-skills工程化实践:用技能单元与测试驱动提升AI编码代理稳定性

agent-skills工程化实践:用技能单元与测试驱动提升AI编码代理稳定性 1. 从agent-skills说起一个被低估的工程化命题第一次看到agent-skills这个词很多人会下意识地把它理解成给 AI 智能体写提示词。这个理解不算错但太浅了。真正在 AI coding agents 这条线上摸爬滚打过一段时间的人会明白agent-skills本质上是一套把人类工程经验沉淀成可复用、可组合、可测试的能力单元的方法论。它解决的不是怎么让 AI 更聪明而是怎么让 AI 在具体项目里稳定地做对事。我接触 Claude Code 这类终端型 AI coding agent 有一段时间了从最早的哇它能直接改文件到后来的为什么它老是改错地方中间踩的坑基本都指向同一个根因agent 缺的不是智力是技能边界。你让它写一个 React 组件它能写得有模有样但你让它按你团队的规范写、按你项目的目录结构写、按你既有的测试风格写它就开始飘了。agent-skills要处理的正是这个飘的问题。这篇文章适合三类人看一是已经在用 Claude Code、Cursor、各类 AI coding agent但总觉得输出不稳定、想找一套系统化约束方法的人二是团队里负责搭建 AI 辅助开发流程、需要把个人经验变成团队资产的人三是对skills CLI、test-driven-development这类关键词感兴趣想搞清楚它们和 agent 能力建设之间关系的人。不管你是刚装完 Claude Code 的新手还是已经能熟练用cc switch切换不同模型的老手下面这些内容应该都能给你一些可以直接抄作业的东西。我会从设计思路讲到具体实现从技能拆解讲到测试驱动尽量把为什么这么设计讲透而不是只丢一堆配置让你照抄。因为agent-skills这东西抄配置只能解决 30% 的问题剩下 70% 靠的是你对自己项目工作流的理解。2. 核心设计思路为什么 agent 需要技能而不是提示词2.1 提示词的天花板在哪里先说个我自己的真实经历。早期我用 Claude Code 的时候习惯在项目根目录放一个CLAUDE.md把项目规范、技术栈、注意事项全塞进去。一开始挺爽agent 确实听话了不少。但项目一复杂问题就来了这个文件越写越长从 200 行涨到 800 行最后 agent 开始选择性失忆——它记住了前半段忘了后半段或者把 A 模块的规范套用到 B 模块上。这不是模型不行是上下文的结构问题。提示词是线性的、扁平的而真实项目是模块化的、有层次的。你把所有规则平铺在一个文件里agent 每次都要在噪音里找信号效率自然低。agent-skills的核心思路就是把这个扁平结构打散变成按需加载的能力包。每个 skill 是一个独立单元有自己的触发条件、自己的上下文、自己的验证方式。agent 在处理某个具体任务时只加载相关的 skill而不是把整个知识库都塞进上下文。这个思路和微服务拆分、和前端按需加载是同一个逻辑——降低单次决策的认知负荷。2.2 一个 skill 应该长什么样我理解的合格 skill至少包含四个部分触发描述什么情况下该用这个 skill。比如当需要新增一个 API 端点时。操作步骤具体怎么做最好是可执行的、有顺序的。约束条件不能做什么边界在哪里。这部分最容易被忽略但恰恰最重要。验证方法做完之后怎么确认做对了。这一步直接关联到test-driven-development。举个具体例子。假设你的项目是 Node.js Express你想让 agent 规范地新增 API。一个粗糙的提示词写法是新增 API 时请遵循 RESTful 规范。这句话对 agent 来说几乎等于没说因为RESTful 规范在不同项目里含义完全不同。而一个 skill 化的写法是这样的## Skill: 新增 API 端点 ### 触发条件 用户要求新增、修改或删除 HTTP 接口时。 ### 操作步骤 1. 在 src/routes/ 下找到对应的路由文件不存在则新建 2. 路由处理函数统一放在 src/controllers/路由文件只做转发 3. 请求参数校验使用 zodschema 定义在 src/schemas/ 4. 数据库操作统一走 src/services/controller 不直接调 ORM 5. 新增端点后在 tests/api/ 下补充对应的集成测试 ### 约束条件 - 禁止在 controller 里写 SQL 或 ORM 查询 - 禁止跳过参数校验直接使用 req.body - 错误响应统一使用 src/utils/errorHandler.js 的格式 ### 验证方法 - 运行 npm run test:api新增端点的测试必须通过 - 用 curl 手动打一次确认返回结构符合 { code, data, message } 格式你看这个 skill 里没有一句废话全是可执行、可验证的东西。agent 拿到它不需要理解你的项目哲学只需要按步骤执行、按约束检查、按验证确认。这就是agent-skills和普通提示词的本质区别前者是操作手册后者是价值观宣言。2.3 为什么这套东西值得工程化有人可能会问我直接写在CLAUDE.md里不行吗行但有几个问题。第一是复用性。你团队有 5 个项目技术栈类似但细节不同。如果每个项目都写一份完整的规范维护成本极高。skill 化之后公共部分抽出来共享项目特有的部分单独覆盖改一处就能影响所有项目。第二是可测试性。这是test-driven-development和agent-skills结合的关键点。一个 skill 写得好不好不能靠感觉要靠测试。你可以设计一组任务让 agent 在加载 skill 前后分别执行对比通过率。skill 是可以被单元测试的提示词不行。第三是版本管理。skill 是文件可以进 git可以 code review可以回滚。你改了一个 skill 导致 agent 行为变差git revert就完事了。而提示词散落在各种对话里改坏了你都不知道是哪次改的。3. 核心细节解析skills CLI 与目录结构设计3.1 skills CLI 到底解决什么问题skills CLI这类工具的出现本质是为了解决 skill 的分发和加载问题。你可以手动把 skill 文件放到项目里但当 skill 数量上到几十个、需要在多个项目间同步、需要区分全局 skill 和项目 skill 时手动管理就崩了。CLI 通常提供几个核心能力安装 skill从本地或远程源、列出已安装 skill、启用/禁用某个 skill、更新 skill 版本。这听起来很朴素但实际用起来差别很大。我见过有人把 skill 直接 commit 到项目仓库结果每次更新都要手动同步到所有项目也见过有人用 CLI 管理一条命令搞定所有项目的 skill 更新。提示选 CLI 工具时重点看它是否支持项目级覆盖全局级的机制。因为团队公共 skill 和项目特有 skill 经常冲突没有覆盖机制的话你只能二选一。3.2 目录结构怎么设计才不混乱我试过几种目录结构最后稳定下来的方案是这样的.agent-skills/ ├── global/ # 全局通用 skill │ ├── git-commit.md │ ├── code-review.md │ └── error-handling.md ├── project/ # 项目特有 skill │ ├── api-endpoint.md │ ├── db-migration.md │ └── deploy-check.md ├── config.json # skill 加载配置 └── tests/ # skill 的验证用例 ├── api-endpoint.test.md └── db-migration.test.md这个结构的关键在于分层。global/放的是跨项目通用的能力比如怎么写 commit message、怎么做 code reviewproject/放的是这个项目独有的比如我们的 API 端点怎么加、数据库迁移走什么流程。config.json控制加载顺序和优先级tests/放验证用例。为什么要把测试单独放因为 skill 的测试和代码测试不一样。代码测试跑的是断言skill 测试跑的是给 agent 一个任务看它输出是否符合预期。这种测试更像集成测试需要单独组织。3.3 skill 的粒度怎么把握这是最容易踩坑的地方。粒度太粗一个 skill 管一大片agent 还是抓不住重点粒度太细skill 数量爆炸加载和维护都成负担。我的经验是一个 skill 对应一个可独立验证的工作单元。判断标准很简单——如果这个 skill 做完之后你能用一句话说清楚做完了什么、怎么验证那粒度就合适。如果说不清楚说明它太粗如果一句话里包含了好几个然后说明它太细。举个例子。新增 API 端点是一个合适的粒度因为它有明确的输入需求、明确的输出可用的端点、明确的验证测试通过。而处理用户相关逻辑就太粗了它可能包含注册、登录、权限、资料修改等一堆事。反过来在路由文件里加一行 import就太细了这种细节应该写在新增 API 端点的步骤里而不是单独成 skill。4. 实操过程从零搭建一套 agent-skills 体系4.1 第一步盘点你项目里的高频操作别急着写 skill先花半天时间做一件事记录你和 agent 协作时最常让它做的 10 件事。不用很精确凭印象列就行。我自己的清单大概是这样的新增/修改 API 端点写数据库迁移脚本修复 bug尤其是测试报错重构某个模块补充单元测试写 commit message处理依赖升级写文档注释排查构建/部署问题代码 review这 10 件事里前 5 件是高频且高价值的优先给它们写 skill。后 5 件可以先用通用 skill 兜着后面再细化。4.2 第二步为每个高频操作写 skill 草稿写 skill 有个技巧先写验证方法再写操作步骤。因为验证方法决定了这个 skill 的边界边界清楚了步骤自然就好写。以修复 bug为例。验证方法是什么最直接的是相关测试从红变绿。那 skill 的边界就清楚了它处理的是有测试覆盖的 bug。如果 bug 没有测试覆盖那这个 skill 的第一步应该是先补一个能复现 bug 的测试然后再修。草稿可以这样写## Skill: 修复有测试覆盖的 Bug ### 触发条件 用户报告某个测试失败或某个功能行为不符合预期且已有测试覆盖。 ### 操作步骤 1. 运行相关测试确认失败现象记录错误信息 2. 阅读测试代码理解测试期望的行为 3. 定位到实现代码分析失败原因 4. 修改实现代码最小化改动范围 5. 重新运行测试确认通过 6. 运行完整测试套件确认没有引入回归 ### 约束条件 - 禁止为了让测试通过而修改测试代码除非测试本身写错了 - 禁止大范围重构bug 修复只做必要改动 - 如果发现是测试写错了必须明确说明理由 ### 验证方法 - 目标测试从失败变为通过 - 完整测试套件全部通过 - 改动范围不超过 3 个文件超过则需说明理由这个 skill 里禁止修改测试代码这条约束特别重要。我见过太多次 agent 为了让测试通过直接把断言改了表面上修好了实际上把 bug 藏起来了。这条约束就是防这个的。4.3 第三步用 test-driven-development 验证 skillskill 写完不是终点是起点。接下来要做的是用测试驱动的方式验证 skill 是否有效。具体怎么做设计一组任务每个任务对应一个 skill然后让 agent 在两种条件下执行不加载 skill 和加载 skill。对比结果。我拿新增 API 端点这个 skill 做过测试。任务是给用户模块新增一个查询用户列表的接口。不加载 skill 时agent 的输出是这样的直接在路由文件里写了处理逻辑参数校验用了手写的 if-else数据库查询直接写在路由里没有补测试加载 skill 后路由文件只做转发逻辑在 controller参数校验用了 zod schema数据库查询走了 service 层补了集成测试差别非常明显。这个对比过程本身就是 skill 的测试报告你可以把它记录下来作为 skill 有效性的证据。注意skill 测试不要只测一次。模型会更新你的项目会变化skill 的有效性也会漂移。建议每个月跑一次回归测试尤其是升级 Claude Code 版本或切换模型之后。4.4 第四步把 skill 接入 Claude CodeClaude Code 加载 skill 的方式取决于你用的版本和配置。常见做法有两种一种是通过CLAUDE.md引用 skill 文件另一种是通过 CLI 工具自动注入。我倾向后者因为手动引用容易漏。配置大概长这样{ skills: { global: [.agent-skills/global/*.md], project: [.agent-skills/project/*.md], priority: project-over-global } }priority这个字段很关键。当全局 skill 和项目 skill 冲突时项目 skill 优先。比如全局 skill 说commit message 用英文项目 skill 说用中文那这个项目就用中文。接入之后建议做一次冒烟测试随便让 agent 做一件小事看它有没有按 skill 走。如果没走检查两个地方——skill 文件路径对不对触发条件写得够不够明确。4.5 第五步迭代和沉淀skill 体系不是一次搭完就完事的。我的做法是每周花半小时做一次skill 复盘回顾这周 agent 做错的事看是不是某个 skill 没覆盖到或者覆盖了但写得不够清楚。复盘时我会问三个问题这个错误是 skill 缺失导致的还是 skill 存在但没触发如果是没触发触发条件是不是写得太窄了如果是触发了但做错了是步骤不清楚还是约束不够这三个问题能帮你精准定位问题而不是笼统地再改改 skill。5. 常见问题与排查技巧实录5.1 skill 不生效的几种典型情况这是被问得最多的问题。我整理了一个排查表按出现频率排序现象可能原因排查方法agent 完全无视 skillskill 文件没被加载检查 config.json 路径确认文件存在agent 偶尔遵守偶尔不遵守触发条件太模糊把触发条件改得更具体加上关键词agent 遵守了但做错步骤描述有歧义把步骤拆得更细每步只做一件事agent 遵守了但过度执行约束条件缺失补充禁止类约束多个 skill 冲突优先级没配好检查 priority 配置明确覆盖关系我遇到最多的是第二种——触发条件太模糊。比如写当需要处理数据时这个处理数据太宽泛了agent 根本不知道什么时候该用。改成当需要新增、修改或删除数据库记录时命中率立刻上去了。5.2 skill 写多长才合适这个问题没有标准答案但有个经验值单个 skill 控制在 50 到 150 行之间。低于 50 行通常说明粒度太细或者内容太单薄高于 150 行agent 的注意力会分散执行质量下降。如果你的 skill 超过 150 行考虑拆成两个。拆分点通常在这几个地方操作步骤超过 8 步、约束条件超过 6 条、或者出现了明显的阶段划分比如先做 A 阶段再做 B 阶段。5.3 怎么处理 skill 和项目现有规范的冲突这是个组织问题不是技术问题。我的建议是skill 应该反映项目实际规范而不是理想规范。如果项目现有代码风格很乱你写一个理想风格的 skillagent 会按理想风格写新代码结果新老代码风格不一致反而更乱。正确做法是分两步走先写一个跟随现有风格的 skill让 agent 模仿周围代码等团队决定统一风格后再更新 skill。这样过渡更平滑。5.4 独家避坑技巧分享几个我踩坑踩出来的经验。第一个坑别在 skill 里写尽量、最好这类词。agent 对这类模糊词的处理很不稳定。要么写必须要么写禁止中间态的词只会让 agent 犹豫。第二个坑skill 里的示例代码要能跑。我见过有人在 skill 里贴了一段伪代码结果 agent 照着伪代码写生成了一堆跑不通的东西。示例代码必须是真实可运行的哪怕简化过。第三个坑定期清理僵尸 skill。项目演进后有些 skill 已经过时了但还挂在配置里。这些僵尸 skill 会干扰 agent 的判断。建议每季度清理一次把不再适用的 skill 归档。第四个坑skill 的命名要一致。我一开始命名很随意有的叫新增API有的叫add-endpoint有的叫API开发。后来统一成动词-名词格式比如新增-API端点、修复-Bug、重构-模块管理起来清爽多了。6. 影响范围与延展思考agent-skills这套东西的价值其实超出了让 AI 写代码更准这个层面。它真正改变的是团队知识的组织方式。传统上团队经验散落在文档、代码注释、老员工脑子里。新人来了靠口口相传。agent-skills提供了一种新的载体把经验写成 agent 能执行、能验证的 skill。这些 skill 既是给 agent 看的也是给新人看的——因为一个写得好的 skill本身就是一份高质量的操作手册。从更长的视角看这套方法会推动两件事。一是开发流程的显性化。很多团队的工作流是隐性的大家凭感觉做事。写 skill 的过程就是把这些隐性流程逼出来的过程。二是质量标准的可执行化。以前说代码要写得好现在得说清楚好的标准是什么因为 agent 需要明确的判断依据。我个人的体会是搭这套体系前期投入不小大概需要两三周才能跑顺。但一旦跑起来收益是复利的——每写一个 skill后面所有相关任务都受益。而且 skill 是可以跨项目复用的你在这个项目沉淀的经验下个项目直接拿来用。最后分享一个小技巧如果你不确定某个 skill 该怎么写先别写先观察。让 agent 做几次相关任务记录它做对和做错的地方然后把这些观察整理成 skill。这样写出来的 skill 最接地气也最有效。
返回列表