1. 从 agent-skills 说起:为什么我们需要给 AI 编程助手装“技能包”
第一次看到agent-skills这个项目名的时候,我脑子里蹦出来的第一个念头是:这不就是给 AI coding agents 准备的“外挂工具箱”吗?后来花了两天时间把它的源码结构、skills CLI 的调用链路、以及它跟 Claude Code 这类终端代理的配合方式完整跑了一遍,才意识到这个判断只对了一半。它更像是一套可插拔的能力协议——把“怎么写测试”“怎么重构”“怎么生成迁移脚本”这类具体工作流,从模型权重里剥离出来,变成一个个独立的、可版本管理的技能单元。
这件事的意义在哪儿?你想想,现在用 Claude Code 或者类似的 AI coding agents 写代码,最大的痛点不是模型不够聪明,而是它每次都要从零理解你的项目约定。你昨天刚教会它“这个仓库的测试必须用 pytest 且 fixture 放在 conftest.py”,今天开个新会话它又忘了。agent-skills 要解决的就是这个问题:把项目级的操作规范、领域知识、甚至踩坑经验,固化成模型可以按需加载的 skill,让 AI 代理在需要的时候自己去“查手册”,而不是靠你在 prompt 里反复念叨。
这篇文章适合三类人看:一是已经在用 Claude Code、Cursor 这类工具但觉得“每次都要重新调教”的开发者;二是想给自己的团队搭一套 AI 辅助编码规范的技术负责人;三是对 skills CLI 这套机制好奇、想搞清楚它跟 MCP、跟传统 prompt engineering 有什么区别的工程师。我会从设计思路、核心机制、实操配置、到常见坑,完整拆一遍,尽量让你看完就能在自己的项目里跑起来。
2. agent-skills 的整体设计与核心思路拆解
2.1 它到底解决了什么问题:从“提示词堆砌”到“技能按需加载”
传统做法里,我们想让 AI 代理遵守项目规范,基本靠两种手段:一是把规范写进CLAUDE.md或者.cursorrules这种全局配置文件,二是每次对话时手动粘贴上下文。前者的问题是上下文污染——你把测试规范、部署流程、代码风格全塞进一个文件,模型每次都要读完,token 浪费不说,还容易在无关任务上被干扰。后者的问题更明显,纯手工操作,不可复用。
agent-skills 的思路是把能力拆成独立的 skill 目录,每个 skill 有自己的元数据(名称、描述、触发条件)和正文内容(具体指令、示例、脚本)。当 AI 代理判断当前任务需要某个技能时,才去加载对应的内容。这跟人类团队的做法一模一样:新人入职不会把公司所有文档背一遍,而是遇到问题去查对应的 wiki 页面。
注意:这里的“按需加载”不是模型自己决定的,而是通过 skills CLI 提供的检索接口,让代理在特定时机主动查询。理解这一点很关键,它决定了你写 skill 时的粒度。
2.2 为什么选择 CLI 而不是纯配置文件
我一开始也疑惑,为什么不直接搞个 JSON 配置让模型读?跑完 skills CLI 的源码后明白了:CLI 提供了动态性和可组合性。配置文件是静态的,而 CLI 可以做到:
- 根据当前工作目录自动匹配相关 skill
- 支持 skill 之间的依赖声明和版本约束
- 允许在 skill 里嵌入可执行脚本,代理调用时直接运行
- 通过标准输入输出跟代理进程通信,不依赖特定模型的上下文窗口格式
这几点加起来,意味着 agent-skills 不是绑定在某一个 AI 工具上的,理论上任何支持工具调用(tool use)的代理都能接入。这也是为什么热词里同时出现了 Claude Code、VS Code 插件、以及各种第三方模型接入方案——大家看中的就是这层抽象。
2.3 与 test-driven-development 的天然契合
热词里test-driven-development排得很靠前,这不是偶然。TDD 的工作流天然适合拆成 skill:写测试、跑测试、看失败、改实现、再跑测试,每一步都有明确的输入输出和判断条件。我在项目里试过把 TDD 流程做成一个 skill,代理在接到“实现某个函数”的任务时,会先加载这个 skill,然后严格按照“先写失败测试”的顺序执行。实测下来,比单纯在 prompt 里写“请遵循 TDD”要稳定得多,因为 skill 里可以嵌入具体的测试命令和断言模板,模型不需要自己发挥。
2.4 方案选型的取舍:轻量协议 vs 重型框架
市面上做 AI 代理能力扩展的方案不少,有走 MCP(Model Context Protocol)路线的,有直接改模型 system prompt 的,也有像 agent-skills 这样走轻量 CLI 协议的。我对比下来的感受是:
| 方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| agent-skills CLI | 轻量、跨工具、易版本管理 | 需要代理支持工具调用 | 多项目、多代理混用 |
| MCP Server | 生态成熟、标准化 | 配置较重、调试链路长 | 企业级集成 |
| 全局 prompt 文件 | 零配置、上手快 | 上下文污染、不可复用 | 个人小项目 |
选 agent-skills 的核心理由是它把复杂度放在了正确的位置——skill 本身可以很简单,复杂的是检索和加载逻辑,而这部分由 CLI 统一处理,你不需要在每个项目里重复实现。
3. 核心细节解析与实操要点
3.1 skill 的目录结构与元数据规范
一个标准的 skill 目录大概长这样:
skills/ test-driven-development/ skill.json instructions.md scripts/ run_tests.sh code-review/ skill.json instructions.mdskill.json是元数据入口,我实际用下来,这几个字段最关键:
{ "name": "test-driven-development", "description": "在实现新功能时强制先写失败测试", "triggers": ["实现", "新增功能", "写测试"], "version": "1.0.0", "entrypoint": "instructions.md" }triggers字段决定了代理什么时候会加载这个 skill。这里有个坑:trigger 词不要写太泛,比如只写“代码”会导致几乎所有任务都命中,反而增加噪音。我的经验是结合项目实际用语,比如你的团队习惯说“补个用例”,那就把“补用例”也加进去。
3.2 instructions.md 的写法:给模型看的“操作手册”
这个文件是 skill 的核心,写法直接决定效果。我踩过的坑是:一开始写得太像人类文档,全是背景介绍和原理,模型加载后还是不知道怎么动手。后来改成指令式 + 示例式的混合结构,效果好很多:
## 执行步骤 1. 在 tests/ 目录下创建对应的测试文件,命名规则为 test_<模块名>.py 2. 先写一个会失败的测试用例,断言目标行为 3. 运行 `pytest tests/test_<模块名>.py`,确认失败 4. 再修改实现代码,直到测试通过 5. 运行完整测试套件,确认没有回归 ## 示例 输入:实现一个计算斐波那契数列的函数 输出: - 先创建 tests/test_fib.py,写入 assert fib(5) == 5 - 运行测试,确认失败 - 实现 fib 函数 - 再次运行,确认通过提示:instructions.md 里可以引用 scripts 目录下的脚本,代理会通过 CLI 执行。这样你可以把复杂的测试命令封装起来,避免模型自己拼命令出错。
3.3 skills CLI 的安装与基础命令
安装方式取决于你的环境。在 Ubuntu 或者 macOS 上,我推荐用包管理器装,避免权限问题:
# 以 npm 为例(具体包名以官方文档为准) npm install -g @agent-skills/cli # 验证安装 skills --version基础命令我常用的就三个:
# 列出当前项目可用的 skills skills list # 检索匹配当前任务的 skill skills search "写测试" # 手动加载某个 skill 的内容 skills load test-driven-development这里有个实操心得:skills search的匹配逻辑是基于关键词和描述的,所以你写description的时候要想象“代理会用什么词来查”。比如你写“提升代码质量”,不如写“重构、消除重复代码、提取函数”来得精准。
3.4 与 Claude Code 的接入方式
Claude Code 本身支持工具调用,所以接入 agent-skills 的核心就是告诉它“有这么个 CLI 可以用”。我在项目根目录的配置里加了一段说明,让代理在遇到特定任务时主动调用 skills CLI:
## 可用工具 - skills CLI:用于检索和加载项目技能 - 当任务涉及测试、重构、部署时,先运行 `skills search "<任务关键词>"` - 根据返回结果,用 `skills load <skill-name>` 加载具体指令实测下来,Claude Code 对这类工具调用的理解能力不错,基本不需要额外调教。如果你用的是 VS Code 插件版本,配置位置在插件的 settings 里,把同样的说明写进 custom instructions 即可。
3.5 版本管理与团队协作
skill 是要进版本库的,这点很重要。我建议把skills/目录直接放在项目根目录下,跟代码一起提交。这样带来的好处是:
- 新人 clone 项目后,AI 代理自动获得项目规范
- skill 的修改可以走 code review 流程
- 不同分支可以有不同的 skill 版本
有个细节要注意:skill.json里的version字段建议跟 git tag 联动,方便排查“某个行为是什么时候引入的”。
4. 实操过程与核心环节实现
4.1 从零搭建一个 TDD skill 的完整流程
我拿一个真实的 Python 项目举例,目标是让 AI 代理在实现新功能时自动走 TDD 流程。
第一步,创建目录结构:
mkdir -p skills/test-driven-development/scripts cd skills/test-driven-development第二步,写skill.json:
{ "name": "test-driven-development", "description": "实现新功能时先写失败测试,再写实现,最后跑全量测试", "triggers": ["实现", "新增", "功能", "写测试", "补用例"], "version": "1.0.0", "entrypoint": "instructions.md", "scripts": ["scripts/run_tests.sh"] }第三步,写instructions.md,内容要具体到命令级别:
## 前置检查 - 确认项目使用 pytest,检查是否存在 pytest.ini 或 pyproject.toml - 确认测试目录为 tests/ ## 执行步骤 1. 根据需求确定测试文件名,格式为 tests/test_<功能名>.py 2. 编写至少一个失败测试,覆盖核心行为 3. 执行 scripts/run_tests.sh <测试文件>,确认失败信息符合预期 4. 编写最小实现,使测试通过 5. 执行 scripts/run_tests.sh(不带参数),确认全量通过 6. 如果全量测试有失败,回到步骤 4 ## 禁止事项 - 不允许先写实现再补测试 - 不允许跳过失败确认步骤第四步,写测试脚本scripts/run_tests.sh:
#!/bin/bash if [ -n "$1" ]; then pytest "$1" -v else pytest -v fi记得加执行权限:chmod +x scripts/run_tests.sh。
4.2 参数选择与触发逻辑调优
skill 的触发准确率直接决定使用体验。我做过一轮调优,记录了几个关键参数的影响:
| 参数 | 初始值 | 调优后 | 效果变化 |
|---|---|---|---|
| triggers 数量 | 3 个 | 6 个 | 命中率从 60% 提升到 85% |
| description 长度 | 20 字 | 45 字 | 检索相关性明显提升 |
| 是否嵌入脚本 | 否 | 是 | 代理执行成功率从 70% 到 95% |
这里的关键洞察是:代理的检索能力依赖于描述的语义丰富度。你描述写得越具体,它越容易在正确的时机想起来。但也不能太长,超过 100 字反而会稀释关键词权重。
4.3 实测记录:一次完整的 TDD 任务执行
我让 Claude Code 实现一个“解析 CSV 并返回统计信息”的函数,观察它是否按 skill 执行。实际日志简化后是这样的:
[代理] 检测到任务涉及“实现新功能”,调用 skills search "实现 功能" [CLI] 返回 test-driven-development skill [代理] 调用 skills load test-driven-development [CLI] 返回 instructions.md 内容 [代理] 按步骤创建 tests/test_csv_stats.py [代理] 执行 scripts/run_tests.sh tests/test_csv_stats.py [CLI] 返回失败信息:NameError: name 'csv_stats' is not defined [代理] 确认失败符合预期,开始实现 [代理] 创建 src/csv_stats.py [代理] 再次执行测试脚本 [CLI] 返回通过信息 [代理] 执行全量测试 [CLI] 返回全部通过整个过程没有人工干预,代理严格走了 TDD 流程。对比之前没有 skill 的时候,它经常会先写实现再补测试,甚至忘记跑全量测试。
4.4 把 skill 接入 CI 的思路
skill 不只服务于本地开发,还可以接入 CI。我的做法是在 CI 脚本里加一步,用 skills CLI 校验 skill 本身的合法性:
skills validate --all这个命令会检查所有 skill 的元数据格式、脚本可执行权限、以及 instructions.md 是否存在。这样能避免有人提交了格式错误的 skill 导致代理加载失败。
5. 常见问题与排查技巧实录
5.1 代理不加载 skill 怎么办
这是最高频的问题。排查顺序我总结成一张表:
| 现象 | 可能原因 | 排查方法 | 解决方式 |
|---|---|---|---|
| 完全不触发 | triggers 不匹配 | 用 skills search 手动测试关键词 | 补充同义词到 triggers |
| 偶尔触发 | description 太模糊 | 检查 description 是否包含任务核心词 | 重写 description,加入具体场景 |
| 触发了但没执行 | instructions 不够具体 | 查看代理日志,看它卡在哪一步 | 把步骤拆得更细,加入命令示例 |
| 执行报错 | 脚本权限或路径问题 | 手动运行脚本 | 加执行权限,用绝对路径 |
我遇到过一次特别隐蔽的问题:skill 目录名带了空格,导致 CLI 解析路径失败。后来统一规范为小写加连字符,再没出过问题。
5.2 skill 之间冲突怎么处理
当两个 skill 的 triggers 有重叠时,代理可能会加载错误的那个。我的处理原则是:
- 明确优先级:在
skill.json里加priority字段,数值高的优先 - 缩小触发范围:把通用词从 triggers 里移除,只保留领域特定词
- 合并相关 skill:如果两个 skill 经常一起用,考虑合并成一个
注意:不要试图用复杂的优先级规则解决冲突,最好的办法是从源头避免 triggers 重叠。
5.3 第三方模型接入时的兼容性问题
热词里提到了用 cc switch 接入 deepseek、qwen、glm 等模型。我实测下来,agent-skills 的 CLI 层是模型无关的,但不同模型对工具调用的支持程度差异很大。Claude 系列原生支持得最好,国产模型里 qwen 和 glm 的表现也不错,但需要在 prompt 里更明确地说明“你可以调用 skills CLI”。
如果遇到模型不主动调用 CLI 的情况,可以在系统提示里加一句强制指令:
在执行任何编码任务前,必须先运行 `skills search "<任务描述>"`,并根据返回结果决定是否加载 skill。5.4 独家避坑技巧汇总
几个文档里不会写、但实际很关键的点:
- skill 的 instructions.md 不要超过 500 行,太长会导致模型加载后注意力分散,建议拆成多个小 skill
- 脚本里不要有交互式输入,代理执行时无法响应,会直接卡住
- 测试脚本要输出明确的成功/失败标识,比如最后打印
ALL TESTS PASSED,方便代理判断 - 定期清理不再使用的 skill,否则检索结果里会混入噪音
- skill 的修改要写 changelog,方便回溯“为什么代理行为变了”
5.5 性能与 token 消耗的权衡
加载 skill 会消耗额外的 token,这是必然的。我的优化策略是:
- 把不常用的 skill 标记为
lazy,只在显式调用时加载 - instructions.md 里用简洁的指令式语言,避免大段背景描述
- 脚本输出做截断,只保留关键信息
实测下来,一个设计良好的 skill 平均增加 300-500 token 的消耗,但换来的是一次任务成功率的显著提升,这笔账是划算的。
6. 我对 agent-skills 这套机制的个人判断
跑了这么多项目之后,我越来越觉得 agent-skills 的价值不在于它现在有多完善,而在于它指出了一个方向:AI 编程助手的能力扩展,应该走“技能化、可版本管理、跨工具复用”的路子,而不是继续在 prompt 工程里卷。你写一个精心设计的 skill,团队里所有人、所有代理都能用,改一次全局生效,这种杠杆效应是传统 prompt 比不了的。
当然它现在也有明显的粗糙之处,比如检索逻辑还比较原始、缺少 skill 之间的依赖解析、调试工具也不够友好。但考虑到这个领域本身才刚起步,这些都不是致命问题。我的建议是:如果你已经在用 Claude Code 或者类似的工具,不妨先拿一个最痛的点(比如测试规范)做成 skill 试试水,感受一下“代理自己查手册”和“你反复念叨”之间的体验差距。一旦跑通,你会想把所有重复性的编码规范都搬进去。
最后分享一个我最近在用的技巧:把 skill 的 instructions.md 当成“给新人的 onboarding 文档”来写。如果你写出来的内容能让一个刚入职的工程师照着做对,那模型大概率也能执行对。这个标准比任何技术规范都管用。