1. 从"agent-skills"说起:一个被低估的工程化命题
第一次看到agent-skills这个词,很多人会下意识地把它理解成"给 AI 智能体写提示词"。这个理解不算错,但太浅了。真正在一线用 AI coding agents 干活的人会告诉你,提示词只是冰山露出水面的那一角,水面之下是一整套可复用、可测试、可版本管理的技能工程体系。agent-skills要解决的,恰恰是"如何把一次性的对话经验,沉淀成团队里每个人都能调用的标准能力"这个问题。
我接触这套东西的起点很朴素:团队里几个人都在用 Claude Code 写代码,每个人都在自己的会话里反复调教同一类任务——写单元测试、重构函数、生成迁移脚本、审查 PR。调教的过程很爽,但结果留不下来。换个人、换个项目、换台机器,一切归零。agent-skills加上配套的 skills CLI,本质上就是给这种"调教成果"找一个正式的存放位置和调用入口,让它从个人手感变成工程资产。
这篇文章适合三类人看。第一类是已经在用 Claude Code、但还停留在"聊天式写代码"阶段的开发者,你会看到怎么把零散经验结构化。第二类是想给团队搭建 AI 编码规范的 Tech Lead,你会看到目录结构、测试驱动、版本管理这些落地细节。第三类是刚听说 AI coding agents、还在纠结要不要上手的新手,前半部分会帮你建立正确的认知框架,不至于一上来就被各种概念绕晕。全文围绕agent-skills这个核心,把设计思路、目录结构、skills CLI 用法、test-driven-development 的落地方式、以及一堆踩坑经验讲透。
2. agent-skills 到底是什么:概念拆解与设计动机
2.1 从"提示词"到"技能"的认知升级
先把概念掰开。在 AI coding agents 的语境里,一个"技能"(skill)不是一句提示词,而是一个自包含的能力单元,通常包含三部分:一段描述这个技能做什么、什么时候该用的元信息;一段指导 agent 如何执行的操作说明;以及可选的辅助资源,比如脚本、模板、参考文档。你可以把它类比成给新员工写的 SOP 手册——不是告诉他"你要努力",而是告诉他"遇到 X 情况,按 1、2、3 步做,注意别踩 Y 这个坑"。
为什么需要这种结构化?因为裸提示词有三个致命问题。第一是不可复用,你在这个会话里调好的提示词,下个会话就找不到了。第二是不可测试,你没法验证"这个提示词是不是真的比那个好",全靠感觉。第三是不可协作,团队里十个人有十套写法,质量参差不齐。agent-skills的设计动机就是把这三点逐个击破:用文件系统解决复用,用 test-driven-development 解决验证,用统一的目录约定解决协作。
这里有个关键判断:技能不是越通用越好。我见过有人试图写一个"万能编程技能",结果它什么都能干一点,什么都干不精。真正好用的技能往往是窄而深的,比如"给 Python 函数补 pytest 测试"、"把回调风格的 JS 重构成 async/await"、"根据 schema 生成数据库迁移文件"。窄意味着触发条件清晰,agent 知道什么时候该调用它;深意味着里面有真正的领域知识,不是泛泛而谈。
2.2 为什么是 Claude Code 这类 agent 先跑通了这个模式
agent-skills这套模式能在 Claude Code 上先跑通,不是偶然。Claude Code 这类工具的核心特征是它能直接读写文件系统、执行终端命令、并且有一个相对稳定的"技能发现"机制——它会去特定目录扫描可用的技能定义。这意味着技能可以像代码一样被 git 管理、被 CI 校验、被 code review。
对比一下纯聊天式的 AI 工具:你在网页对话框里让模型写测试,它写完就完了,你复制粘贴走人,下次还得重新描述需求。而 Claude Code 里,你把"写测试"这件事写成一个 skill 文件放进项目,之后任何人在这个项目里说"给这个模块补测试",agent 就会自动加载这个技能,按你定义的标准来。这个差别是数量级的——前者是消费,后者是投资。
提示:不要把 agent-skills 理解成某个特定产品的专属功能。它是一种工程范式,核心思想是"把 agent 的能力定义外置成可管理的文件"。理解了这一点,你换任何支持类似机制的 agent 工具,迁移成本都很低。
2.3 技能、命令、子代理:别把三个概念搞混
新手最容易混淆的是 skill、command、subagent 这三个东西。我用一个类比说清楚:skill 像是"菜谱",描述怎么做一道菜;command 像是"点菜按钮",你按一下就触发某个流程;subagent 像是"专门负责某道菜的厨师",它有独立的上下文,专门处理某类任务。
在实际项目里,这三者经常配合使用。比如你有一个"代码审查"的 skill,定义审查的标准和输出格式;然后有一个/review的 command,一键触发审查流程;审查过程中如果发现需要深入分析某个复杂模块,可以派一个 subagent 去专门读那部分代码,避免污染主会话的上下文。理解这个分工,你在设计自己的 agent-skills 体系时就不会把所有东西塞进一个文件里。
3. 目录结构与技能组织:让技能像代码一样可管理
3.1 标准目录布局与命名约定
一套能长期维护的 agent-skills 体系,目录结构必须清晰。我实测下来比较稳的布局是这样的:
project-root/ ├── .agent/ │ ├── skills/ │ │ ├── write-pytest-tests/ │ │ │ ├── SKILL.md │ │ │ ├── templates/ │ │ │ └── scripts/ │ │ ├── refactor-to-async/ │ │ │ └── SKILL.md │ │ └── generate-migration/ │ │ ├── SKILL.md │ │ └── reference/ │ ├── commands/ │ │ └── review.md │ └── config.json └── src/每个技能一个独立目录,目录名用动词开头的 kebab-case,比如write-pytest-tests而不是pytest或tests-helper。为什么强调动词开头?因为技能的本质是"做一件事",动词开头能让 agent 在扫描技能列表时更快匹配到用户意图。SKILL.md是技能的主文件,里面包含元信息头(通常用 YAML frontmatter)和正文说明。辅助资源放在同目录的子文件夹里,保持自包含。
命名上还有个细节:避免用过于宽泛的词。我见过有人把技能命名成coding、helper、utils,这种名字对 agent 来说毫无信息量,触发准确率极低。好的命名应该让人一眼看出"这个技能在什么场景下用",比如fix-flaky-test、add-type-hints、split-large-component。
3.2 SKILL.md 的元信息设计:触发条件是灵魂
SKILL.md里最重要的不是正文,而是元信息头。因为 agent 决定"要不要用这个技能",靠的就是元信息里的描述。一个典型的元信息头长这样:
--- name: write-pytest-tests description: 为 Python 函数或类生成 pytest 单元测试,覆盖正常路径、边界条件和异常分支。当用户要求"补测试""写单测""提高覆盖率"时使用。 version: 1.2.0 tags: [python, testing, pytest] ---这里description是灵魂。它要同时回答两个问题:这个技能做什么,以及什么时候该触发。我踩过的坑是早期只写了"生成 pytest 测试",结果 agent 在用户说"这个函数好像有问题"时也会误触发。后来加上触发场景描述"当用户要求补测试、写单测时使用",误触发率明显下降。
version字段别省。技能是会迭代的,没有版本号你根本不知道线上跑的是哪一版。tags用于分类检索,当技能多到几十个时,标签能帮你快速定位。这些字段看起来是小事,但技能库一旦上规模,没有它们就是灾难。
3.3 正文写法:给 agent 看的说明书,不是给人看的文档
SKILL.md的正文和普通技术文档写法完全不同。普通文档是写给人看的,可以省略"显而易见"的步骤;技能正文是写给 agent 看的,必须把每一步都显式化,因为 agent 不会"脑补"你的隐含意图。
我的经验是正文按这个结构组织:先写"适用场景"和"不适用场景",划清边界;再写"执行步骤",用有序列表,每步都是可执行的动作;然后写"输出格式",明确告诉 agent 结果应该长什么样;最后写"注意事项",把容易出错的地方点出来。举个写测试技能的例子,执行步骤会写成"1. 读取目标函数签名和 docstring;2. 识别所有分支和异常抛出点;3. 为每个分支生成一个测试函数;4. 使用 pytest.mark.parametrize 处理多组输入;5. 运行测试确认全部通过"。每一步都是 agent 能直接执行的动作,不含糊。
注意:正文里绝对不要写"根据情况灵活处理"这种话。agent 对模糊指令的处理方式是不可预测的,你以为的"灵活"在它那里可能是"随机"。要么给明确规则,要么给判断标准,别给模糊空间。
4. skills CLI:把技能管理变成命令行操作
4.1 安装与初始化:从零搭起技能库
skills CLI 是管理这套技能体系的命令行入口。它的价值在于把"创建技能、校验技能、列出技能、同步技能"这些操作标准化,避免手动建目录、手写元信息时出错。安装方式通常是通过包管理器,具体命令随工具版本变化,但初始化流程大同小异。
初始化一个技能库,核心动作是init。它会在项目根目录创建.agent/骨架,包括skills/、commands/和一份默认配置。我建议初始化后第一件事是改配置里的技能扫描路径,如果你的项目有 monorepo 结构,可能需要配置多个扫描根目录,否则子包里的技能不会被发现。
初始化完成后,用list命令确认当前技能列表。空库是正常的,接下来就是往里加技能。这里有个实操心得:不要一上来就写十个技能。先写一个你每天都在重复的任务,把它跑通、跑顺,再考虑第二个。技能库的质量远比数量重要,十个半成品技能不如一个打磨到位的。
4.2 创建与校验:new 和 validate 的配合
new命令用于创建一个新技能骨架,它会生成目录和一份带占位符的SKILL.md。我通常的流程是new生成骨架,然后手动填充元信息和正文,最后用validate校验。
validate这个命令值得单独说。它会检查元信息字段是否完整、description 是否足够具体、正文结构是否符合约定、引用的辅助文件是否存在。早期我觉得这步多余,直到有一次技能里的脚本路径写错了,agent 调用时静默失败,排查了半天才发现是路径问题。从那以后我养成了习惯:每次改完技能必跑validate,把它加进 pre-commit hook 里。
校验能抓的问题类型大致有这么几类,我整理成表格方便对照:
| 问题类型 | 典型表现 | validate 是否捕获 |
|---|---|---|
| 元信息缺失 | 没有 description 或 version | 是 |
| description 过泛 | 只写"处理代码" | 部分(会警告) |
| 辅助文件路径错误 | 引用了不存在的脚本 | 是 |
| 正文结构混乱 | 缺少执行步骤 | 部分(会警告) |
| 命名不规范 | 用下划线或大写 | 是 |
4.3 同步与分发:让团队用上同一套技能
技能写好了,怎么让团队里每个人都用上?这就是sync或类似命令的用武之地。它的逻辑通常是把技能库同步到 agent 的全局配置目录,或者从远程仓库拉取最新版本。
我的做法是把技能库作为项目仓库的一部分,跟着代码一起提交。这样有个好处:技能和代码版本绑定,某个技能是针对这个项目特定架构写的,跟着项目走最合理。对于跨项目通用的技能,我会单独维护一个技能仓库,通过 CLI 的远程同步功能分发。两种方式结合,既保证了项目特定技能的一致性,又避免了通用技能在每个项目里重复维护。
提示:技能同步后,agent 不一定立即感知到变化。有些工具需要重启会话或执行一次刷新命令。如果你改了技能但 agent 行为没变,先检查是不是没刷新,别急着怀疑技能写错了。
5. test-driven-development:让技能质量可验证
5.1 为什么技能也需要测试
这是agent-skills体系里最容易被忽视、也最能拉开差距的一环。大多数人写完技能,手动试一次觉得"能用"就完事了。但技能和代码一样会腐化:底层模型升级了、项目结构变了、依赖库换版本了,昨天好用的技能今天可能就失灵。没有测试,你只能等它在实际使用中出问题才发现。
test-driven-development 的思路套用到技能上,就是先定义"这个技能在什么输入下应该产出什么输出",然后构造测试用例去验证。技能的测试和普通代码测试有个关键区别:技能的输出是自然语言或代码片段,不是确定性的返回值,所以断言方式要调整。我们通常不比对完整输出,而是检查关键特征——比如生成的测试文件是否包含特定数量的测试函数、是否覆盖了指定的边界条件、是否用了项目约定的 fixture 命名。
5.2 技能测试的三种粒度
我把技能测试分成三种粒度,从轻到重依次是:结构测试、行为测试、端到端测试。
结构测试最轻,只检查技能文件本身是否合规——元信息完整、正文有执行步骤、引用的文件存在。这类测试跑得飞快,适合放进 pre-commit。
行为测试中等,构造一个典型输入,让 agent 加载技能执行,检查输出是否满足预设特征。这类测试需要真实调用 agent,有成本,通常放在 CI 里按需触发。
端到端测试最重,在真实项目场景里跑完整流程,验证技能和项目其他部分的配合。这类测试我一般只在技能大版本更新时跑,日常不跑,因为太慢。
三种粒度的取舍,本质是测试成本和信心之间的平衡。我的经验是结构测试必做,行为测试覆盖核心技能,端到端测试只覆盖最关键的几个。
5.3 一个可复现的技能测试流程
具体怎么落地?我拿"写 pytest 测试"这个技能举例。首先准备一个 fixtures 目录,里面放几个待测的 Python 文件,每个文件代表一种典型场景:有分支的函数、会抛异常的函数、有边界条件的函数。然后写一个测试脚本,对每个 fixture 调用技能,检查输出。
检查点我通常设这几个:生成的测试文件能否被 pytest 成功收集(语法正确);测试函数数量是否覆盖了所有分支(覆盖率);是否包含至少一个异常路径测试;命名是否符合项目约定。这四个检查点跑通,基本能保证技能在真实场景里不会太离谱。
跑测试的时机也有讲究。我把它挂在两个地方:一是技能文件变更时自动触发,防止改坏;二是底层 agent 版本升级后手动跑一次,因为模型行为变化可能导致技能失效。第二点特别重要,我遇到过模型升级后技能输出格式变了的情况,幸好有测试兜底,不然要等用户反馈才发现。
6. 实操全流程:从零搭一个可用的技能库
6.1 环境准备与前置检查
动手之前,先把环境理清楚。你需要一个能跑 Claude Code 的环境,无论是 VS Code 插件还是终端版本都行。安装方式各平台不同,Mac、Ubuntu、Windows 各有各的步骤,核心是确保 agent 能正常启动并读写项目文件。装完之后,用一个简单任务验证一下,比如让它读一个文件并总结,确认基础能力正常。
然后是 skills CLI 的准备。确认 CLI 能正常执行--version,能访问到项目目录。如果你的项目在远程开发环境里,注意 CLI 的工作目录要和 agent 的工作目录一致,否则技能扫描路径会对不上。这一步看着简单,但我见过不少人卡在这里,agent 找不到技能,排查半天发现是 CLI 在另一个目录跑的。
注意:环境准备阶段不要急着写技能。先用 agent 裸跑几个任务,感受一下它的行为模式,知道它在没有技能时是怎么处理这类任务的。有了这个基线,你才能判断技能到底带来了多少提升。
6.2 第一个技能:从最痛的点切入
选第一个技能的原则是"高频且标准化"。高频保证你很快能验证效果,标准化保证技能容易写清楚。我建议从"生成单元测试"或"代码格式化重构"这类任务入手,因为它们输入输出明确,判断标准清晰。
以生成单元测试为例,创建技能目录,写SKILL.md。元信息里 description 要写清楚触发场景。正文里把执行步骤拆细:读目标文件、识别函数、分析分支、生成测试、运行验证。辅助资源里可以放一个测试模板文件,让 agent 生成时参考项目已有的测试风格。
写完先别急着用,跑一遍validate,再手动触发一次,看输出是否符合预期。第一次大概率不完美,可能是测试命名不对,可能是漏了某个分支。根据实际输出调整正文里的步骤描述,把"识别所有分支"改成更具体的"识别 if/elif/else、try/except、循环边界三类分支"。技能就是在这样一轮轮微调中变好的。
6.3 技能迭代与版本管理
技能上线不是终点。我维护技能库的经验是,每个技能都要有明确的 owner 和变更记录。SKILL.md里的 version 字段每次改动都要递增,配合 git 的 commit message 记录改了什么、为什么改。
迭代的驱动力通常来自两个方向:一是使用中发现的失败案例,agent 在某类输入下表现不好,需要补充规则;二是底层能力变化,模型升级后某些原本需要显式说明的步骤可以简化了。前者是修补,后者是优化,两种都要做,但优先级不同——先保证不坏,再追求更好。
版本管理还有个实际问题:技能更新后,正在进行的会话可能还在用旧版本。我的处理方式是重大更新时通知团队重启会话,小更新则等下个自然会话周期。这个策略不完美,但比强制所有人立刻重启要现实。
7. 常见问题与排查技巧实录
7.1 技能不触发或误触发
这是最高频的问题。技能不触发,先检查三件事:技能目录是否在扫描路径内、元信息 description 是否包含用户可能说的关键词、agent 是否需要刷新才能感知新技能。我遇到过的案例里,八成是 description 写得太抽象,用户说"帮我写个测试",技能描述里只有"生成单元测试代码",关键词对不上。
误触发则相反,通常是 description 太宽泛。解决办法是在 description 里加"不适用场景",比如"当用户只是询问测试概念、不需要生成代码时,不要使用本技能"。给 agent 划清边界,比让它自己判断要可靠得多。
7.2 技能执行结果不稳定
同一个技能,两次执行结果差异很大,这通常不是技能的问题,而是任务本身有歧义。agent 对模糊输入的处理是概率性的,你给它的输入越模糊,输出越飘。解决办法是在技能正文里增加"输入澄清"步骤:如果用户请求缺少关键信息(比如没说测试框架、没说覆盖范围),先追问再执行。
另一个原因是技能依赖的外部资源不稳定,比如引用的脚本在不同环境下行为不同。这类问题要靠测试兜底,把环境差异显式化。
7.3 技能库膨胀后的管理难题
技能写到二三十个之后,管理成本会陡增。这时候需要做两件事:一是定期清理,把长期不用、效果不佳的技能归档或删除;二是建立分类索引,用 tags 把技能分组,方便检索。我还会定期跑一次全量技能的行为测试,把失败的技能挑出来修复或下线。
下面这张表是我整理的常见问题速查,遇到问题先对照排查:
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| 技能完全不触发 | 路径不对/未刷新/描述不匹配 | 检查扫描路径,重启会话,核对关键词 |
| 技能误触发 | 描述过泛 | 补充不适用场景 |
| 输出格式不对 | 正文缺输出格式说明 | 在正文加明确的输出模板 |
| 执行中途失败 | 辅助文件缺失或路径错 | 跑 validate,检查引用 |
| 结果时好时坏 | 输入歧义或环境差异 | 增加澄清步骤,固定环境 |
7.4 团队协作中的技能冲突
多人维护技能库时,冲突不可避免。两个技能可能触发条件重叠,导致 agent 不知道该用哪个。解决办法是建立技能命名和描述的评审机制,新技能上线前检查是否和现有技能冲突。我还会在技能正文里写明"本技能与 X 技能的区别",帮助 agent 做选择。
提示:技能冲突的根源往往是职责划分不清。与其在技能层面打补丁,不如回到源头,重新想清楚每个技能到底负责什么。一个技能只干一件事,冲突自然就少了。
8. 我踩过的坑和几条实在建议
聊了这么多,最后分享几条从实际项目里摔出来的经验。第一条,别追求技能数量。我早期一口气写了十几个技能,结果维护不过来,一半都处于半失修状态。后来砍到五个核心技能,每个都打磨到位,实际使用效果反而更好。技能库的价值在于可靠,不在于多。
第二条,description 值得反复打磨。我现在的习惯是,一个新技能的 description 至少改三遍,第一遍写功能,第二遍加触发场景,第三遍加排除条件。这三遍下来,触发准确率能提升一大截。很多人在这上面偷懒,结果技能写得不差,就是用不起来。
第三条,测试不是负担是保险。技能测试看起来增加了工作量,但它省下的是"技能悄悄失效却没人发现"的隐性成本。我现在的技能库,结构测试全量跑,行为测试覆盖核心,这套组合让我在模型升级时心里有底。
第四条,技能要跟着项目走。项目架构变了,技能也得跟着改。我见过有人把技能写死成针对某个旧目录结构的,项目重构后技能全废。技能正文里尽量用相对路径和抽象描述,把具体路径放到配置里,这样项目结构变化时改动最小。
这套agent-skills的玩法,说到底就是把"个人调教 AI 的手感"变成"团队可复用的工程资产"。过程有点繁琐,但一旦跑通,你会发现团队里每个人用 AI 写代码的质量都上了一个台阶,而且这个台阶是稳定的、可传承的。后续我打算把技能库和 CI 更深度地结合,让技能质量成为代码质量的一部分,这条路还长,但方向是清楚的。