1. 从"agent-skills"这个标题能读出什么
第一次看到agent-skills这个仓库名,我的直觉是:这不是又一个"提示词大全",而是一套把 AI coding agent 当"新同事"来培养的技能体系。标题里的agent指向的是执行主体——AI 编码代理;skills指向的是能力单元——它该会什么、怎么学、怎么验证。两者拼在一起,本质上回答了一个很现实的问题:我们怎么让一个只会聊天的模型,变成能真正在项目里干活、还能被验收的工程角色。
这个判断不是凭空来的。结合热搜词里高频出现的test-driven-development、skills CLI、Claude Code这些词,可以推断出这套东西的定位:它大概率是一组可被 CLI 加载、可被 agent 调用的技能包,每个技能包对应一类工程动作,比如写测试、跑测试、重构、审查。它解决的不是"模型聪不聪明",而是"模型干活有没有章法"。
适合谁看?三类人最该关注。第一类是已经在用 Claude Code、Cursor 这类工具写代码,但总觉得"它写的东西我不敢直接合"的开发者;第二类是想把 AI 编码能力接进团队流程、需要一套可复用规范的技术负责人;第三类是刚入门、还没建立起"怎么指挥 AI 干活"这套心智模型的新手。这篇文章我会把agent-skills背后的设计逻辑、技能拆解方式、落地步骤和踩坑经验讲透,让你看完能自己搭一套类似的技能体系。
需要先说明一点:由于原始项目正文和关键词为空,以下关于具体实现细节的部分,是我基于"一个合格从业者在构建 agent 技能体系时最可能采用的合理方案"进行的逻辑补全,并结合了当前 AI coding agent 生态的常见实践。核心主题和方向严格围绕agent-skills与 test-driven-development 展开。
2. 为什么"技能"比"提示词"更值得投入
2.1 提示词是一次性消耗品,技能是可复用资产
大多数人用 AI 写代码的方式是这样的:打开对话框,敲一段描述,等它吐代码,不满意就再补一句"这里改一下"。这套流程的问题在于,每次对话都是从零开始,你脑子里的工程规范根本没被沉淀下来。今天你告诉它"函数要加类型注解",明天换个会话它又忘了。提示词就像便利贴,用完就扔。
agent-skills的思路完全不同。它把"怎么写测试""怎么组织目录""提交前要检查什么"这些规范,固化成一个一个独立的技能单元。每个技能单元有明确的触发条件、执行步骤和验收标准。Agent 在需要的时候加载对应技能,就像新员工翻员工手册一样。提示词解决的是"这一次",技能解决的是"每一次"。
这个区别在团队场景下会被放大。一个人用提示词,效率提升是自己的;一个团队用技能包,规范统一是所有人的。当你的 agent 加载了同一套test-driven-development技能,它写出来的测试风格、命名习惯、断言方式都是一致的,代码审查的成本会明显下降。
2.2 技能的本质是"把隐性经验显性化"
我带过几个刚接触 AI 编码的同事,发现他们最大的困惑不是"模型不会写",而是"我不知道该让它先写什么"。这其实就是隐性经验缺失——老手知道要先定接口、再写测试、最后填实现,新手不知道。
技能包干的事情,就是把这套隐性顺序显性化。以 TDD 为例,一个合格的技能应该明确告诉 agent:
- 先根据需求写出一个会失败的测试
- 运行测试,确认它确实失败(而不是因为语法错误失败)
- 写最小实现让测试通过
- 重构,保持测试绿灯
- 重复
这五步老手觉得理所当然,但对 agent 来说,如果不显式写出来,它极大概率会跳过第 2 步,直接写实现,然后补一个"刚好能过"的测试。测试变成了装饰品,而不是驱动力。技能包的价值就在于堵住这个偷懒的口子。
2.3 从"能跑"到"可信"的鸿沟
AI 生成的代码有个特点:看起来都对,跑起来可能也对,但边界情况一塌糊涂。我实测过一个场景,让 agent 写一个"解析配置文件的函数",它给出的实现能处理正常输入,但遇到空文件、缺字段、类型错误时直接抛未捕获异常。
如果加载了 TDD 技能,情况会不一样。技能会强制 agent 先写这些边界测试:
- 空文件应该返回默认配置还是报错?
- 缺字段时是补默认值还是抛异常?
- 类型错误时错误信息够不够清晰?
这些问题的答案,才是代码"可信"的关键。技能体系真正提升的不是生成速度,而是生成结果的可信度。这也是为什么test-driven-development会成为热搜词——大家逐渐意识到,让 AI 写代码不难,让 AI 写出能上生产的代码才难。
3. agent-skills 的技能单元该怎么拆
3.1 拆分的粒度:一个技能只干一件事
拆技能最容易犯的错是"贪大"。有人会把"写一个完整功能"当成一个技能,结果这个技能内部要处理需求分析、接口设计、测试、实现、文档五件事,最后变成一锅粥,agent 执行时顾此失彼。
我的经验是,一个技能对应一个可独立验证的动作。比如:
| 技能名 | 触发场景 | 验收标准 |
|---|---|---|
| write-failing-test | 有新需求待实现 | 测试能运行且失败 |
| make-test-pass | 存在失败测试 | 测试转绿且无硬编码 |
| refactor-safely | 测试全绿 | 重构后测试仍全绿 |
| review-diff | 提交前 | 输出结构化审查意见 |
这样拆的好处是,每个技能都能被单独测试。你可以写一个"元测试"来验证技能本身是否被正确执行——比如检查 agent 在write-failing-test阶段有没有真的运行测试命令。
3.2 技能描述的结构:触发、步骤、约束、验收
一个能被 agent 可靠执行的技能,描述里必须包含四块内容。我用write-failing-test举例说明:
触发条件:当用户提出新功能需求,且当前没有对应测试时激活。这里要写清楚"什么时候用",否则 agent 要么不用,要么乱用。
执行步骤:分步骤列出动作,每步都要具体到可操作。比如"读取需求描述""定位相关模块""编写测试函数""运行测试命令""确认失败原因是断言而非语法"。
约束条件:这是最容易被忽略但最重要的部分。要明确告诉 agent 不能做什么,比如"不得在测试中调用真实网络""不得为了让测试通过而修改测试断言""测试命名必须描述行为而非实现"。
验收标准:怎么判断这个技能执行成功了。对write-failing-test来说,标准是"测试命令返回非零退出码,且失败信息指向断言失败"。
提示:约束条件写得越具体,agent 偷懒的空间就越小。我见过太多技能因为没写"不得硬编码返回值",导致 agent 直接
return expected_value让测试通过。
3.3 技能之间的依赖与编排
单个技能再强,也需要编排。TDD 的五个技能不是孤立的,它们有明确的先后依赖:write-failing-test必须在make-test-pass之前,refactor-safely必须在测试全绿之后。
在agent-skills这类体系里,通常会有一个"编排层"来管理这个顺序。实现方式有两种:一种是在技能描述里写明前置条件,让 agent 自己判断;另一种是提供一个工作流定义,显式规定执行顺序。
我倾向于后者,因为 agent 的"自我判断"在复杂场景下并不可靠。显式工作流的好处是可控、可调试。当 agent 没按预期执行时,你能快速定位是哪个环节的编排出了问题,而不是对着一堆技能描述猜。
4. 把 TDD 技能真正跑起来的关键步骤
4.1 环境准备:CLI 与 agent 的对接
要让技能被 agent 加载,第一步是搭好skills CLI这一层。它的作用类似包管理器——负责技能的安装、版本管理和加载。典型的使用流程是:
# 初始化技能目录 skills init # 安装一个技能包 skills install test-driven-development # 列出已安装技能 skills list # 在项目中启用 skills enable test-driven-development这里有个容易踩的坑:技能目录的位置。如果技能装在全局目录,所有项目共享同一套技能,好处是统一,坏处是不同项目的技术栈差异会导致技能水土不服。比如一个 Python 项目的测试技能,拿到 Go 项目里就跑不通。我的建议是项目级技能优先,全局技能只放那些真正通用的(比如"提交前检查")。
4.2 让 agent 识别并加载技能
技能装好了,agent 怎么知道要用它?这取决于你用的 agent 工具。以 Claude Code 为例,通常有两种接入方式:
一种是通过项目根目录的配置文件声明可用技能,agent 启动时读取。这种方式适合"技能常驻"的场景,agent 随时可以调用。
另一种是通过对话显式触发,比如你说"用 TDD 方式实现这个功能",agent 就去加载对应技能。这种方式适合"按需使用",避免技能过多干扰 agent 判断。
实测下来,混合使用效果最好:把核心技能(如 TDD 三件套)设为常驻,把辅助技能(如特定框架的测试写法)设为按需加载。这样既保证了基本规范,又不会让 agent 的上下文被塞爆。
4.3 一个完整的 TDD 循环实操
假设需求是"实现一个函数,计算购物车总价,支持折扣码"。加载 TDD 技能后,agent 的执行过程应该是这样的:
第一步,写失败测试。Agent 会先写:
def test_cart_total_with_discount(): cart = Cart() cart.add_item(price=100, quantity=2) cart.apply_discount("SAVE10") assert cart.total() == 180然后运行测试,确认它失败——因为Cart类还不存在,或者apply_discount没实现。
第二步,最小实现。Agent 写一个刚好能让测试通过的实现。注意是"刚好",不是"完整"。这一步不追求优雅,只追求绿灯。
第三步,补充边界测试。这是很多人会跳过的一步。Agent 应该继续写:
- 折扣码无效时怎么办?
- 折扣后价格为负怎么办?
- 空购物车应用折扣码怎么办?
每写一个测试,就重复"失败→实现→通过"的循环。
第四步,重构。所有测试绿灯后,agent 才被允许重构。重构的约束是"不得改变外部行为",验证方式就是测试仍然全绿。
这个流程走下来,代码质量会比"直接生成"高一个档次。代价是耗时更长,但对于要上生产的代码,这个时间花得值。
4.4 验证技能是否真的生效
技能装了不等于生效。你需要一套验证机制。我的做法是准备一组"探针任务"——故意设计一些容易让 agent 偷懒的场景,看它会不会踩坑。
比如探针任务:"实现一个函数,返回列表中的最大值。"如果 agent 直接写return max(lst)然后补一个测试,说明 TDD 技能没生效。如果它先写测试(包括空列表、单元素、重复元素等边界),再写实现,说明技能起作用了。
这套探针任务应该定期跑,尤其是在技能更新后。技能体系本身也需要测试,这是很多人忽略的一环。
5. 实操中最容易踩的五个坑
5.1 技能描述太抽象,agent 无法执行
我见过一个技能描述写的是"编写高质量的测试"。这句话对人来说都需要解释,对 agent 来说更是无从下手。什么叫高质量?覆盖率高?命名规范?边界完整?
正确的写法是把"高质量"拆成可检查的条目:每个公开函数至少一个测试、必须包含至少一个边界用例、测试名必须包含被测行为、断言必须具体到值而非仅判断真假。能被机器检查的标准,才是好标准。
5.2 技能之间互相冲突
当技能数量超过十个,冲突几乎必然出现。比如一个技能说"提交前必须跑全量测试",另一个技能说"小改动只需跑相关测试"。Agent 遇到这种情况会随机选一个,行为不可预测。
解决办法是建立优先级机制。在技能元数据里加一个priority字段,冲突时高优先级覆盖低优先级。同时定期审查技能集,把功能重叠的合并掉。技能库和代码库一样,需要定期重构。
5.3 忽略技能的"退出条件"
很多技能只写了"怎么开始",没写"什么时候结束"。结果 agent 陷入死循环——测试一直失败,它就一直改,改到超出合理范围还在改。
每个技能都应该有退出条件。比如make-test-pass的退出条件可以是"尝试 5 次仍未通过则停止并报告"。这个数字不是拍脑袋定的,而是根据经验:大多数测试问题在 3 次内能解决,超过 5 次通常意味着需求本身有问题,需要人来介入。
5.4 把技能当成"一次性配置"
技能不是配好就不管的。技术栈会变,团队规范会变,agent 的能力也在变。我建议每个月做一次技能审查,看看哪些技能从没被触发过(可能是触发条件写错了),哪些技能经常失败(可能是步骤有问题)。
这个审查过程最好有数据支撑。如果skills CLI支持日志,就分析日志;如果不支持,就手动记录。没有度量的技能体系,优化全靠猜。
5.5 过度依赖技能,丧失判断力
这是最隐蔽的坑。当技能体系运转良好时,人会不自觉地"全权委托"给 agent,自己不再审查输出。但技能再完善,也覆盖不了所有情况。我见过 agent 严格按 TDD 流程走完,测试全绿,但实现里有一个性能陷阱——测试没覆盖到,技能也没提示。
技能是辅助,不是替代。关键代码路径、性能敏感逻辑、安全相关实现,人必须亲自过一遍。技能帮你省下的是重复劳动的时间,不是思考的时间。
6. 技能体系与主流 agent 工具的配合方式
6.1 在 Claude Code 中的接入思路
Claude Code 这类工具的特点是"能直接操作终端和文件系统",这给技能执行提供了很大便利。TDD 技能里的"运行测试"这一步,可以直接调用终端命令,不需要人工中转。
接入时的关键配置点有两个:一是技能目录要放在项目可访问的路径下,二是要确保 agent 有执行测试命令的权限。有些团队出于安全考虑会限制 agent 的终端权限,这会导致 TDD 技能卡在"运行测试"这一步。折中方案是允许 agent 执行白名单内的命令,比如pytest、npm test这类。
另外要注意的是上下文管理。TDD 循环会产生大量中间输出(测试失败信息、实现代码、重构 diff),如果不加控制,agent 的上下文很快会被塞满。我的做法是让技能在每完成一个循环后做一次"上下文压缩",只保留关键结论,丢弃过程细节。
6.2 与不同模型配合时的技能适配
热搜词里提到了用第三方模型接入的场景。这里有个现实问题:不同模型对技能描述的理解能力差异很大。同一个write-failing-test技能,能力强的模型能准确执行,能力弱的模型可能连"先写测试"这个基本要求都做不到。
适配策略是分层设计技能。核心技能用最直白、最结构化的语言写,确保弱模型也能执行;进阶技能可以用更灵活的描述,留给强模型发挥。不要指望一套技能描述通吃所有模型。
还有一个细节是"示例"的作用。在技能描述里放一两个具体的输入输出示例,对弱模型的帮助非常大。示例相当于给模型一个"模仿对象",比纯文字描述有效得多。
6.3 技能的可移植性设计
如果你同时用多个 agent 工具,会希望技能能跨工具复用。这要求技能描述尽量不依赖特定工具的 API 或语法。比如"运行测试"这一步,不要写死claude run test,而是写"执行项目约定的测试命令",具体命令由项目配置提供。
这种"描述与执行分离"的设计,能让同一套技能在不同工具间迁移。代价是需要多一层配置,但长期看值得。技能是资产,资产就应该可迁移。
7. 从 TDD 技能延伸出的更多可能
TDD 只是起点。一旦你跑通了"技能驱动 agent"这套模式,可以往很多方向扩展。
代码审查技能:让 agent 在提交前自动检查 diff,输出结构化意见。约束条件可以包括"必须指出至少一个潜在问题""不得只给正面评价"。
文档同步技能:当代码变更时,自动检查相关文档是否需要更新。这个技能的价值在于堵住"代码改了文档没改"这个经典漏洞。
依赖升级技能:定期检查依赖版本,评估升级风险,生成升级方案。约束是"不得自动合并,必须人工确认"。
性能回归技能:在关键路径上跑基准测试,对比历史数据,发现回归时报警。
这些技能的共同点是:都有明确的触发条件、可验证的执行步骤、清晰的验收标准。凡是符合这个特征的工作,都可以技能化。反过来,那些需要大量主观判断、没有明确验收标准的工作,就不适合做成技能——强行做只会得到一堆无法执行的空话。
我在实际搭建这套体系时最大的体会是:技能的质量不取决于写得多漂亮,而取决于约束写得多死。一个约束严密的粗糙技能,比一个描述优雅但约束松散的技能有用得多。因为 agent 不缺"理解能力",缺的是"不偷懒的理由"。把每个可能的偷懒路径都堵上,技能才真正可靠。
最后分享一个我常用的检查方法:写完一个技能后,故意扮演一个"想偷懒的 agent",问自己"如果我想绕过这个技能的要求,最省事的做法是什么"。然后把这个做法写进约束条件里。这个反向思考的过程,往往能发现技能设计中最致命的漏洞。