ARTICLE DETAIL

资讯详情

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

agent-skills 实战:用 CLI 与 TDD 构建稳定的 AI coding agent 工作流

agent-skills 实战:用 CLI 与 TDD 构建稳定的 AI coding agent 工作流 1. 从“agent-skills”说起为什么它值得单独拎出来聊第一次看到agent-skills这个标题很多人会以为它只是某个仓库里随手放的一堆提示词集合。但真正在 AI coding agent 这条线上折腾过一段时间的人会明白它其实指向一个更底层的问题当模型能力越来越强决定一个 agent 好不好用的往往不再是模型本身而是它被赋予的“技能”结构。我最初接触这个概念是在用 Claude Code 做日常开发辅助的时候。那时候我的用法很粗暴就是把需求丢进去让它改代码、跑测试、提交。能用但很不稳定。同一个任务今天跑得顺明天就翻车。后来我才意识到问题不在模型而在于我没有给它一套稳定的“技能包”——也就是 agent-skills 所代表的那套东西可复用的指令、可组合的工作流、可验证的测试驱动流程。agent-skills这个标题背后核心是三个关键词AI coding agents、skills CLI、test-driven-development。它解决的不是“模型会不会写代码”而是“模型能不能按照一套可靠的工程规范稳定地完成开发任务”。适合谁来参考我认为有三类人一是已经在用 Claude Code、Cursor 这类工具但觉得效果飘忽的开发者二是想给自己团队搭建统一 agent 工作流的技术负责人三是刚入门 AI coding、想少走弯路的独立开发者。这篇文章我会从设计思路、核心细节、实操过程、常见问题四个层面把 agent-skills 这套东西拆开讲清楚。不是复述文档而是把我自己踩过的坑、试过的参数、验证过的流程原原本本写出来。2. 整体设计思路为什么 agent-skills 要这样组织2.1 从“提示词”到“技能”的认知升级早期大家用 AI coding agent基本就是写一段 prompt然后祈祷它输出正确。这种做法的问题在于提示词是一次性的、不可复用的、无法验证的。你今天写了一段很长的 prompt 让 agent 帮你重构一个模块明天换个模块又得重写一遍。更麻烦的是你没法判断它到底做对了没有。agent-skills 的思路完全不同。它把每一个能力单元抽象成一个“技能”每个技能包含三部分触发条件、执行步骤、验证标准。触发条件告诉 agent 什么时候该用这个技能执行步骤是具体的操作指令验证标准则是判断任务是否完成的依据。这三者缺一不可尤其是验证标准它是把“感觉能用”变成“确定能用”的关键。我举个实际例子。假设你要让 agent 帮你修一个 bug。传统做法是“帮我修一下这个登录失败的 bug。”agent 可能会去改代码也可能去改配置甚至可能只是给你一段解释。而用技能化的方式你会定义一个fix-bug技能触发条件是“存在失败测试或明确报错”执行步骤是“先复现、再定位、再修改、再验证”验证标准是“相关测试全部通过且无回归”。这样一来agent 的行为就被约束在一个可控的框架里。2.2 为什么选择 CLI 作为主要入口skills CLI 是这套体系里很关键的一环。很多人会问为什么不做成图形界面非要搞命令行我的理解是CLI 是最适合 agent 的交互方式。原因有三点。第一CLI 的输出是结构化的、可解析的。agent 可以直接读取命令的返回结果判断下一步该做什么。图形界面则很难做到这一点截图识别、坐标点击这些方式既慢又不稳定。第二CLI 天然支持组合。一个技能的输出可以作为另一个技能的输入通过管道、脚本串联起来。这种组合能力是构建复杂工作流的基础。第三CLI 的调试成本低。出问题的时候你可以直接把命令复制出来手动跑一遍快速定位是技能定义的问题还是环境的问题。图形界面出问题你往往只能看到“失败了”三个字。提示如果你之前没有太多 CLI 经验建议先从最基础的命令开始熟悉比如文件操作、进程查看、环境变量设置。这些是后续所有技能的基础。2.3 test-driven-development 为什么被放在核心位置在 agent-skills 的语境里TDD 不只是一个开发方法论它更是agent 的“验收机制”。人类开发者写测试是为了保证代码质量agent 写测试是为了给自己一个明确的完成信号。我试过两种模式。一种是让 agent 先写代码再补测试。结果经常是测试写得敷衍甚至为了让测试通过而修改测试本身。另一种是先写测试再写实现。这种情况下agent 的目标非常明确让测试从红变绿。它不会跑偏也不会偷懒因为测试结果是客观的。所以 agent-skills 把 TDD 作为核心技能之一逻辑是通的。它把“做完了”这个模糊的判断变成了“测试通过了”这个明确的信号。对于 agent 来说明确的信号比模糊的指令重要得多。3. 核心细节解析agent-skills 的关键组成与实操要点3.1 技能定义文件的结构与写法一个标准的技能定义通常包含以下几个字段名称、描述、触发条件、输入参数、执行步骤、验证方式、失败处理。我用一个实际用过的run-tests技能来举例说明。name: run-tests description: 运行项目测试并返回结果 trigger: 当需要验证代码改动时 inputs: - test_path: 测试文件路径默认为 tests/ steps: - 检查测试框架配置 - 执行测试命令 - 解析测试输出 - 返回通过/失败状态 validation: 测试命令退出码为 0 on_failure: 输出失败用例详情建议回滚或修复这个结构看起来简单但每个字段都有讲究。trigger要写得足够具体否则 agent 会在不该用的时候乱用。inputs要给出默认值减少 agent 的决策负担。steps要拆得足够细每一步都是可执行的动作而不是模糊的描述。validation必须是客观可判断的不能是“看起来没问题”这种主观标准。我踩过的一个坑是早期我把steps写得太笼统比如“运行测试”。结果 agent 有时候跑单元测试有时候跑集成测试有时候甚至跑了个 lint 就交差了。后来我把步骤拆成“先检查 package.json 里的 test 脚本再执行 npm test再检查退出码”行为就稳定多了。3.2 技能之间的依赖与组合关系单个技能能做的事有限真正强大的是技能之间的组合。比如fix-bug技能会依赖run-tests技能来验证修复结果run-tests又可能依赖setup-env技能来保证环境正确。这里有个关键原则依赖关系要显式声明不能靠 agent 自己猜。我见过很多配置技能之间是隐式依赖的agent 有时候能猜对有时候猜错结果就是时好时坏。显式声明的方式很简单在技能定义里加一个depends_on字段列出它需要的前置技能。name: fix-bug depends_on: - setup-env - run-tests steps: - 复现问题 - 定位根因 - 修改代码 - 运行 run-tests 验证 - 如果失败回到定位步骤这样 agent 在执行fix-bug之前会先确保setup-env和run-tests是可用的。如果前置技能失败它会先处理前置问题而不是硬着头皮往下走。3.3 验证标准的设定技巧验证标准是 agent-skills 里最容易被忽视、也最容易出问题的地方。我总结了几条经验。第一验证标准必须是机器可判断的。“代码质量好”不是验证标准“lint 无报错”才是。“功能正常”不是验证标准“指定测试用例通过”才是。第二验证标准要分层。最底层是语法检查中间层是单元测试上层是集成测试。agent 应该逐层验证而不是直接跳到最上层。这样出问题的时候能快速定位是哪一层挂了。第三验证标准要可回滚。如果验证失败agent 需要知道怎么回到上一个稳定状态。这通常意味着在执行修改前要先做备份或者依赖版本控制。注意不要设一个 agent 永远无法满足的验证标准。比如要求“所有测试通过”但项目里本来就有几个长期失败的测试。这种情况下agent 会陷入无限循环。正确的做法是明确指定“本次改动相关的测试通过”。3.4 与 Claude Code 等工具的集成方式agent-skills 本身是一套抽象规范要落地到具体工具上需要做适配。以 Claude Code 为例它的工作方式是基于对话和工具调用的。你可以把技能定义转换成 Claude Code 能理解的指令格式通常是通过配置文件或者项目根目录下的约定文件。我自己的做法是在项目根目录放一个skills/目录里面每个技能一个文件。然后在 Claude Code 的配置里指定这个目录让它启动时加载。这样每次对话agent 都知道有哪些技能可用以及怎么用。对于 VS Code 里的 Claude Code 插件配置方式类似但要注意插件的版本差异。有些版本对自定义技能的支持还不完善需要手动在对话里引用技能名称。Ubuntu 和 Mac 上的安装流程基本一致主要是 Node 环境和相关依赖的差异。4. 实操过程从零搭建一套可用的 agent-skills 工作流4.1 环境准备与基础配置先说一下我的环境Ubuntu 22.04Node 20Claude Code 最新版。Mac 上的流程几乎一样只是包管理命令换成 brew。Windows 我没深度用过不做展开。第一步是安装 Claude Code。官方文档里有详细的安装说明核心就是通过 npm 全局安装然后配置 API 相关的环境变量。这里要注意不同版本的配置项名称可能有变化建议以官方文档为准。npm install -g anthropic-ai/claude-code claude --version安装完成后需要在项目里初始化配置。我通常会在项目根目录创建.claude/目录里面放settings.json和skills/子目录。settings.json里配置模型、权限、技能目录路径等。{ model: claude-sonnet-4-20250514, skillsDir: ./.claude/skills, autoApprove: false }autoApprove这个参数我建议初期设为 false让 agent 每次执行命令前都询问一下。等你对它的行为有足够信任了再考虑放开部分权限。4.2 编写第一个技能setup-env环境准备技能是所有其他技能的基础。它的作用是确保项目依赖安装完整、环境变量配置正确、必要的服务已经启动。name: setup-env description: 准备开发环境 trigger: 每次开始新任务前 steps: - 检查 node_modules 是否存在 - 如果不存在执行 npm install - 检查 .env 文件是否存在 - 如果不存在从 .env.example 复制 - 检查数据库连接 validation: npm install 退出码为 0 且 .env 文件存在 on_failure: 输出具体缺失项停止后续技能执行这个技能看起来简单但它解决了一个很实际的问题agent 经常在环境没准备好的情况下就开始干活结果各种莫名其妙的报错。有了这个前置技能后面的事情就顺多了。4.3 编写核心技能tdd-cycle这是整套工作流里最核心的技能。它把 TDD 的流程固化下来让 agent 严格按照“红-绿-重构”的节奏走。name: tdd-cycle description: 执行一轮完整的 TDD 循环 trigger: 需要新增或修改功能时 depends_on: - setup-env inputs: - feature_desc: 功能描述 steps: - 根据 feature_desc 编写一个失败的测试 - 运行测试确认它失败红 - 编写最少的代码让测试通过绿 - 运行测试确认它通过 - 重构代码保持测试通过 - 运行完整测试套件确认无回归 validation: 新增测试通过且完整测试套件无新增失败 on_failure: 回滚本次改动输出失败详情我实测下来这个技能的效果非常明显。以前让 agent 直接写功能它经常写出一堆看起来对但实际跑不通的代码。用了 tdd-cycle 之后它必须先写测试再写实现目标非常明确。而且因为测试是它自己写的它对测试的理解也更到位。提示feature_desc要写得足够具体。比如“用户可以通过邮箱和密码登录”比“实现登录功能”好得多。描述越具体agent 写的测试越准确。4.4 编写辅助技能review-diff代码写完了还需要检查。review-diff技能的作用是让 agent 自己审查自己的改动。name: review-diff description: 审查当前代码改动 trigger: 完成一个功能或修复后 steps: - 执行 git diff 获取改动 - 检查是否有调试代码残留 - 检查是否有硬编码的敏感信息 - 检查是否有未处理的异常 - 检查命名是否清晰 - 输出审查报告 validation: 审查报告生成且无严重问题 on_failure: 列出问题清单建议修复这个技能帮我省了很多事。以前我经常在提交前才发现 agent 留了一堆console.log或者写死了测试用的 API key。现在有了自动审查这些问题在提交前就被拦下来了。4.5 把技能串起来完整工作流演示有了上面几个技能就可以串成一个完整的工作流。假设我要给项目加一个“用户注册”功能流程是这样的执行setup-env确保环境就绪。执行tdd-cycle传入feature_desc: 用户可以通过邮箱和密码注册密码需要加密存储。agent 先写测试运行失败然后写实现运行通过。执行review-diff检查改动。如果审查有问题回到步骤 2 修复。全部通过后执行run-tests跑完整测试套件。确认无回归后提交代码。整个过程我只需要在关键节点确认一下大部分工作由 agent 自动完成。实测下来一个中等复杂度的功能从开始到提交大概 15 到 20 分钟。比我手动写快不少而且质量更稳定。5. 常见问题与排查技巧实录5.1 agent 不按技能定义执行怎么办这是最常见的问题。表现是 agent 跳过了某些步骤或者用了错误的技能。原因通常有三个。第一触发条件写得太模糊。比如trigger: 需要时agent 根本不知道什么时候算“需要”。改成trigger: 当存在失败测试时就明确多了。第二技能描述和实际任务不匹配。agent 在多个技能之间选择时会优先选描述最贴近当前任务的。如果描述写得不准它就会选错。第三技能之间有冲突。比如两个技能都声称自己处理“测试相关任务”agent 就会犹豫。解决办法是明确优先级或者在触发条件里加更具体的限定。排查方法很简单把 agent 的执行日志打开看它每一步选了哪个技能、为什么选。大部分问题看日志就能定位。5.2 测试一直失败导致 agent 陷入循环这个问题的根源通常是验证标准设得太严或者测试本身有问题。我遇到过一次agent 写的测试依赖了一个外部服务但那个服务在测试环境里没启动所以测试永远失败agent 就一直重试。解决办法有两个。一是把验证标准改成“本次新增的测试通过”而不是“所有测试通过”。二是确保测试环境是隔离的、可重复的。外部依赖要么 mock 掉要么在setup-env里确保它已启动。注意给 agent 设置最大重试次数。比如max_retries: 3。超过次数就停下来输出问题详情而不是无限循环。5.3 技能加载失败或找不到这个问题通常出在路径配置上。skillsDir的路径要相对于项目根目录或者用绝对路径。我见过有人写成了相对当前工作目录的路径结果 agent 在不同目录下启动时加载的技能不一样。另外要注意文件格式。YAML 对缩进很敏感一个空格错了就解析失败。建议用编辑器自带的 YAML 校验功能或者写完用yamllint检查一遍。5.4 常见问题速查表问题现象可能原因排查方法解决方案agent 跳过步骤触发条件模糊查看执行日志细化 trigger 描述测试无限失败验证标准过严检查测试输出缩小验证范围设置重试上限技能加载失败路径或格式错误检查 skillsDir 配置修正路径校验 YAMLagent 选错技能描述重叠对比技能描述明确优先级或合并技能环境报错依赖未安装手动跑 setup 命令完善 setup-env 技能改动被覆盖缺少备份机制检查 git 状态执行前先 commit 或 stash5.5 几个我踩过的坑和对应技巧第一个坑是技能定义太细。我一开始把每个步骤都拆得很碎结果 agent 执行起来很慢而且容易在某个小步骤上卡住。后来我调整了粒度一个技能大概 5 到 8 个步骤既清晰又不至于太琐碎。第二个坑是忽略了 agent 的上下文限制。技能定义太多太长会占用大量上下文导致 agent 在处理实际任务时反而变笨。我的做法是只加载当前任务相关的技能其他的按需加载。第三个坑是没有版本控制技能定义。技能定义本身也是代码也需要 review 和回滚。我现在把.claude/skills/目录纳入 git 管理每次修改都走正常的提交流程。第四个坑是过度依赖自动批准。早期我为了省事把autoApprove设成了 true结果 agent 执行了一些我没预期的命令。后来改回 false关键操作手动确认安心多了。6. 技能库的扩展与团队协作6.1 如何沉淀团队自己的技能库单个开发者用 agent-skills收益是线性的。团队一起用收益是指数级的。因为技能可以共享、可以复用、可以迭代。我的做法是在团队内部建一个共享的技能仓库。每个成员在项目中沉淀的好用技能都提交到这个仓库里。新项目启动时直接从仓库拉取需要的技能。这样新人不用从零摸索直接站在前人的肩膀上。技能仓库的结构大概是这样的skills-repo/ common/ setup-env.yaml run-tests.yaml review-diff.yaml frontend/ component-test.yaml visual-check.yaml backend/ api-test.yaml db-migrate.yaml README.mdcommon目录放通用技能frontend和backend放特定领域的技能。每个技能文件里除了定义还可以加注释说明使用场景和注意事项。6.2 技能评审与迭代机制技能定义不能随便改因为改了会影响所有使用它的人。我们团队的做法是技能修改走类似代码 review 的流程。提交者说明修改原因和影响范围至少一个人 review 通过后才能合并。迭代的节奏大概是每两周一次。每次迭代会上大家分享自己新写的技能、遇到的问题、改进的想法。好的技能会被提升到common目录不好的会被标记废弃。这个机制运行了几个月效果不错。技能库从最初的几个扩展到了现在的几十个覆盖了日常开发的大部分场景。6.3 与 CI/CD 的衔接agent-skills 不仅能用在本地开发还能和 CI/CD 衔接。比如在 CI 流程里加一步用 agent 自动检查代码改动是否符合规范、是否有遗漏的测试。我试过在 GitHub Actions 里跑一个 agent 任务让它 review PR 的 diff输出审查意见。虽然不能完全替代人工 review但能拦住很多低级问题比如格式错误、明显的逻辑漏洞、缺失的测试。配置方式大概是这样name: agent-review on: [pull_request] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Run agent review run: | npm install -g anthropic-ai/claude-code claude --skill review-diff --output review.md - name: Post review comment uses: actions/github-scriptv7 with: script: | const fs require(fs); const review fs.readFileSync(review.md, utf8); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: review });这个配置会在每个 PR 上自动跑一次 review把结果作为评论贴出来。实测下来能提前发现不少问题减少了人工 review 的负担。6.4 技能库的长期维护建议技能库用久了容易出现两个问题一是冗余二是过时。冗余是指多个技能做类似的事过时是指技能依赖的工具或流程已经变了。我的建议是定期做一次“技能审计”。把所有的技能过一遍合并重复的删除废弃的更新过时的。审计的频率不用太高一个季度一次就够了。另外给每个技能加一个last_verified字段记录最后一次验证可用的日期。超过一定时间没验证的标记为“待确认”。这样用的时候心里有数。7. 一些个人体会和后续可以尝试的方向这套 agent-skills 的工作流我从最初摸索到现在稳定使用大概花了三个月。中间踩了不少坑也走了不少弯路。最大的体会是agent 的能力上限很高但需要你用结构化的方式去引导。你给它模糊的指令它就给你模糊的结果你给它清晰的技能定义和验证标准它就能稳定地输出高质量的工作。另一个体会是TDD 在 agent 场景下的价值被放大了。人类开发者写测试有时候会觉得是负担。但对 agent 来说测试是它理解任务、验证结果的核心依据。没有测试agent 就像蒙着眼睛走路走对走错全靠运气。后续我打算尝试的方向有两个。一是把技能库和项目模板结合起来新项目初始化时自动带上常用技能。二是探索多 agent 协作让不同的 agent 分别负责不同的技能通过消息传递来协同完成复杂任务。这两个方向都还在早期等有成熟经验了再分享。如果你也在用 Claude Code 或者其他 AI coding agent我建议你从最简单的setup-env和run-tests开始先跑通一个最小闭环。别一上来就搞大而全的技能库那样容易挫败。小步快跑逐步沉淀才是可持续的路子。
返回列表