ARTICLE DETAIL

资讯详情

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

agent-skills实战:用CLI和Claude Code构建可复用TDD技能包

agent-skills实战:用CLI和Claude Code构建可复用TDD技能包 1. 从“agent-skills”说起为什么它值得你花时间第一次看到agent-skills这个词是在一个做 AI 编程工具链的朋友群里。有人甩了个链接说“这玩意儿把 Claude Code 的 skill 机制拆成了可复用的 CLI 工具”。当时我没太在意直到自己开始频繁用 AI coding agents 写项目才发现一个问题每次开新会话agent 都像失忆一样之前调教好的工作流、项目规范、测试习惯全部归零。agent-skills要解决的就是这件事。它本质上是一套围绕skills CLI构建的技能管理方案让你把“怎么让 AI 按我的方式干活”这件事从每次重复交代变成一次定义、处处复用。配合Claude Code这类支持 skill 机制的 AI coding agent你可以把test-driven-development这样的工程实践固化成 agent 能直接调用的技能包。这篇文章适合三类人看一是已经在用 Claude Code 或类似工具、但觉得每次都要重新“教”它很烦的开发者二是想把自己的工程经验沉淀成可复用资产的技术负责人三是刚接触 AI coding agents、想知道这套东西到底能干嘛的新手。我会从设计思路讲到实操细节包括 skill 的目录结构、CLI 的安装配置、怎么跟 TDD 流程结合以及我踩过的那些坑。2. 核心设计思路为什么是 skill CLI 这套组合2.1 从“提示词工程”到“技能工程”的转变早期用 AI coding agent大家的做法基本是写一大段 system prompt把项目背景、代码规范、测试要求全塞进去。我试过刚开始还行但 prompt 越写越长agent 反而开始抓不住重点。更麻烦的是换个项目就得重写一遍复用性几乎为零。agent-skills的思路不一样。它把每个独立的能力单元拆成一个skill每个 skill 有自己的目录、描述文件、执行逻辑和依赖声明。Agent 在需要的时候按需加载而不是一次性把所有信息灌进去。这就像从“给员工一本员工手册”变成“给员工一个技能工具箱”需要拧螺丝的时候拿螺丝刀需要量尺寸的时候拿卷尺。skills CLI则是管理这个工具箱的命令行入口。你可以用它安装、更新、组合、发布 skill。我实测下来这套机制最大的价值在于skill 是可版本化的。你可以把团队的最佳实践做成 skill 包push 到仓库里新同事 clone 下来就能用agent 的行为立刻对齐。2.2 为什么选 Claude Code 作为主要载体市面上支持 skill 机制的 AI coding agent 不止一个但 Claude Code 目前在这块的支持最成熟。它的 skill 加载机制、工具调用协议、以及跟终端命令的集成度都让agent-skills的落地变得顺滑。具体来说Claude Code 允许 skill 定义自己的触发条件、输入参数、执行步骤甚至可以在 skill 内部调用其他 skill。这意味着你可以构建一个 skill 依赖图比如run-testsskill 依赖detect-test-frameworkskill后者又依赖read-package-jsonskill。这种组合能力是单纯写 prompt 做不到的。另外Claude Code 对test-driven-development的支持也很关键。TDD 的核心是“红-绿-重构”循环这个循环里有很多重复动作跑测试、看失败信息、改代码、再跑测试。把这些动作封装成 skillagent 就能自动执行整个循环你只需要在关键节点做决策。2.3 方案选型背后的取舍有人可能会问为什么不直接用 Makefile 或者 npm scripts我的理解是Makefile 和 npm scripts 是给人用的而 skill 是给 agent 用的。区别在于skill 需要包含语义描述让 agent 能理解“这个技能是干什么的、什么时候该用、输入输出是什么”。这是传统构建工具不具备的。另一个取舍是skill 的粒度。太粗复用性差太细管理成本高。我的经验是一个 skill 最好对应一个“可独立验证的行为”。比如“运行单元测试”是一个 skill“生成测试报告”是另一个 skill而不是把两者揉在一起。这样 agent 在只需要跑测试的时候不会被迫生成报告。3. 核心细节解析skill 的目录结构与关键文件3.1 一个标准 skill 的解剖我拿自己写的一个tdd-cycleskill 举例目录结构大概是这样tdd-cycle/ ├── skill.yaml # 技能描述文件 ├── README.md # 人类可读的说明 ├── scripts/ │ ├── run_tests.sh # 执行测试 │ ├── parse_output.py # 解析测试结果 │ └── apply_fix.sh # 应用修复建议 ├── templates/ │ └── test_template.py └── tests/ └── test_skill.py # skill 自身的测试skill.yaml是最关键的文件它定义了技能的元信息。我通常会写这几块name: tdd-cycle version: 1.2.0 description: 执行测试驱动开发的完整循环包括运行测试、解析失败、生成修复建议 triggers: - 运行TDD循环 - 执行红绿重构 inputs: - name: test_command type: string default: pytest description: 测试执行命令 - name: max_iterations type: integer default: 5 description: 最大迭代次数 outputs: - name: status type: string enum: [passed, failed, max_iterations_reached] - name: report type: string dependencies: - detect-test-framework - parse-test-output这里有几个细节值得说。triggers字段决定了 agent 在什么情况下会加载这个 skill。我试过用自然语言描述触发条件效果比用关键词匹配好很多因为 agent 能理解语义相似度。inputs和outputs的显式声明让 skill 之间的组合变得可靠agent 知道该传什么、该期待什么。3.2 skills CLI 的安装与初始化安装 skills CLI 本身不复杂但有几个坑我踩过。官方推荐的方式是通过包管理器安装我以 npm 为例npm install -g agent-skills/cli装完之后先跑一下skills --version确认安装成功。然后初始化你的 skill 仓库skills init my-skills-repo cd my-skills-repo这个命令会生成一个标准的仓库结构包括skills/目录、registry.yaml索引文件、以及一个示例 skill。registry.yaml是本地 skill 的注册表CLI 通过它来发现和管理 skill。注意如果你在公司内网环境npm 源可能需要切换。我建议先确认npm config get registry的输出如果不是你预期的源用npm config set registry改掉。这个坑我踩过装了半天装不上最后发现是源的问题。3.3 skill 的加载机制与优先级Claude Code 加载 skill 的时候会按一定优先级搜索。我实测下来的顺序是项目根目录下的.claude/skills/目录用户主目录下的~/.claude/skills/目录通过 skills CLI 全局安装的 skill内置的默认 skill这个优先级意味着你可以在项目里覆盖全局 skill。比如全局的run-testsskill 默认用 pytest但某个项目用的是 jest你可以在项目目录下放一个同名的 skillagent 会优先用项目级的。这里有个容易忽略的点skill 的加载是懒加载的。Agent 不会在启动时把所有 skill 都读进来而是根据 triggers 按需加载。所以你的 skill 数量可以很多不会拖慢启动速度。但反过来如果 triggers 写得不好agent 可能找不到该用的 skill。我的经验是triggers 里至少写 3-5 个不同角度的描述覆盖用户可能的表达方式。4. 实操过程从零搭建一个 TDD skill4.1 环境准备与依赖确认在开始写 skill 之前先确认你的环境。我用的是 Ubuntu 22.04Claude Code 版本是当时的最新版。你需要Node.js 18skills CLI 依赖Python 3.10我用来写 skill 的辅助脚本一个可用的 Claude Code 环境确认 Claude Code 能正常工作claude --version如果这个命令报错说明 Claude Code 没装好或者没在 PATH 里。我遇到过在 Ubuntu 上用 snap 安装后 PATH 不对的情况解决办法是手动把安装目录加到.bashrc里。4.2 创建 skill 骨架用 CLI 创建一个新 skillskills create tdd-cycle --template basic这个命令会生成前面提到的目录结构。然后进入目录开始填内容。我建议先从skill.yaml开始因为它是整个 skill 的契约。写skill.yaml的时候description 字段要特别用心。Agent 会读这个描述来判断是否加载 skill。我一开始写得太简略比如“运行测试”结果 agent 经常在不需要的时候也加载它。后来改成“执行测试驱动开发的完整循环包括运行测试、解析失败信息、生成修复建议适用于需要严格TDD流程的场景”准确率明显提升。4.3 编写核心执行脚本scripts/run_tests.sh是实际干活的脚本。我的写法是这样#!/bin/bash set -e TEST_COMMAND${1:-pytest} OUTPUT_FILE/tmp/tdd_test_output.txt echo 执行测试命令: $TEST_COMMAND if $TEST_COMMAND $OUTPUT_FILE 21; then echo STATUS: PASSED exit 0 else echo STATUS: FAILED exit 1 fi这个脚本很简单但有几个设计决策值得说。第一我把输出重定向到临时文件而不是直接打印。因为 agent 需要解析输出文件比 stdout 更可靠。第二我用STATUS: PASSED/FAILED这样的标记方便 agent 用正则提取。第三set -e确保脚本在出错时立即退出避免 agent 拿到混乱的状态。parse_output.py负责解析测试结果。我写了个简化版import re import sys def parse_test_output(file_path): with open(file_path, r) as f: content f.read() failures re.findall(rFAILED (.?) - (.), content) errors re.findall(rERROR (.?) - (.), content) result { failure_count: len(failures), error_count: len(errors), failures: [{test: t, reason: r} for t, r in failures], errors: [{test: t, reason: r} for t, r in errors] } return result if __name__ __main__: import json result parse_test_output(sys.argv[1]) print(json.dumps(result, indent2))这个脚本的输出是 JSONagent 可以直接解析。注意不同测试框架的输出格式不一样pytest、jest、go test 各有各的格式。我的做法是让detect-test-frameworkskill 先识别框架然后parse-test-outputskill 根据框架选择对应的解析器。这就是 skill 组合的价值。4.4 注册与测试 skill写完脚本后用 CLI 注册skills register ./tdd-cycle然后验证 skill 是否能被正确加载skills list skills info tdd-cycleskills info会显示 skill 的元信息、依赖关系、以及触发条件。我建议每次改完skill.yaml都跑一下这个命令确认没有语法错误。接下来是实际测试。在 Claude Code 里输入触发词比如“帮我跑一下TDD循环”看 agent 是否加载了正确的 skill。我一开始遇到的问题是 agent 加载了 skill 但没传对参数后来发现是inputs的default值没写对。教训skill.yaml里的每个字段都要仔细检查agent 对格式很敏感。4.5 参数计算与迭代策略max_iterations这个参数我设成 5是经过计算的。假设每次迭代 agent 有 70% 的概率修复一个失败测试那么 5 次迭代后至少修复一个的概率是 1 - 0.3^5 ≈ 99.8%。但实际上agent 修复失败的概率没那么高我实测大概在 40%-60% 之间。所以 5 次迭代是个平衡点太少可能没修完就停了太多浪费 token 和时间。如果你跑的测试套件很大建议把max_iterations调低比如 3。因为大测试套件里agent 一次修复可能影响多个测试迭代次数不需要太多。反过来如果测试套件很小但很复杂可以调到 8-10。提示max_iterations不是越大越好。我试过设成 20结果 agent 在明显修不好的情况下还在硬试浪费了大量 token。后来我加了个early_stop逻辑如果连续 3 次迭代失败测试数量没减少就提前退出。5. 常见问题与排查技巧实录5.1 skill 加载失败从日志入手最常见的问题是 skill 没被加载。排查步骤确认 skill 在正确的目录下。用skills list看 CLI 是否能发现它。检查skill.yaml的语法。YAML 对缩进很敏感我建议用在线 YAML 校验器过一遍。看 Claude Code 的日志。日志里会显示 agent 尝试加载了哪些 skill、为什么跳过某些 skill。我遇到过一次skill 明明在目录里但 agent 就是不加载。查了半天发现是triggers里写了一个特殊字符导致 YAML 解析失败。教训skill.yaml里尽量用纯文本避免特殊符号。5.2 脚本执行权限问题scripts/下的脚本需要有执行权限。我一开始忘了chmod x结果 agent 调用时报“Permission denied”。解决办法chmod x scripts/*.sh chmod x scripts/*.py另外如果你在 Windows 上开发、在 Linux 上运行注意换行符问题。我用dos2unix处理过一批脚本不然 bash 会报奇怪的错误。5.3 测试输出解析失败不同测试框架的输出格式差异很大。我整理了一个速查表测试框架失败标记错误标记建议解析方式pytestFAILEDERROR正则匹配FAILED (.?) - (.)jest✕●解析 JSON 输出--json参数go test--- FAILpanic按行解析找--- FAILmochafailingError解析 JSON 输出--reporter json我的建议尽量让测试框架输出 JSON解析起来最可靠。pytest 可以用--json-report插件jest 和 mocha 原生支持 JSON reporter。5.4 agent 不按预期调用 skill有时候 agent 会“自作主张”不用你定义的 skill而是自己写命令。这通常是因为 triggers 不够明确或者 skill 的 description 没写好。我的解决办法是在skill.yaml里加priority: high提高 skill 的优先级在 description 里明确写“必须使用此 skill 执行 XX 操作”在项目的CLAUDE.md里写明“执行测试必须通过 tdd-cycle skill”最后一条最有效。Claude Code 会读项目根目录的CLAUDE.md你可以在里面强制规定某些操作必须走 skill。5.5 常见问题速查表问题现象可能原因解决方法skill 未加载triggers 不匹配增加 triggers 描述覆盖更多表达方式脚本报权限错误缺少执行权限chmod x脚本文件解析结果为空输出格式不匹配检查测试框架输出格式调整正则agent 不用 skill优先级不够加priority: high或在 CLAUDE.md 中强制skill 依赖找不到依赖未安装用skills install dep安装依赖迭代次数过多max_iterations 太大调低到 3-5加 early_stop 逻辑6. 进阶玩法skill 组合与团队协作6.1 构建 skill 依赖图单个 skill 的能力有限真正强大的是 skill 组合。我现在的项目里TDD 流程涉及这几个 skilldetect-test-framework识别项目用的测试框架run-tests执行测试命令parse-test-output解析测试结果generate-fix根据失败信息生成修复建议apply-fix应用修复tdd-cycle编排以上所有 skilltdd-cycle的skill.yaml里声明了依赖dependencies: - detect-test-framework - run-tests - parse-test-output - generate-fix - apply-fixAgent 加载tdd-cycle时会自动加载所有依赖。这样你只需要触发一个 skill整个流程就跑起来了。6.2 团队协作中的 skill 管理团队用 skill 的时候最大的问题是版本不一致。我的做法是把 skill 仓库作为 git submodule 挂在项目里在 CI 里加一步skills validate确保所有 skill 的skill.yaml合法用skills lock生成锁定文件记录每个 skill 的版本和哈希这样新同事 clone 项目后跑一下skills sync就能拿到完全一致的 skill 环境。我试过比口头交代“你要这样那样配置”靠谱多了。6.3 把个人经验沉淀成 skillagent-skills最有价值的地方是让你把“我平时怎么干活”变成可复用的资产。比如我有个习惯每次改完代码先跑 lint再跑测试最后检查 git diff。这个流程我写成了一个pre-commit-checkskillname: pre-commit-check description: 提交前检查依次执行 lint、测试、diff 审查 steps: - skill: run-lint - skill: run-tests - skill: review-diff condition: git diff --cached --quiet || true这个 skill 现在团队里所有人都在用新人入职第一天就能按老员工的习惯干活。这就是 skill 的复利效应你花一次时间定义团队所有人受益。6.4 性能优化减少 skill 加载时间Skill 多了之后加载时间会变长。我实测下来20 个 skill 的情况下首次加载大概多花 1-2 秒。优化方法把不常用的 skill 的priority设为lowagent 只在明确需要时才加载合并功能相近的 skill比如把run-unit-tests和run-integration-tests合并成run-tests用参数区分用skills cache命令缓存 skill 元信息避免每次重新解析注意skills cache在 skill 更新后需要手动刷新不然 agent 可能用到旧版本。我建议在 CI 里加一步skills cache --refresh。7. 我踩过的坑与实操心得7.1 不要过度设计 skill我一开始想把所有东西都做成 skill结果搞了 30 多个管理起来很累。后来发现只有重复三次以上的操作才值得做成 skill。一次性的任务直接让 agent 执行就行没必要封装。7.2 skill 的测试很重要Skill 本身也是代码也需要测试。我现在的做法是每个 skill 的tests/目录下至少有一个测试文件验证核心逻辑。CI 里跑skills test确保 skill 改动不会破坏现有功能。7.3 文档要写给 agent 看也要写给人看skill.yaml的 description 是给 agent 看的README.md是给人看的。两者都要写而且内容要一致。我遇到过 agent 按 description 加载了 skill但人看 README 发现用法不对的情况。后来我强制要求两者同步更新。7.4 版本管理要严格Skill 的版本号我建议遵循语义化版本修 bug 升 patch加功能升 minor破坏性改动升 major。团队协作时用skills lock锁定版本避免“我这儿能跑你那儿报错”的情况。7.5 从简单 skill 开始如果你刚接触agent-skills别一上来就搞复杂的 TDD 编排。先写一个最简单的 skill比如“打印当前项目结构”跑通了再逐步加复杂度。我当初就是贪多结果一个 skill 都没跑通差点放弃。8. 后续可以这样扩展agent-skills这套机制的上限很高。我现在在探索几个方向一是把 code review 流程做成 skill让 agent 自动检查 PR 的常见问题二是把部署流程封装成 skill实现“一句话部署到测试环境”三是把 skill 和 CI/CD 打通让 agent 在 CI 失败时自动触发修复 skill。另外skill 的分享机制也值得关注。现在已经有人在建 skill 市场你可以把自己写的 skill 发布上去也可以安装别人写的。我试过几个社区 skill质量参差不齐但有几个确实好用。我的建议是安装第三方 skill 前先看它的skill.yaml和脚本确认没有危险操作再用。最后分享一个小技巧如果你不确定某个操作该不该做成 skill先手动做三遍。三遍之后你自然就知道哪些步骤是固定的、哪些是变化的。固定的部分封装成 skill变化的部分做成参数。这个原则我用了半年做出来的 skill 复用率最高。
返回列表