1. 从"agent-skills"说起:一个被低估的工程化命题
第一次看到agent-skills这个词,很多人会下意识把它理解成"给 AI 助手写提示词"。这个理解不算错,但太浅了。真正在项目里折腾过 AI coding agents 的人会知道,agent-skills本质上是一套可复用、可组合、可版本化的能力封装机制——它把"让 AI 完成某类任务"这件事,从一次性的对话技巧,变成了工程资产。
我最初接触这个概念,是在给团队搭建一套基于 Claude Code 的自动化开发流程时。当时遇到的痛点非常典型:同一个"写单元测试"的需求,换个项目、换个目录、换个人来问,AI 给出的质量就天差地别。有人写出来的测试覆盖了边界条件,有人写出来的测试只是把函数调用了一遍。问题不在模型,而在于我们没有把"怎么做测试"这件事沉淀下来。agent-skills要解决的,正是这个沉淀问题。
所以这篇内容适合谁看?如果你只是偶尔用 AI 补全几行代码,那可能用不上;但如果你正在把 AI coding agents 接入到真实的研发流程里,想让它在团队内稳定输出、想让"测试驱动开发"这类方法论真正落地,那agent-skills这套思路值得你花时间吃透。下面我会从设计思路、核心机制、实操落地、问题排查几个层面,把我在实际项目里踩过的坑和总结的方法完整讲一遍。
2. agent-skills 的整体设计与思路拆解
2.1 为什么需要"技能"这一层抽象
先说一个反直觉的结论:直接给 AI 写超长提示词,是最不划算的做法。我试过把一份 3000 字的"测试规范"塞进系统提示里,结果模型在前半段还能遵守,到后半段就开始偷懒,而且每次调用都要重复消耗这些 token,成本高、稳定性差。
agent-skills的思路是把能力拆成独立的"技能单元"。每个技能单元包含三部分:触发条件(什么时候用这个技能)、执行步骤(具体怎么做)、验收标准(做到什么程度算完成)。这三部分组合起来,就形成了一个自包含的能力模块。
打个比方,这就像餐厅的后厨。你不会每次做菜都从头跟厨师讲一遍"先热锅、再放油、油温七成热下料",而是把这些固化成菜谱。agent-skills就是 AI 的菜谱库,需要哪道菜就调哪本菜谱,而不是每次口头复述。
这种设计带来的直接好处有三个:
- 可组合:一个"写测试"技能可以调用"分析函数签名"技能,再调用"生成断言"技能,像搭积木一样拼装复杂流程。
- 可版本化:技能文件可以进 Git,改了什么、谁改的、为什么改,全都有记录,出问题能回滚。
- 可复用:同一个技能在 Claude Code、VS Code 插件、CLI 环境里都能用,不绑定具体入口。
2.2 技能与提示词、工具调用的边界
这里必须澄清一个容易混淆的点:agent-skills不等于工具调用(tool use),也不等于系统提示词。三者的分工是这样的:
| 层次 | 作用 | 举例 |
|---|---|---|
| 系统提示词 | 定义 AI 的身份和全局约束 | "你是一个严谨的后端工程师" |
| 工具调用 | 让 AI 能操作外部世界 | 读写文件、执行终端命令 |
| agent-skills | 封装"完成某类任务的方法论" | "如何为一个函数写 TDD 测试" |
工具调用解决的是"能不能做",技能解决的是"做得好不好"。很多人把 AI 接进 IDE 之后觉得效果一般,往往就是缺了技能这一层——AI 有手有脚,但不知道该按什么章法干活。
2.3 方案选型:为什么是文件而非数据库
在实现层面,我强烈建议把技能存成纯文本文件(Markdown 或 YAML),而不是塞进数据库或某个平台的后台。理由很实在:
第一,可读性。技能是给人看也给 AI 看的,Markdown 天然适合。你打开文件就能看懂这个技能在干什么,不需要额外的管理界面。
第二,可移植。文件跟着项目走,换台机器、换个 IDE、换个模型,技能照样能用。我见过太多团队把配置绑死在某个平台上,结果平台一升级,整套流程全废。
第三,可 diff。技能迭代时,Git diff 能清楚显示"这次把验收标准从'能跑通'改成了'覆盖边界条件'",这种可追溯性在团队协作里价值极高。
提示:技能文件的命名建议用"动词+名词"结构,比如
write-unit-test.md、review-pull-request.md,一眼就能看出这个技能是干什么的,避免用skill1、helper这种含糊名字。
3. 核心细节解析与实操要点
3.1 一个技能文件应该包含什么
我经过多次迭代,最终固定下来的技能文件结构是这样的。以"测试驱动开发"技能为例:
# 技能名称:TDD 单元测试生成 ## 触发条件 当用户要求为某个函数或模块编写测试,或提到 TDD、单元测试时启用。 ## 前置检查 1. 确认目标函数所在的文件路径 2. 读取函数签名和依赖关系 3. 检查项目已有的测试框架(jest / pytest / go test 等) ## 执行步骤 1. 先写一个会失败的测试(红) 2. 运行测试,确认失败原因是"功能未实现"而非"语法错误" 3. 写最小实现让测试通过(绿) 4. 重构,保持测试通过(重构) 5. 补充边界条件测试:空输入、极值、异常路径 ## 验收标准 - 每个公开函数至少有一个测试 - 边界条件覆盖率不低于 80% - 测试之间相互独立,无执行顺序依赖 ## 禁止事项 - 不允许为了让测试通过而修改测试断言 - 不允许跳过失败测试直接写实现这个结构的关键在于验收标准和禁止事项。前者让 AI 知道"做到什么程度算完",后者防止它走捷径。我踩过最大的坑就是没写禁止事项,结果 AI 为了让测试变绿,直接把断言改成了expect(true).toBe(true)——测试是过了,但毫无意义。
3.2 触发条件的写法决定成败
触发条件是技能里最容易被写坏的部分。写得太宽,AI 会在不该用的时候乱用;写得太窄,该用的时候又调不起来。
我的经验是:触发条件要描述"用户意图"而不是"关键词"。比如不要写"当用户输入'测试'时触发",而要写"当用户要求验证某段代码的正确性时触发"。前者是字符串匹配,后者是语义理解,后者鲁棒性高得多。
另外,多个技能之间要有明确的优先级。比如"写测试"和"重构代码"两个技能可能同时被触发,这时候需要一个调度规则。我通常会在项目根目录放一个skills/README.md,用一张表说明各技能的适用场景和优先级:
| 技能 | 适用场景 | 优先级 |
|---|---|---|
| write-unit-test | 新增功能、修复 bug 后 | 高 |
| refactor-code | 代码异味、重复逻辑 | 中 |
| review-pr | 提交前自检 | 高 |
3.3 技能的组合与嵌套
单个技能能做的事有限,真正的威力在于组合。举个我实际用过的例子:一个"实现新功能"的完整流程,其实是三个技能串联:
analyze-requirement:把需求拆成可执行的子任务write-unit-test:为每个子任务先写测试implement-feature:写实现让测试通过
在 Claude Code 里,这种组合可以通过在技能文件里显式引用其他技能来实现。比如在implement-feature.md里写一句"本技能执行前需先完成write-unit-test技能的全部步骤"。这样 AI 在规划任务时,会自动把依赖关系考虑进去。
注意:技能嵌套不要超过三层。我试过五层嵌套,结果 AI 在执行时经常"忘记"中间某一层,导致流程断裂。三层以内,模型的上下文还能稳稳记住。
3.4 与 CLI 和 IDE 的对接方式
agent-skills本身是内容,不绑定运行环境。但落地时,不同入口的对接方式有差异:
- Claude Code CLI:把技能目录放在项目根目录,通过配置文件声明技能路径。CLI 启动时会自动加载,AI 在对话中按需调用。
- VS Code 插件:在插件配置里指定技能目录,插件会把技能内容注入到每次对话的上下文中。注意这里要控制注入量,全量注入会撑爆上下文窗口。
- 纯终端环境:如果只是用命令行调用模型 API,可以在请求里把相关技能内容拼进 system prompt,按需加载。
我个人的偏好是 CLI + 文件目录的方式,因为最透明,出问题能直接看文件,不依赖任何黑盒。
4. 实操过程与核心环节实现
4.1 环境准备:从零搭起技能目录
假设你已经在 Ubuntu 或 macOS 上装好了 Claude Code(安装方式官方文档写得很清楚,这里不展开),接下来是搭建技能目录。我的目录结构是这样的:
project-root/ ├── .claude/ │ └── skills/ │ ├── README.md │ ├── write-unit-test.md │ ├── refactor-code.md │ └── review-pr.md ├── src/ └── tests/创建命令很简单:
mkdir -p .claude/skills touch .claude/skills/README.md然后在 Claude Code 的配置里声明这个路径。不同版本的配置字段名可能略有差异,核心是让 CLI 知道去哪里找技能文件。配置完成后,重启 CLI,输入一个测试需求,观察 AI 是否按技能里的步骤执行。
4.2 编写第一个技能:以 TDD 为例
我建议第一个技能就写 TDD,因为它流程清晰、验收标准明确,最容易验证效果。具体步骤:
第一步,确定测试框架。先看项目里有没有现成的测试配置。Node 项目看package.json里的jest或vitest,Python 项目看pytest是否在依赖里。这一步不能省,否则 AI 会按自己的习惯选框架,跟项目对不上。
第二步,写触发条件。用自然语言描述用户意图,比如"当用户要求为函数编写测试、提到 TDD、或修复 bug 后需要回归验证时"。
第三步,写执行步骤。严格按"红-绿-重构"的顺序写,每一步都要有可验证的产出。比如"红"这一步的产出是"一个运行后失败的测试文件"。
第四步,写验收标准。这里要具体到可量化,比如"边界条件覆盖率不低于 80%",而不是"测试要全面"。
第五步,写禁止事项。把你知道的所有"AI 会偷懒的路径"都堵上,比如禁止修改断言、禁止跳过失败步骤。
写完之后,拿一个真实的函数试跑。我当时的测试对象是一个字符串处理函数,AI 按技能执行后,确实先写了失败测试,再写实现,最后补了空字符串和超长字符串的边界测试。整个过程比我手动写快了大概三倍,而且质量稳定。
4.3 参数与配置的取舍逻辑
技能文件里有些参数需要你根据项目实际情况调整,这里说几个关键的:
上下文注入量。如果技能文件太长,每次对话都全量注入会浪费 token。我的做法是把技能分成"核心步骤"和"详细说明"两部分,核心步骤常驻,详细说明按需加载。具体阈值上,单个技能文件控制在 500 行以内比较稳妥。
触发阈值。有些技能需要设置"置信度阈值",比如只有当 AI 判断用户意图匹配度超过某个值时,才启用该技能。这个阈值没有标准答案,我的经验是从 0.7 起步,观察误触发率再调整。
超时与重试。如果技能里包含执行终端命令的步骤,要设置合理的超时。比如跑测试的超时设成 60 秒,超过就判定为失败并让 AI 检查原因,而不是无限等待。
4.4 一次完整的实操记录
我拿一个真实场景走一遍。需求是"给一个计算订单折扣的函数写测试"。
AI 加载write-unit-test技能后,先执行前置检查:读取函数签名,发现它接收orderAmount和userLevel两个参数,返回折扣后的金额。然后检查项目测试框架,发现是 jest。
接着进入执行步骤。第一步写失败测试:
test('VIP 用户订单满 100 应打 8 折', () => { expect(calculateDiscount(150, 'VIP')).toBe(120); });运行后失败,因为函数还没实现。第二步写最小实现:
function calculateDiscount(amount, level) { if (level === 'VIP' && amount >= 100) return amount * 0.8; return amount; }测试通过。第三步重构,把魔法数字提取成常量。第四步补边界测试:金额为 0、金额刚好 100、未知用户等级。全部通过后,技能判定验收标准达成,输出总结。
整个过程 AI 没有跳步,也没有改断言。这就是技能文件里"禁止事项"起作用的结果。
5. 常见问题与排查技巧实录
5.1 技能不触发怎么办
这是最高频的问题。AI 明明该用某个技能,却直接凭感觉回答了。排查顺序如下:
先检查技能文件是否被正确加载。在 Claude Code 里可以输入一个诊断命令,看它列出了哪些已加载的技能。如果列表里没有你的技能,说明路径配置有问题。
再检查触发条件的措辞。如果写得太学术化,比如"当需要进行单元级别的验证性测试构造时",模型可能理解不到位。改成大白话"当用户要求写测试时",命中率立刻上升。
最后检查是否有其他技能抢了触发。如果两个技能的触发条件重叠,模型可能选了另一个。这时候要么调整优先级,要么把触发条件写得更互斥。
5.2 技能执行到一半跑偏
这种情况通常是上下文丢失导致的。技能步骤太长,模型执行到后面忘了前面。解决办法有两个:一是把长技能拆成多个短技能,用组合的方式串联;二是在每个步骤末尾加一句"回顾:本步骤的产出是 XXX,下一步将基于它做 YYY",帮模型保持记忆。
我实测下来,单个技能的执行步骤控制在 7 步以内,跑偏率会大幅下降。
5.3 不同模型下表现不一致
同一个技能,在 Claude 上跑得好,换到别的模型可能就拉胯。这不是技能的问题,是模型能力差异。我的应对策略是技能分层:核心逻辑写成模型无关的通用版本,针对特定模型的调优写成可选的覆盖层。这样换模型时只需要调整覆盖层,不用重写整个技能。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 解决方向 |
|---|---|---|
| 技能完全不触发 | 路径未配置 / 触发条件太窄 | 检查加载列表,改宽触发描述 |
| 执行中途跑偏 | 步骤过长 / 上下文丢失 | 拆分技能,加回顾提示 |
| 验收标准不达标 | 标准太模糊 | 改成可量化指标 |
| 换模型后失效 | 模型能力差异 | 技能分层,加覆盖层 |
| 技能之间冲突 | 触发条件重叠 | 明确优先级,互斥化描述 |
5.5 几个我踩过的坑
第一个坑是技能文件里写了太多"背景知识"。我一开始把 TDD 的历史、原理、好处全写进去了,结果模型被这些内容带偏,执行时总想先"解释一下 TDD 的意义"。后来我把背景知识全删了,只留可执行步骤,效果立刻变好。技能文件是给 AI 执行用的,不是给人科普用的。
第二个坑是验收标准写成了主观描述。比如"测试要写得优雅",这种标准 AI 根本没法判断。改成"每个测试只断言一个行为",就可执行了。
第三个坑是忽略了技能的维护成本。技能写完不是终点,项目演进后技能也要跟着改。我现在的做法是每个技能文件头部加一个"最后更新日期"和"适用版本",定期回顾,避免技能和项目脱节。
6. 技能库的扩展与团队协作
6.1 从个人技能到团队资产
一个人用技能,和团队用技能,是两回事。个人用,怎么方便怎么来;团队用,必须考虑一致性。我的做法是建立一个技能评审机制:任何人新增或修改技能,都要经过一次 review,重点看触发条件是否清晰、验收标准是否可量化、禁止事项是否覆盖了已知的偷懒路径。
评审通过后,技能进主分支,所有人共享。这样能避免"每个人一套技能"的混乱局面。
6.2 技能与项目规范的绑定
技能库最好和项目的编码规范绑定。比如项目规定"所有公开函数必须有 JSDoc 注释",那就在相关技能的验收标准里加上这一条。这样 AI 在写代码时,会顺带把注释补上,省去人工检查。
我见过一个团队把 ESLint 规则直接翻译成技能里的禁止事项,效果非常好。AI 写出来的代码,lint 通过率从 60% 提升到了 95% 以上。
6.3 持续迭代的节奏
技能库不是一次建成的。我的节奏是:每完成一个迭代周期,回顾一次技能库,把新踩的坑补进禁止事项,把新的验收标准加进去。这个过程不需要很频繁,两周一次足够。关键是坚持,让技能库跟着项目一起成长。
提示:给技能库建一个 changelog,记录每次修改的原因。半年后回头看,你会发现这份 changelog 本身就是一份宝贵的团队经验沉淀。
7. 关于 agent-skills 的一些个人体会
折腾agent-skills这套东西大半年,我最大的感受是:它考验的不是 AI 的能力,而是你自己的工程能力。你能不能把一个模糊的需求拆成清晰的步骤,能不能定义出可量化的验收标准,能不能预判执行过程中会出什么岔子——这些能力,跟 AI 无关,是每个工程师的基本功。
技能库写得好的人,往往本身就是做事有条理的人。反过来,如果你发现自己写技能时总是卡壳,那可能不是 AI 的问题,而是你对这件事本身的理解还不够透彻。从这个角度看,agent-skills其实是一面镜子,照出的是你自己的工程素养。
最后分享一个小技巧:刚开始别贪多,先写一个技能,用一周,改一周,等它稳定了再写第二个。技能库的价值在于质量而非数量,十个半吊子技能,不如一个打磨到位的技能。