1. 从"agent-skills"这个标题能读出什么
第一次看到agent-skills这个仓库名,我的直觉是:这不是又一个"提示词大全",而是一套把 AI coding agent 当"新员工"来培养的技能体系。标题里的 skills 用的是复数,说明它不是一个单点技巧,而是一组可组合、可复用、可被 agent 主动调用的能力单元。结合热搜词里高频出现的 AI coding agents、skills CLI、Claude Code、test-driven-development,基本可以判断:这个项目要解决的核心问题是——如何让一个通用大模型驱动的编码代理,在具体工程里表现得像一个懂规矩、有方法论的熟练工程师,而不是一个只会补全代码的自动补全器。
大多数人用 AI 写代码的方式还停留在"对话式":打开对话框,描述需求,复制粘贴结果,跑一下报错了再贴回去。这种方式在写几十行脚本时够用,但一旦进入真实项目——有测试、有 lint、有目录约定、有 CI——就会迅速崩盘。崩盘的原因不是模型不够聪明,而是它不知道这个项目的"规矩"。agent-skills这类项目的价值,就是把这些规矩和方法论沉淀成 agent 能读、能执行、能自我校验的技能包。
这篇文章适合三类人看:一是已经在用 Claude Code 或类似 AI coding agent、但总觉得"它不够听话"的开发者;二是想给团队搭建一套 AI 辅助开发规范的技术负责人;三是单纯好奇"skills CLI 到底是个什么东西"的探索者。我会从技能的本质讲起,拆到目录结构、CLI 用法、TDD 技能的具体设计,再聊接入不同模型时的坑,最后给一套可以直接抄的落地流程。全程按我自己的实操经验来写,不堆概念。
需要先说明一点:下面涉及的具体命令、目录命名、配置字段,凡是输入材料里没有明确给出的,都是基于这类工具常见实践做的合理补全,你在自己项目里落地时以实际版本为准。
2. 为什么"技能"比"提示词"更适合 agent
2.1 提示词是临时的,技能是沉淀的
提示词(prompt)的本质是一次性指令。你今天写了一段很长的系统提示,告诉模型"写代码前先写测试、提交前跑 lint、不要用 any 类型",明天换个会话,这些约束就没了。你得反复粘贴,或者塞进一个越来越臃肿的配置文件里。时间一长,这个配置文件会变成一坨没人敢动的"祖传提示词"。
技能(skill)的思路完全不同。它把一类任务的方法论拆成一个独立单元,每个单元有自己的触发条件、执行步骤、校验标准。agent 在遇到对应场景时,主动加载这个技能,按里面的流程走。这就像公司里的 SOP 文档:新员工不需要你每次口头交代,他自己会去翻对应的操作手册。
这个区别带来的直接好处是可维护性。测试驱动开发是一套技能,代码审查是一套技能,数据库迁移是一套技能。它们互不干扰,可以单独迭代。某个技能写错了,改那一个文件就行,不会牵动全局。
2.2 技能让 agent 有了"工作流意识"
普通 agent 的工作模式是"你问我答",缺乏流程感。你让它实现一个功能,它可能直接开始写业务代码,测试最后补,边界条件靠你提醒。而带技能的 agent 会先判断:这个任务属于哪一类?该调用哪个技能?技能里规定的第一步是什么?
以 TDD 为例,一个合格的 TDD 技能应该强制 agent 走这样的顺序:先理解需求 → 写一个会失败的测试 → 运行测试确认它确实失败 → 写最小实现让测试通过 → 重构 → 再跑一遍全部测试。这个顺序不是形式主义,它保证了 agent 每一步都有明确的"完成信号",而不是凭感觉说"我觉得写完了"。
2.3 技能是可组合的积木
单个技能解决单类问题,但真实任务往往是复合的。比如"给用户模块加一个导出 CSV 的接口"这件事,同时涉及:接口设计、测试编写、错误处理、文档更新。如果每个环节都有对应技能,agent 就能把它们串起来,形成一个完整的工作流。这种组合能力,是单纯堆提示词做不到的。
我在实际项目里观察到的一个现象:当 agent 有了明确的技能边界后,它"跑偏"的概率明显下降。因为它知道当前处于哪个阶段,下一步该做什么,而不是自由发挥。
3. 一个 agent-skills 仓库通常长什么样
3.1 目录结构背后的设计意图
虽然输入材料没有给出具体结构,但这类项目的组织方式有很强的共性。一个典型的 skills 仓库大致是这样:
agent-skills/ ├── skills/ │ ├── test-driven-development/ │ │ ├── SKILL.md │ │ ├── examples/ │ │ └── scripts/ │ ├── code-review/ │ │ ├── SKILL.md │ │ └── checklist.md │ └── ... ├── cli/ │ └── ... ├── package.json └── README.md每个技能一个目录,目录里最核心的是那个描述文件(这里叫SKILL.md,不同项目可能叫别的名字)。这个文件通常包含几块内容:技能名称和一句话描述、触发条件(什么时候该用这个技能)、执行步骤、校验标准、示例。
为什么要把示例和脚本单独放?因为技能描述文件要保持"可读性",让 agent 快速抓住要点;而具体的代码示例、辅助脚本属于"参考资料",按需加载即可。这种分层设计能有效控制上下文长度——agent 不需要一次性把所有细节都读进来。
3.2 SKILL.md 里到底写什么
我拆过几个类似的技能文件,结构上大同小异。一个写得好的技能描述,通常包含以下要素:
- 元信息:技能名、版本、适用场景的一句话说明。
- 触发条件:明确列出"当用户要求 X 时"或"当检测到 Y 时"启用本技能。这一块非常关键,写得太宽会导致技能被滥用,写得太窄又永远触发不了。
- 前置检查:执行前需要确认的环境、依赖、文件状态。
- 步骤清单:编号的执行步骤,每步都有明确的输入和输出。
- 完成标准:怎么判断这个技能执行成功了。比如 TDD 技能的完成标准是"所有测试通过且新增测试覆盖了新功能"。
- 反例:明确写出"不要这样做"的情况,这往往比正面指导更有效。
提示:技能描述文件最忌讳写成散文。agent 读的是结构化信息,不是文学作品。用列表、用明确的动词开头,比大段叙述有效得多。
3.3 技能之间的依赖关系
有些技能不是孤立的。比如"提交代码"这个技能,可能依赖"运行测试"和"运行 lint"两个前置技能。设计时要把这种依赖显式写出来,否则 agent 可能在测试没跑的情况下就提交了。
我见过一种处理方式:在技能文件里加一个depends_on字段,列出必须先完成的技能。agent 加载技能时,会先检查依赖是否满足。这种显式声明比让 agent 自己"悟"要可靠得多。
4. skills CLI:把技能装进你的工作流
4.1 CLI 解决的核心痛点
手动管理技能目录很麻烦:你得知道技能该放哪、怎么让 agent 发现它、更新时怎么同步。skills CLI 就是把这些操作命令化。常见的子命令大概包括:
| 命令 | 作用 | 典型场景 |
|---|---|---|
skills list | 列出已安装技能 | 查看当前有哪些能力可用 |
skills add <name> | 安装某个技能 | 从仓库拉取技能到本地 |
skills remove <name> | 卸载技能 | 清理不再需要的技能 |
skills update | 更新技能到最新版 | 同步上游改进 |
skills init | 初始化技能目录 | 新项目接入时用 |
这些命令的具体名称和参数,不同实现会有差异,但思路是一致的:让技能的安装、更新、发现变成一条命令的事。
4.2 技能装到哪里,agent 怎么找到它
这是最容易踩坑的地方。技能文件必须放在 agent 能扫描到的路径下。以 Claude Code 这类工具为例,它通常会在项目根目录或用户主目录下寻找特定名称的配置目录。如果技能放错位置,agent 就是"看不见"。
我的建议是:优先放在项目级目录,而不是全局目录。原因很简单,不同项目的技术栈和规范不一样。A 项目用 pytest,B 项目用 jest,你把两套测试技能都塞进全局目录,agent 反而会混乱。项目级技能跟着代码走,团队里每个人 clone 下来就有一致的体验。
具体路径上,常见做法是在项目根目录建一个约定的隐藏目录(比如.agent/skills/或类似名称),然后在 agent 的配置文件里指向它。这一步一定要对着你所用工具的官方文档确认,因为不同版本可能改过默认路径。
4.3 用 CLI 做技能版本管理
技能也是代码,也会迭代。今天写的 TDD 技能可能漏了"测试失败时的处理",明天就得补上。如果团队多人维护,没有版本管理会乱套。
CLI 工具通常会配合一个清单文件(类似package.json或skills.lock),记录每个技能的来源和版本。这样skills update时能精确拉到指定版本,而不是每次都拿最新的(最新版可能引入了不兼容的改动)。这一点和依赖管理是一个道理,别嫌麻烦。
5. 以 TDD 技能为例,拆解一个技能该怎么写
5.1 为什么 TDD 是 agent 技能的"试金石"
在所有候选技能里,测试驱动开发最能检验一个 agent 技能体系是否合格。原因有三:第一,TDD 有严格的步骤顺序,任何一步跳过都会破坏整个流程;第二,它需要 agent 真正运行命令、读取输出、根据结果决策,而不是纯文本生成;第三,它有明确的成功判据——测试从红到绿。
如果 agent 能在 TDD 技能约束下稳定工作,说明这套技能机制是有效的。反过来,如果连 TDD 都跑不顺,那其他更复杂的技能基本也别指望。
5.2 TDD 技能的步骤设计
一个可用的 TDD 技能,步骤应该写得足够具体,具体到 agent 不需要"发挥":
- 确认需求边界:把用户的需求转写成一条可验证的行为描述。比如"用户输入非法邮箱时,注册接口返回 400"。
- 定位测试文件:根据项目约定,找到或创建对应的测试文件。这一步要明确告诉 agent 测试文件放在哪、命名规则是什么。
- 写失败测试:只写测试,不写实现。测试要能表达预期行为。
- 运行测试并确认失败:这一步不能省。很多 agent 会"假设"测试失败了就直接写实现,结果测试其实因为语法错误而失败,根本没测到逻辑。
- 写最小实现:只写让测试通过的最少代码,不要提前优化。
- 运行测试确认通过:看到绿灯才算这一步完成。
- 重构:在测试保护下清理代码。
- 回归:跑一遍全部测试,确认没破坏别的功能。
5.3 让 agent 真正"运行"测试,而不是"想象"结果
这是实操中最关键的一点。agent 必须被明确要求:每一步都要实际执行命令,并把真实输出作为判断依据。我在项目里见过 agent 声称"测试已通过",结果一查根本没运行,它只是根据代码逻辑"推断"应该通过。
解决办法是在技能文件里写死命令,比如"运行npm test -- <测试文件路径>,读取退出码,退出码为 0 才视为通过"。把判断标准绑定到可观测的信号上,而不是 agent 的自我陈述。
注意:如果你的 agent 环境不允许直接执行终端命令,TDD 技能基本无法完整落地。执行能力是这类技能的前提,配置环境时务必先确认这一点。
5.4 一个 TDD 技能描述文件的骨架
# Skill: test-driven-development ## 触发条件 当用户要求实现新功能、修复 bug,且项目已配置测试框架时启用。 ## 前置检查 - 确认测试命令(读取 package.json / pyproject.toml) - 确认测试文件目录约定 ## 步骤 1. 将需求转写为一条可验证的行为描述 2. 创建或定位测试文件 3. 编写失败测试 4. 执行测试,确认失败原因是"功能未实现"而非语法错误 5. 编写最小实现 6. 执行测试,确认通过 7. 重构,保持测试通过 8. 运行全量测试 ## 完成标准 - 新增测试覆盖新行为 - 全量测试通过 - 无跳过的测试 ## 反例 - 不要先写实现再补测试 - 不要在测试未确认失败前写实现 - 不要用 mock 掩盖真实逻辑这个骨架可以直接改成你项目里的版本。重点是步骤要可执行、判据要可观测。
6. 接入不同模型时,技能体系会遇到什么
6.1 模型能力差异对技能执行的影响
热搜词里出现了不少关于接入第三方模型的讨论。这里有个现实问题:技能体系对模型的"指令遵循能力"和"工具调用能力"要求很高。同一个 TDD 技能,在指令遵循强的模型上能一步步走完,在弱一些的模型上可能第三步就开始偷懒——跳过"确认失败"直接写实现。
我的经验是:技能越结构化,对模型能力的依赖越低。因为结构化技能把"该做什么"写死了,模型只需要按部就班执行,不需要自己规划。所以如果你用的是能力一般的模型,反而更应该把技能写得细,而不是指望模型自己聪明。
6.2 工具调用是硬门槛
TDD 技能要求 agent 能执行命令、读文件、写文件。如果接入的模型或客户端不支持工具调用(function calling / tool use),那这套技能就只能"纸上谈兵"。选模型时,工具调用支持是比"代码写得好不好"更前置的指标。
6.3 上下文长度与技能加载策略
技能多了以后,不可能全部塞进上下文。合理的做法是:agent 先读一个技能索引(只有名称和一句话描述),判断当前任务需要哪个技能,再加载那个技能的完整内容。这种"按需加载"策略能显著降低上下文压力,也让 agent 的注意力更集中。
如果你的工具支持,可以在技能索引里加上关键词,让匹配更精准。比如 TDD 技能的关键词是"测试、TDD、红绿重构、单元测试",当用户提到这些词时优先加载。
7. 落地一套 agent-skills 的完整流程
7.1 从最小可用集合开始
不要一上来就写二十个技能。我的建议是先做三个:测试驱动开发、代码审查、提交规范。这三个覆盖了日常开发最高频的场景,也最容易验证效果。跑顺了再扩展。
7.2 每个技能都要有"验收测试"
技能本身也需要测试。怎么测?拿一个真实的小任务,让 agent 在技能约束下完成,观察它是否按步骤走、是否在关键节点做了正确判断。如果它跳步了,说明技能描述有歧义,回去改。
我一般会准备几个"标准任务"作为回归用例:一个需要写测试的功能、一个需要修 bug 的场景、一个需要重构的模块。每次改完技能,用这几个任务跑一遍,看行为是否稳定。
7.3 团队协作中的技能维护
技能是团队资产,不是个人玩具。建议把技能仓库纳入代码评审流程:谁改了技能,要说明改的原因,最好附上改动前后的行为对比。这样能避免技能被随意改坏。
另外,技能描述里涉及项目约定的部分(比如测试目录、命名规范),最好从项目配置文件里读取,而不是硬编码。这样换项目时技能还能复用。
7.4 常见问题排查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| agent 不加载技能 | 路径不对 / 索引未更新 | 检查技能目录位置和索引文件 |
| 技能加载了但不执行 | 触发条件写得太窄 | 放宽触发条件,补充关键词 |
| 执行到一半跳步 | 步骤描述有歧义 | 把步骤拆得更细,加明确判据 |
| 声称完成但实际没做 | 缺少可观测的完成标准 | 绑定到命令退出码或文件状态 |
| 多个技能冲突 | 触发条件重叠 | 明确优先级或合并技能 |
8. 我在实操中踩过的几个坑
第一个坑是技能写得像文档。我一开始把 TDD 技能写成了一篇讲 TDD 原理的文章,结果 agent 读完还是不知道具体该敲什么命令。后来改成"步骤 + 命令 + 判据"的结构,效果立刻不一样。技能是给机器执行的,不是给人阅读的,这个定位要摆正。
第二个坑是忽略了测试框架的差异。同一个 TDD 技能,在 jest 项目和 pytest 项目里,运行命令、断言写法、文件命名都不一样。我最初的技能硬编码了 jest 的命令,换到 Python 项目就废了。后来改成从项目配置里探测测试命令,通用性好了很多。
第三个坑是过度依赖 agent 的自我报告。有次 agent 说"所有测试通过",我信了,结果提交后 CI 挂了。从那以后,我在技能里强制要求 agent 输出真实的命令和输出片段,而不是一句"通过了"。可观测性这东西,在 AI 辅助开发里比在人写代码时更重要。
第四个坑是技能更新没有版本控制。团队里两个人同时改同一个技能,合并时冲突一堆。后来我们约定技能改动走 PR,并且给技能文件加了版本号,才稳定下来。
9. 技能体系还能往哪些方向扩展
跑通基础技能后,可以往几个方向延伸。一是领域技能,比如针对特定框架(React、Django)的最佳实践技能;二是流程技能,比如发布流程、回滚流程;三是质量技能,比如性能检查、安全检查。
还有一个有意思的方向是技能的组合编排。当技能足够多时,可以定义一个"元技能",描述一个完整任务需要哪些技能、按什么顺序执行。这相当于给 agent 装了一个"项目级工作流引擎"。
不过要提醒一句:技能不是越多越好。每多一个技能,agent 的判断负担就多一分。保持精简、保持每个技能职责单一,比堆数量重要得多。我自己维护的技能集合一直控制在十个以内,够用就行。
最后分享一个我常用的检验方法:把技能描述拿给一个不熟悉项目的同事看,如果他看完能照着做出来,说明这个技能写得够清楚;如果他自己都看不懂,agent 大概率也执行不好。技能的可读性,某种程度上就是它的可执行性。