ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

agent-skills实战:用TDD和skills CLI工程化AI coding agent

agent-skills实战:用TDD和skills CLI工程化AI coding agent 1. 从agent-skills这个仓库名说起它到底在解决什么问题第一次看到agent-skills这个仓库名很多人会以为是某个AI代理的技能库合集点进去发现它其实是一套围绕AI coding agents的能力组织方案。核心思路很直接把让AI写代码这件事从随口一问变成有章法的工程流程。它不是一个独立运行的框架更像是一份约定——约定好技能怎么定义、怎么被调用、怎么和测试驱动开发TDD串起来。我最初接触这类东西是因为一个很现实的痛点用 Claude Code 或者类似的 AI coding agent 写代码单次对话质量还行但一旦涉及多步骤任务比如给这个模块加个功能顺便补测试再重构一下agent 就容易跑偏。要么忘了写测试要么改完不验证要么把不相关的文件也动了。agent-skills这类方案的价值就在于它把一个完整任务拆成可复用的技能单元每个技能有明确的输入、输出和验证标准。关键词里出现的skills CLI、test-driven-development就是这套思路的两个支柱。skills CLI 负责技能的注册、发现和调用TDD 则是保证 agent 产出质量的硬约束。说白了它想让 AI coding agent 像一个有纪律的工程师那样干活而不是一个想到哪写到哪的实习生。这篇文章适合谁看如果你已经在用 Claude Code、Cursor、或者任何支持 agent 模式的编码工具但总觉得能用但不好用那这套东西值得研究。如果你还没入门只是想搞清楚 AI coding agent 的工程化到底长什么样也能从里面拿到可复用的思路。下面我会从技能定义、CLI 机制、TDD 集成、实际踩坑几个角度拆开讲。2. 技能Skill的抽象方式为什么不是简单的 prompt 模板2.1 技能和 prompt 的本质区别很多人第一反应是技能不就是一段写好的 prompt 吗。我一开始也这么想实际用下来发现差别很大。普通 prompt 是一次性的你写一段话让模型干活干完就完了。技能是可组合、可验证、可复用的单元它至少包含四个部分触发条件什么情况下该用这个技能比如当需要新增一个 API 端点时执行步骤具体做什么按什么顺序验证标准怎么判断做完了、做对了依赖关系这个技能依赖哪些前置技能或工具这个结构看起来简单但它解决了一个关键问题agent 的上下文管理。当你把任务拆成技能后agent 不需要一次性把所有信息塞进上下文而是按需加载当前技能相关的指令。实测下来这能显著降低长任务中前面说的后面忘了的概率。2.2 技能目录的组织约定agent-skills这类仓库通常有一个约定俗成的目录结构。虽然具体实现各家不同但核心逻辑一致每个技能一个目录目录里有描述文件、执行脚本、测试用例。我见过比较合理的组织方式是这样的skills/ add-api-endpoint/ SKILL.md # 技能描述、触发条件、步骤 validate.sh # 验证脚本 examples/ # 示例输入输出 write-unit-test/ SKILL.md templates/SKILL.md是核心它用自然语言加结构化字段描述这个技能。为什么用 Markdown 而不是 JSON因为 agent 本身是语言模型Markdown 对模型更友好同时人也能直接读。这个选择背后有个实用考量技能文件既要给机器看也要给人维护纯结构化格式反而增加维护成本。2.3 技能粒度怎么把握这是最容易踩坑的地方。技能太粗比如实现一个功能那和直接下指令没区别技能太细比如创建一个文件那 agent 光在技能之间跳转就耗尽了上下文。我的经验是一个技能的粒度应该对应一个可独立验证的交付物。比如新增一个带测试的 API 端点就是一个合理粒度因为它有明确的完成标志端点能响应、测试能通过。而设计数据库 schema可能太粗因为它没有即时可验证的产出写一行 SQL又太细。提示判断粒度是否合适可以问自己——这个技能完成后我能不能用一条命令验证它如果不能说明粒度可能不对。3. skills CLI 的工作机制注册、发现与调用链路3.1 CLI 存在的意义有人会问技能文件放在那agent 直接读不就行了为什么还要一个 CLI这个问题问到点子上了。CLI 的价值在于标准化和可编程。没有 CLI 的时候每个项目对技能的组织方式都不一样agent 每次都要重新理解这个项目的技能放哪、怎么调用。有了 CLI就有一套统一的命令skills list列出当前可用的所有技能skills show name查看某个技能的详细定义skills run name执行某个技能skills validate验证技能定义是否合规这套命令的意义不只是方便人用更重要的是 agent 可以通过调用 CLI 来发现自己有哪些能力。这比让 agent 去扫描文件系统要可靠得多因为 CLI 可以返回结构化的技能元数据。3.2 技能发现与上下文注入实际运行时agent 拿到一个任务后第一步是匹配技能。这个过程通常是agent 读取任务描述调用skills list拿到技能清单然后根据技能描述判断该用哪个。匹配上之后CLI 会把该技能的完整定义注入到 agent 的上下文里。这里有个细节值得注意技能描述的质量直接决定匹配准确率。如果技能描述写得含糊比如处理数据相关任务agent 就很难判断该不该用。好的描述应该包含具体的触发词和场景比如当需要解析 CSV 文件并做列级校验时使用。3.3 技能执行的隔离性我在实践中发现一个容易被忽略的点技能执行应该是隔离的。什么意思就是技能 A 的执行不应该污染技能 B 的环境。比如技能 A 创建了临时文件技能 B 不应该看到这些文件。这要求 CLI 在执行技能时做好工作目录管理。具体做法通常是给每个技能执行分配独立的临时目录执行完清理。这个设计看起来是小事但在多技能串联的任务里能避免很多莫名其妙的失败。我踩过一次坑两个技能都往同一个临时文件写数据结果后执行的技能读到了前一个技能的残留数据排查了半天才发现是隔离没做好。3.4 技能版本管理技能是会迭代的。今天写的新增 API 端点技能明天可能因为项目规范变了需要调整。如果没有版本管理agent 可能用到过时的技能定义。合理的做法是给技能加版本号CLI 在调用时记录用了哪个版本方便回溯。这个点在小团队里容易被忽视但一旦技能数量上去了没有版本管理就是灾难。我建议从第一天就给技能加版本哪怕只是简单的日期标记。4. 把 TDD 焊进 agent 工作流测试先行的工程化落地4.1 为什么 AI coding agent 特别需要 TDD人类工程师不写测试代码可能还能跑因为人有直觉和经验兜底。AI coding agent 不写测试产出质量就完全靠运气。原因很简单agent 没有运行代码看结果的直觉它只能根据模式生成代码。没有测试作为反馈信号agent 根本不知道自己写对没有。TDD 在这里的作用不是最佳实践这么虚而是给 agent 提供可执行的验证信号。红-绿-重构的循环本质上是一个反馈闭环先写一个会失败的测试红然后写代码让它通过绿最后优化重构。对 agent 来说每一步都有明确的成功标准。4.2 技能如何与 TDD 循环绑定在agent-skills的思路里TDD 不是一个独立技能而是嵌入到其他技能里的约束。比如新增 API 端点这个技能它的执行步骤会强制包含先写测试用例覆盖正常路径和边界情况运行测试确认失败红实现端点逻辑运行测试确认通过绿检查是否有可重构的地方这个顺序不能乱。我试过让 agent 先写实现再补测试结果它写的测试往往是为了通过而写覆盖不到真正的边界。先写测试agent 会被迫先想清楚这个功能应该表现成什么样实现反而更聚焦。4.3 测试作为技能的验证标准前面说技能要有验证标准TDD 天然提供了这个标准。一个技能的完成定义可以直接绑定到相关测试全部通过。这比让 agent 自己判断我觉得做完了要可靠得多。具体实现上技能的validate.sh通常就是跑测试命令根据退出码判断成败。这个设计的好处是可自动化CI 里可以跑本地可以跑agent 自己也可以跑。三方用同一套标准不会出现agent 说做完了但实际没做完的情况。4.4 测试覆盖率的现实取舍追求 100% 覆盖率在 AI agent 场景下不现实也没必要。我的做法是给技能定义最低覆盖要求比如新增功能必须有正常路径测试加至少两个边界测试。这个要求写进技能定义里agent 执行时会遵守。注意不要指望 agent 自己判断测试够不够。必须把要求量化写进技能否则它会用最少的测试糊弄过去。5. 实际跑起来从零搭建一套可用的技能工作流5.1 环境准备与 CLI 安装假设你已经有一个支持 agent 模式的编码环境Claude Code、Cursor 或其他接下来是搭技能工作流。第一步是拿到 skills CLI。这类工具通常通过包管理器分发安装后需要初始化一个技能目录。初始化的核心是生成一个技能清单文件告诉 CLI 技能放在哪、有哪些技能。这个文件是整套工作流的入口agent 启动时会读它。我建议初始化后先手动加一两个简单技能跑通流程再批量迁移。5.2 写第一个技能从最小可用开始第一个技能不要选复杂的。我推荐从写单元测试这种边界清晰的技能开始。它的输入是一个待测试的函数或模块输出是一组测试用例验证标准是测试能运行且覆盖指定场景。写技能定义时把步骤拆到 agent 能直接执行的程度。比如不要写分析代码逻辑而要写读取目标文件识别所有公开函数为每个函数生成至少一个正常路径测试。越具体agent 执行越稳定。5.3 技能串联多步骤任务的编排单个技能跑通后下一步是串联。比如一个完整功能开发可能涉及写测试 → 实现 → 重构 → 更新文档四个技能。串联方式有两种一种是 agent 自己根据任务判断调用顺序另一种是在技能定义里显式声明依赖。我倾向于显式声明因为 agent 自己判断顺序时容易漏步骤。显式声明的方式是在技能里加depends_on字段CLI 执行时会自动按依赖顺序调度。这样即使 agent 想跳步CLI 也会拦住。5.4 调试技能执行失败技能执行失败是常态关键是怎么快速定位。我的排查顺序是现象可能原因排查方法技能没被匹配到描述触发词不清晰检查 SKILL.md 的触发条件执行到一半停了步骤描述有歧义看 agent 日志找它卡在哪步验证不通过测试标准太严或实现有误手动跑 validate 脚本看具体报错技能间数据传递失败隔离目录配置问题检查临时目录是否被正确清理这个表是我踩坑总结出来的大部分失败都能归到这几类。其中步骤描述有歧义最常见解决办法是把模糊动词换成具体操作。6. 踩过的坑与反直觉经验6.1 技能不是越多越好刚开始我热情很高恨不得把每个操作都做成技能。结果 agent 在技能匹配上花的时间比干活还多而且经常匹配错。后来砍到只保留高频、边界清晰的技能效率反而上去了。经验是技能数量控制在 10-20 个以内超过这个数就要考虑合并或分层。6.2 别让 agent 自己写技能我试过让 agent 根据现有代码自动生成技能定义结果生成的技能要么太泛要么把实现细节写死换个项目就不能用。技能定义还是得人来写因为只有人知道什么算完成哪些边界重要。agent 可以辅助填充模板但核心逻辑必须人定。6.3 测试先行不等于测试万能TDD 能保证 agent 产出符合测试预期但测试本身的质量取决于写测试的人或 agent。如果测试写得太浅agent 实现也会跟着浅。我现在的做法是关键技能的测试用例由人先写一版作为模板agent 在此基础上扩展。这样既保证质量下限又保留自动化效率。6.4 上下文窗口是硬约束不管技能设计得多好agent 的上下文窗口是有限的。技能串联太多前面的上下文会被挤掉。解决办法是让每个技能尽量自包含减少对前序技能的隐式依赖。需要传递的数据通过文件或 CLI 参数显式传递而不是靠上下文记忆。7. 技能库的长期维护与团队协作7.1 技能评审机制技能一旦被 agent 使用它的质量就影响所有依赖它的任务。所以技能变更应该像代码一样走评审。我们团队的做法是技能定义改动需要至少一人 review重点看触发条件是否还准确、验证标准是否还成立。这个机制听起来重但实际跑下来成本不高因为技能改动频率远低于代码。关键是养成习惯别让技能变成没人管的野文件。7.2 技能文档与新人上手新成员加入时技能库是最好的切入点。它把这个项目怎么做开发从口口相传变成了可读的文档。我通常会带新人先读几个核心技能的定义然后让他跑一遍技能执行观察 agent 的行为。这比直接看代码库上手快得多。7.3 技能与项目规范的同步项目规范变了技能要跟着变。比如代码风格从 2 空格缩进改成 4 空格相关技能的验证脚本就得更新。我建议把技能更新纳入项目规范变更的 checklist避免遗漏。遗漏的后果是 agent 持续产出不符合规范的代码而且因为验证脚本没更新还检测不出来。7.4 跨项目复用技能技能库做成熟后会发现很多技能是跨项目通用的比如写单元测试生成 API 文档。这时候可以考虑抽出来做成共享技能库。但要注意通用技能的定义要更抽象不能绑定特定项目的路径或命名。我的做法是给通用技能加参数化配置项目通过配置文件注入自己的约定。8. 关于 agent-skills 这套思路的边界agent-skills这类方案不是银弹。它适合的是任务可拆解、验证标准明确的场景比如功能开发、测试编写、重构。对于探索性任务比如帮我调研一下这个技术方案技能化反而增加负担因为这类任务没有明确的完成标准。另外技能工作流对 agent 本身的能力有要求。如果底层模型在长上下文和指令遵循上表现一般技能串联的效果会打折扣。我实测下来技能化在指令遵循强的模型上收益最明显在弱模型上可能还不如直接下指令。最后一个体会技能库是需要养的。刚开始可能只有几个技能随着项目推进慢慢补充。不要指望一次设计完美而是在使用中不断调整粒度和描述。我现在的技能库已经迭代了十几版每一版都是被实际失败逼出来的改进。这个过程本身其实就是把团队开发经验沉淀成可复用资产的过程。
返回列表