欢迎光临
我们一直在努力

Skill 测试入门:从使用场景出发,搞清楚怎么验证你的 AI 技能

Skill 测试入门:从使用场景出发,搞清楚怎么验证你的 AI 技能

最近在项目里密集使用 Skill,踩了几个坑,让我开始认真思考「怎么测试 Skill」这件事。

一个是 Code Review Skill。我让它审查一个涉及业务规则变更的 PR,它把代码风格问题列了一堆,但真正影响业务逻辑的改动反而没提。换个 PR,它又把正常的防御性编程当 Bug 报了出来。

另一个是文档一致性检测 Skill。我用 Claude Code 跑的时候效果还行,换了个模型再跑,输出格式和检测粒度都偏了,像是完全不同的 Skill。

还有一个更头疼的。项目里的业务 Agent 会自动调用流程化 Skill 处理用户请求,有一次中间步骤的脚本报错了,Agent 直接把堆栈信息原封不动吐给了用户,没有重试也没有降级。

这三个场景让我意识到一件事:这些虽然都叫 Skill,但它们干的活完全不同。Code Review 测的是「代码理解准不准」,流程 Skill 测的是「编排稳不稳」。用同一套思路去测试,肯定不行。

于是我开始系统地研究 Skill 测试这件事。下面是我整理出来的东西,从类型分类到文件夹结构,再到测试策略和开源工具,一步步讲清楚。

Skill 有哪些类型

① 从「谁在调用它」出发来分类

一开始我也按安装位置来分 Skill——内置的、用户装的、项目级的。后来发现这么分对测试没什么指导意义。

真正决定测试策略的,是「谁在调用它」和「它在干什么」。从这个角度,Skill 大体可以分成两类:开发期编码辅助 Skill 和 业务期 Agent 流程工具 Skill。

开发期的 Skill 是你主动调用的。你在写代码的时候让 Claude Code 帮你做 Code Review,或者让它检测文档和代码是不是一致,这些是你在开发过程中有意识地使用的工具。

业务期的 Skill 是 Agent 自动调用的。用户在使用你的产品时,Agent 根据业务逻辑自动触发某个 Skill,走一套固定流程,调用外部 API 或脚本,最后把结果返回给用户。

这两类 Skill 的测试重心完全不同:前者测「代码质量和语义理解」,后者测「流程稳定性和工具编排」。

② 开发期三种常见 Skill

开发期的编码辅助 Skill,我在项目里主要用三种:

Code Review Skill:审查代码变更,发现潜在 Bug、规范问题、安全风险。核心能力是理解代码语义,不只是做语法检查。

文档一致性检测 Skill:检查代码变更后,相关的接口文档、README、设计文档是不是同步更新了。核心能力是同时理解代码和文档的语义,判断它们是否对齐。

清理冗余 Skill:找出项目里的死代码、重复逻辑、未使用的依赖,然后清理掉。核心能力是在不破坏功能的前提下识别「可以删」的代码。

③ 业务期两种常见 Skill

业务期的 Skill 跟着 Agent 走,用户触发、Agent 调用、自动执行:

流程化 Skill:多步骤编排,比如「接收需求 → 生成 Spec → 拆分 Task → 执行开发 → 跑测试 → Code Review → 归档」。每个步骤可能调用不同的子 Agent 或工具。

工具调用 Skill:调用外部 API、数据库、Shell 脚本等。比如「查用户订单状态」「调用支付接口」「执行数据库迁移脚本」。

④ 一张表看清区别
类型调用方式核心能力测试重心
Code Review 你主动调用 代码语义理解 漏报率、误报率
文档一致性 你主动调用 代码+文档语义对齐 变更同步检测、语义对齐
清理冗余 你主动调用 死代码识别 安全性、功能等价性
流程化 Agent 自动调用 多步骤编排 状态机流转、异常处理
工具调用 Agent 自动调用 外部系统交互 权限控制、幂等性

#mermaid-svg-kody6eLly1piwNYN{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kody6eLly1piwNYN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kody6eLly1piwNYN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kody6eLly1piwNYN .error-icon{fill:#552222;}#mermaid-svg-kody6eLly1piwNYN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kody6eLly1piwNYN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kody6eLly1piwNYN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kody6eLly1piwNYN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kody6eLly1piwNYN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kody6eLly1piwNYN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kody6eLly1piwNYN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kody6eLly1piwNYN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kody6eLly1piwNYN .marker.cross{stroke:#333333;}#mermaid-svg-kody6eLly1piwNYN svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kody6eLly1piwNYN p{margin:0;}#mermaid-svg-kody6eLly1piwNYN .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-kody6eLly1piwNYN .cluster-label text{fill:#333;}#mermaid-svg-kody6eLly1piwNYN .cluster-label span{color:#333;}#mermaid-svg-kody6eLly1piwNYN .cluster-label span p{background-color:transparent;}#mermaid-svg-kody6eLly1piwNYN .label text,#mermaid-svg-kody6eLly1piwNYN span{fill:#333;color:#333;}#mermaid-svg-kody6eLly1piwNYN .node rect,#mermaid-svg-kody6eLly1piwNYN .node circle,#mermaid-svg-kody6eLly1piwNYN .node ellipse,#mermaid-svg-kody6eLly1piwNYN .node polygon,#mermaid-svg-kody6eLly1piwNYN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kody6eLly1piwNYN .rough-node .label text,#mermaid-svg-kody6eLly1piwNYN .node .label text,#mermaid-svg-kody6eLly1piwNYN .image-shape .label,#mermaid-svg-kody6eLly1piwNYN .icon-shape .label{text-anchor:middle;}#mermaid-svg-kody6eLly1piwNYN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kody6eLly1piwNYN .rough-node .label,#mermaid-svg-kody6eLly1piwNYN .node .label,#mermaid-svg-kody6eLly1piwNYN .image-shape .label,#mermaid-svg-kody6eLly1piwNYN .icon-shape .label{text-align:center;}#mermaid-svg-kody6eLly1piwNYN .node.clickable{cursor:pointer;}#mermaid-svg-kody6eLly1piwNYN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kody6eLly1piwNYN .arrowheadPath{fill:#333333;}#mermaid-svg-kody6eLly1piwNYN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kody6eLly1piwNYN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kody6eLly1piwNYN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kody6eLly1piwNYN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kody6eLly1piwNYN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kody6eLly1piwNYN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kody6eLly1piwNYN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kody6eLly1piwNYN .cluster text{fill:#333;}#mermaid-svg-kody6eLly1piwNYN .cluster span{color:#333;}#mermaid-svg-kody6eLly1piwNYN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kody6eLly1piwNYN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kody6eLly1piwNYN rect.text{fill:none;stroke-width:0;}#mermaid-svg-kody6eLly1piwNYN .icon-shape,#mermaid-svg-kody6eLly1piwNYN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kody6eLly1piwNYN .icon-shape p,#mermaid-svg-kody6eLly1piwNYN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kody6eLly1piwNYN .icon-shape .label rect,#mermaid-svg-kody6eLly1piwNYN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kody6eLly1piwNYN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kody6eLly1piwNYN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kody6eLly1piwNYN :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

主动调用

自动调用

业务期 Agent 流程工具 Skill

流程化 Skill

工具调用 Skill

开发期编码辅助 Skill

Code Review

文档一致性检测

清理冗余

Agent

这个分类不是学术上的严格划分,而是在实际项目中摸出来的。你可能还会遇到其他类型,但大部分 Skill 都能归到这两类五种里。

一个 Skill 文件夹里都有什么

① 目录结构长什么样

从 skill-creator 的官方定义看,每个 Skill 就是一个目录,核心是 SKILL.md,其他都是可选的:

skill-name/
├── SKILL.md # 必需,核心文件
├── agents/
│ └── openai.yaml # 可选,UI 展示元数据
├── scripts/ # 可选,可执行脚本
│ └── validate.py
├── references/ # 可选,按需加载的参考文档
│ └── style-guide.md
└── assets/ # 可选,模板、图标等资源
└── template.md

② SKILL.md 是关键

SKILL.md 分两部分:YAML frontmatter 和 Markdown body。

Frontmatter 里只有两个字段是必须的:name 和 description。这两个字段是 Skill 的触发机制——Agent 靠它们来决定要不要加载这个 Skill。

Body 是具体的指令和指南,告诉 Agent 拿到这个 Skill 后怎么干活。但 body 只在 Skill 被触发后才会加载,不是一开始就塞进上下文的。

这个设计叫渐进式披露。Agent 先看 description 决定要不要用,用了才读 body。这样能省不少上下文空间。

③ Sub-agent 怎么调用 Skill

这里有个细节值得讲。Sub-agent 调用 Skill 的过程分三步:

  • 系统提示词里注入了一份 Skill 索引,包含所有启用 Skill 的名称和描述,最多 20 个,总大小不超过 4KB
  • LLM 判断当前任务和某个 Skill 的描述匹配,调用内置的 load_skill 工具
  • Skill 完整内容写入上下文缓冲区,下一轮 LLM 请求时自动注入到用户消息前面
  • 有个关键设计:每个 Sub-agent 有独立的 Skill 缓冲区,用 LRU 策略最多缓存 3 个 Skill。因为 Skill 内容注入后会从缓冲区清空(drain 操作),如果多个 Sub-agent 共享同一个缓冲区,一个 Worker 的 drain 会把另一个 Worker 还没读到的内容清掉。

    ④ Skill 怎么匹配

    用户输入一段话,系统怎么知道该加载哪个 Skill?打分制。

    每个 Skill 的得分由四个维度加权计算:

    • 精确名称匹配:直接加 10000 分,确保用户点名的 Skill 一定排第一
    • 名称词项命中:权重 ×12
    • 标签词项:权重 ×6
    • 描述词项:权重 ×2

    中文分词不走传统分词器,而是取单个汉字加上 2 字和 3 字的滑动窗口。比如「代码审查」会生成「代」「码」「审」「查」「代码」「码审」「审查」「代码审」「码审查」这些特征。这样能覆盖大部分中文短语。

    ⑤ 三层覆盖体系

    Skill 有三层,按优先级从低到高:

    项目级 .paicli/skills/ 最高优先级,同名覆盖
    用户级 ~/.paicli/skills/ 中等优先级,同名覆盖
    内置 程序打包 最低优先级

    同名 Skill,优先级高的整体覆盖低的。为什么这么分?内置 Skill 提供开箱即用的基础能力,用户级满足个人工作流定制,项目级承载团队约定。离项目越近,优先级越高。

    Claude Code 的设计也是一脉相承:内置 Skill、用户 Skill、项目 Skill 三层。

    为什么不能纯手工测试

    ① 大模型的非确定性

    传统软件测试是确定性的。给一个输入,得到一个固定的输出,跑一万次都一样。但大模型不一样,同样的 Prompt,温度参数、上下文长度、甚至服务端负载不同,都可能导致输出不同。

    这意味着你不能用「跑通了没」这种二元判断来测试 Skill。得用概率思维:跑通了多少次。

    ② 玄学调试的陷阱

    很多开发者(包括我)写 Skill 的时候容易陷入一种状态:改一句 Prompt,试十次看效果。这次跑通了就觉得 OK,下次跑挂了再改一句。这就是「玄学调试」。

    玄学调试的问题在于:你看到的一两次成功可能是偶然,一两次失败也可能是偶然。没有足够的样本量,你分不清「这个 Skill 真的好用」还是「这次碰巧跑对了」。

    ③ 需要工具和方法论

    正确的做法是:

    • 先写测试,再写 Skill:定义功能时就同步写下 10-20 个核心测试用例
    • 引入 A/B 测试:每次修改 description 或指令,跑一遍 Benchmark,看哪一版胜率更高
    • 建立数据飞轮:线上真实流量采样 → 标注 → 加入数据集 → 评测 → 优化 → 上线,形成闭环

    说白了,得有工具帮忙。纯靠人工点,效率太低,结论也不可靠。

    开发期编码辅助 Skill 怎么测

    这类 Skill 的核心是「理解代码语义」,测试重点在于准确率、误报率和安全性。

    ① Code Review Skill

    测试点:漏报率(真实 Bug 没发现)、误报率(正常代码当 Bug 报)、规范符合度(是否遵循团队编码规范)。

    关键步骤:

  • 构造黄金数据集:准备 20-30 个 PR 片段,包含真实漏洞(空指针、SQL 注入、并发问题)和正常代码,作为「标准答案」。
  • 差异比对测试:把 Skill 的输出和资深开发者的真实 Review 意见比对,计算召回率(Recall,该发现的 Bug 发现了多少)和精确率(Precision,报出来的问题有多少是真的)。
  • 上下文感知测试:传入跨文件的调用链,测试它能不能发现跨模块的逻辑缺陷,而不是只盯着单文件看。
  • 推荐工具:Diff 工具比对输出;结合 SonarQube 等静态分析工具的结果做交叉验证。如果 Skill 的 Review 结果和 SonarQube 的报告高度一致,说明它的基础能力没问题;如果 Skill 能发现 SonarQube 漏掉的问题,那才是真正的价值。

    ② 文档一致性检测 Skill

    测试点:变更同步检测能力(代码改了文档没改,能不能发现)、语义对齐能力(文档描述和实际逻辑是不是一致)。

    关键步骤:

  • 变更注入测试:手动改代码逻辑(比如改 API 参数、字段名),但保持文档不变,验证 Skill 能不能精准定位不一致的地方。
  • 反向验证测试:改文档描述,保持代码不变,验证 Skill 能不能识别出文档和代码的语义冲突。
  • 多文档关联测试:测试 Swagger/YAPI 接口文档、README、内部设计文档与代码的多维一致性。很多 Skill 只能检测一对关系(代码 vs README),碰到多文档场景就歇菜了。
  • 推荐工具:写脚本自动对比 Git diff 中的代码变更与文档变更;用 LLM-as-Judge 做语义相似度打分——让一个更强的模型来判断「这段文档描述的是不是这段代码的功能」。

    ③ 清理冗余 Skill

    测试点:安全性(有没有误删核心逻辑)、代码瘦身效果、功能等价性(清理前后代码行为是不是一致)。

    关键步骤:

  • 沙箱执行测试:在 Docker 隔离环境里运行清理后的代码,确保单元测试 100% 通过,功能没受损。这是最基础的保底测试。
  • 死代码边界测试:构造包含条件编译、动态反射、插件化加载的代码,测试 Skill 会不会误删「看似冗余实则必要」的代码。比如 Java 里通过反射调用的方法,静态分析看是「没用到」,但删了就炸。
  • 幂等性测试:对同一份代码连续运行多次清理 Skill,确保结果稳定,不会越删越少。跑第一次删了 10 个文件,跑第二次又删了 3 个,这就说明 Skill 的判断不够确定。
  • 推荐工具:JUnit/pytest 做回归验证;JaCoCo/Istanbul 等代码覆盖率工具验证清理后覆盖率没下降——如果覆盖率反而上升了,说明删掉的确实是没用的代码。

    业务期 Agent 流程工具 Skill 怎么测

    这类 Skill 的核心是「状态机流转」和「外部交互」,测试重点在于流程稳定性、异常处理和防死循环。

    ① 流程化 Skill(多步骤编排)

    测试点:状态机流转正确性、中间产物完整性、死循环检测。

    关键步骤:

  • 状态机断点测试:在流程的每个阶段(比如 plan → dev → test → review)插入断点,验证上游输出是不是完整传递给了下游。很多 Bug 不是单步骤的问题,而是步骤之间上下文截断导致的。
  • 异常中断与恢复测试:模拟某一步骤失败(API 超时、脚本报错),验证 Skill 有没有重试机制或优雅降级。直接崩溃把堆栈吐给用户是最差的体验。
  • 人工介入模拟:在流程中间强制打断,模拟用户修改中间产物,验证下游能不能正确感知变更并继续执行。比如用户在 plan 阶段手动改了需求,dev 阶段的 Agent 应该能感知到变化,而不是按旧 plan 继续跑。
  • 推荐工具:LangSmith 或 LangFuse 做全链路追踪。这两个工具能记录每个 Skill 调用的输入、输出、Token 消耗、延迟和工具调用链,排查多 Agent 协作时的「断链」问题特别好用。

    ② 工具调用 Skill(调用外部 API/脚本)

    测试点:权限控制(有没有越权)、异常处理(API 挂了怎么办)、数据脱敏(有没有泄露敏感信息)、脚本执行的幂等性。

    关键步骤:

  • Mock 依赖测试:用 Mock 服务器模拟外部 API 的各种返回——正常返回、超时、500 错误、非法数据格式,验证 Skill 的容错能力。不能假设外部依赖永远正常。
  • 权限边界测试:构造越权请求(比如未授权访问数据库、删除非当前目录文件),验证 Skill 有没有拦截机制。这个在生产环境里是安全底线。
  • 敏感数据扫描:检查 Skill 的输入输出日志,确保没有硬编码的 API Key、密码、用户隐私数据。有些 Skill 开发时图方便把密钥写死在脚本里,上线后就是安全事故。
  • 推荐工具:WireMock 或 MockServer 做 API 模拟;Semgrep 做敏感信息静态扫描。Semgrep 能在代码提交前就扫出硬编码的密钥和敏感信息。

    开源测试工具全景

    ① 工具一览

    测试 Skill 不能从零造轮子,得借助成熟的工具。下面是我在调研过程中整理的主流工具:

    工具定位适用场景链接
    anthropic skill-creator Skill 创建+验证+改进 写 Skill 时同步测试 https://github.com/openai/skills
    Promptfoo Prompt/Skill 评测框架 批量跑用例、A/B 测试 https://github.com/promptfoo/promptfoo
    Skillgrade AI Skill 单元测试框架 Docker 环境自动评测 开源项目
    LangSmith Agent 全链路追踪 生产级监控和调试 https://smith.langchain.com
    LangFuse 开源 Agent 可观测性 本地调试、可视化分析 https://langfuse.com
    Playwright + MCP 前端/UI 自动化测试 涉及 Web 交互的 Skill https://playwright.dev
    Agent Evaluation 开源 Agent 测试框架 LLM 当考官自动打分 开源项目
    WireMock/MockServer API Mock 模拟外部依赖 https://wiremock.org
    Semgrep 静态代码扫描 敏感信息检测 https://semgrep.dev
    SonarQube 静态分析平台 代码质量交叉验证 https://www.sonarqube.org

    工具和 Skill 类型的对应关系:

    #mermaid-svg-M2V6bXnXiokozDXz{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-M2V6bXnXiokozDXz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-M2V6bXnXiokozDXz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-M2V6bXnXiokozDXz .error-icon{fill:#552222;}#mermaid-svg-M2V6bXnXiokozDXz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-M2V6bXnXiokozDXz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-M2V6bXnXiokozDXz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-M2V6bXnXiokozDXz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-M2V6bXnXiokozDXz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-M2V6bXnXiokozDXz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-M2V6bXnXiokozDXz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-M2V6bXnXiokozDXz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-M2V6bXnXiokozDXz .marker.cross{stroke:#333333;}#mermaid-svg-M2V6bXnXiokozDXz svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-M2V6bXnXiokozDXz p{margin:0;}#mermaid-svg-M2V6bXnXiokozDXz .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-M2V6bXnXiokozDXz .cluster-label text{fill:#333;}#mermaid-svg-M2V6bXnXiokozDXz .cluster-label span{color:#333;}#mermaid-svg-M2V6bXnXiokozDXz .cluster-label span p{background-color:transparent;}#mermaid-svg-M2V6bXnXiokozDXz .label text,#mermaid-svg-M2V6bXnXiokozDXz span{fill:#333;color:#333;}#mermaid-svg-M2V6bXnXiokozDXz .node rect,#mermaid-svg-M2V6bXnXiokozDXz .node circle,#mermaid-svg-M2V6bXnXiokozDXz .node ellipse,#mermaid-svg-M2V6bXnXiokozDXz .node polygon,#mermaid-svg-M2V6bXnXiokozDXz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-M2V6bXnXiokozDXz .rough-node .label text,#mermaid-svg-M2V6bXnXiokozDXz .node .label text,#mermaid-svg-M2V6bXnXiokozDXz .image-shape .label,#mermaid-svg-M2V6bXnXiokozDXz .icon-shape .label{text-anchor:middle;}#mermaid-svg-M2V6bXnXiokozDXz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-M2V6bXnXiokozDXz .rough-node .label,#mermaid-svg-M2V6bXnXiokozDXz .node .label,#mermaid-svg-M2V6bXnXiokozDXz .image-shape .label,#mermaid-svg-M2V6bXnXiokozDXz .icon-shape .label{text-align:center;}#mermaid-svg-M2V6bXnXiokozDXz .node.clickable{cursor:pointer;}#mermaid-svg-M2V6bXnXiokozDXz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-M2V6bXnXiokozDXz .arrowheadPath{fill:#333333;}#mermaid-svg-M2V6bXnXiokozDXz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-M2V6bXnXiokozDXz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-M2V6bXnXiokozDXz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-M2V6bXnXiokozDXz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-M2V6bXnXiokozDXz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-M2V6bXnXiokozDXz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-M2V6bXnXiokozDXz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-M2V6bXnXiokozDXz .cluster text{fill:#333;}#mermaid-svg-M2V6bXnXiokozDXz .cluster span{color:#333;}#mermaid-svg-M2V6bXnXiokozDXz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-M2V6bXnXiokozDXz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-M2V6bXnXiokozDXz rect.text{fill:none;stroke-width:0;}#mermaid-svg-M2V6bXnXiokozDXz .icon-shape,#mermaid-svg-M2V6bXnXiokozDXz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-M2V6bXnXiokozDXz .icon-shape p,#mermaid-svg-M2V6bXnXiokozDXz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-M2V6bXnXiokozDXz .icon-shape .label rect,#mermaid-svg-M2V6bXnXiokozDXz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-M2V6bXnXiokozDXz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-M2V6bXnXiokozDXz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-M2V6bXnXiokozDXz :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    通用工具

    创建加验证

    A/B 测试

    自动评测

    skill-creator

    所有 Skill

    Promptfoo

    Skillgrade

    业务期测试

    全链路追踪

    Mock + 扫描

    LangSmith / LangFuse

    流程化 Skill

    WireMock + Semgrep

    工具调用 Skill

    开发期测试

    交叉验证

    语义打分

    回归验证

    SonarQube

    Code Review Skill

    Git diff + LLM-as-Judge

    文档一致性 Skill

    pytest + JaCoCo

    清理冗余 Skill

    ② 重点工具展开

    anthropic skill-creator(https://github.com/openai/skills)

    这个工具不只是创建 Skill,还内置了验证和测试机制。三个核心模式:

    • Eval 模式:验证 Skill 的触发是否准确,检查 description 会不会在不该触发的时候误触发
    • Benchmark 模式:A/B 测试不同版本的 description,看哪个版本的胜率更高
    • Improve 模式:根据失败案例自动改进 Skill 的指令

    它还内置了 forward-testing 机制:启动 Subagent 作为「不知情的测试员」,给它一个任务让它用 Skill 来完成,然后检查输出质量。关键设计是 Subagent 不知道在测试 Skill,只当是普通任务,这样测出来的结果更真实。

    验证脚本 scripts/quick_validate.py 可以检查 YAML frontmatter 格式、必填字段和命名规则。

    Promptfoo

    适合做批量评测和 A/B 测试。你可以定义一组测试用例(输入 + 期望输出),然后跑不同版本的 Skill,自动生成胜率对比报告。对于优化 description 和指令特别有用。

    LangSmith / LangFuse

    这两个工具功能类似,都是做 Agent 全链路追踪的。区别是 LangSmith 是商业产品,LangFuse 是开源的。核心能力:

    • 记录每个 Skill 调用的完整链路(输入 → 推理 → 工具调用 → 输出)
    • 统计 Token 消耗和延迟
    • 排查多 Agent 协作时的信息丢失和断链

    对于流程化 Skill 的调试,这两个工具几乎是必备的。

    Playwright + MCP

    如果你的 Skill 涉及前端页面验证或 Web 交互,可以让 Claude Code 通过 MCP 集成 Playwright,自动启动浏览器、模拟点击、截图对比、捕获 JS 错误。测试 Webapp Testing Skill 或 UI 自动化验收特别好用。

    5 个核心测试维度

    不管是哪种类型的 Skill,开发者视角的测试都可以从 5 个维度来衡量。这不是我拍脑袋想的,是实际项目中反复验证出来的:

    ① 触发精准度(目标 ≥90%)

    准备 20-30 条测试查询,包含应触发场景(「帮我做代码审查」)和不应触发场景(「这段代码什么意思」)。如果 Skill 在不该触发的时候强行介入,用户体验会很差。

    ② 任务完成率(目标 ≥85%)

    设计 5-10 个典型任务场景,每个场景定义清晰的「完成标准」(比如文档包含所有必需章节、代码无报错)。记录独立完成、需人工干预或完全失败的比例。

    ③ 上下文效率

    观察从初始版本到可用版本需要多少轮迭代。3-5 轮迭代后质量趋于稳定是健康信号;如果 10 轮以上还不稳定,说明 Skill 设计过于复杂,需要拆分或重新设计。

    ④ 用户满意度(目标 ≥80%)

    通过评测界面收集反馈,或者记录用户手动修改输出结果的比例。如果用户每次都得大改,说明 Skill 的实际价值有限。

    ⑤ 时间效率(目标 ≥2x)

    对比使用 Skill 和人工完成相同任务的时间。如果 Skill 还没人工快,那自动化的意义就不大了。

    9 大评估指标

    上面 5 个维度是宏观的,落到具体执行层面,还有 9 个量化指标可以参考:

    指标及格线优秀线
    任务完成率(TCR) ≥90% >98%
    工具调用准确率(TCA) ≥95% ≥99%
    幻觉率 ≤5% ≤1%
    P95 延迟 <10s <5s
    Token 效率 <5000/任务 <2000/任务
    平均交互步数 <8 步 <4 步
    安全通过率 100% 100%
    回归通过率 ≥98% 100%

    安全通过率是唯一不能妥协的指标。其他指标可以逐步优化,但安全问题没有「及格线」,只有「全过」和「全不过」。

    用户视角和软件测试视角

    ① 用户怎么验证 Skill 好不好用

    如果你是普通用户,装了 Skill 但不确定有没有用,可以试三种方法:

  • 明确调用测试:不要只靠 AI 自动触发,测试时明确告诉模型「这次只使用指定的 Skill」。这样你才能清楚看到它到底有没有生效。
  • AB 对比测试:拿一个真实任务,一次不用 Skill,一次明确调用 Skill,对比结果稳定性、是否需要重复说明背景、后续修改成本。
  • 输入输出验证:检查 Skill 的输入要求是不是清晰,输出结果是不是符合预期格式。靠谱的 Skill 必须能明确说出「需要你给我什么」和「最后交付什么」。
  • ② 用 Skill 来生成测试用例

    还有一种用法:不是测试 Skill 本身,而是用 Skill 来辅助软件测试。常见的实战项目:

    • 生成测试用例:上传需求文档或截图,让 Skill 自动生成包含正常、异常、边界场景的结构化测试用例,支持导出 Markdown
    • 生成测试脑图:上传 PRD 文档,让 Skill 自动解析业务逻辑,生成 XMind 测试用例脑图
    • 性能数据分析:上传性能测试原始数据(响应时间、并发数),让 Skill 提炼核心指标,生成专业分析报告
    • 需求风险分析:上传产品原型截图,让 Skill 输出核心业务目标、关键用户场景和潜在风险

    分层测试金字塔

    测试不是一层的,得分层来做:

    ┌─────────────┐
    │ 回归测试 10% │ 历史 Badcase + 黄金数据集
    ├─────────────┤
    │ 集成测试 30% │ 多 Skill 协作、Agent 编排
    ├─────────────┤
    │ 单元测试 60% │ 单个 Skill 输入输出
    └─────────────┘

    单元测试层(60%):针对单个 Skill 的输入输出,用脚本和 Mock 环境跑自动化测试。这是基础,投入最多,回报也最大。

    集成测试层(30%):针对多 Skill 协作和 Agent 编排,用状态机脚本跑端到端流程,验证流程连通性。流程化 Skill 和工具调用 Skill 的主要测试阵地。

    回归测试层(10%):每次上线前,用历史 Badcase 和黄金数据集跑一遍,防止「修了一个 Bug,引入两个新 Bug」。

    落地建议:先从单元测试层开始,把单个 Skill 的脚本在本地沙箱里跑通,确保输入输出符合预期,再往上叠加集成和回归测试。

    我的收获和还没想明白的事

    ① 三个收获

    第一个收获:开发期 Skill 测「语义理解」,业务期 Skill 测「流程稳定性」。这两类 Skill 的测试方法论完全不同,不能混着来。Code Review 的黄金数据集对流程 Skill 没用,流程 Skill 的状态机断点测试对 Code Review 也没用。

    第二个收获:从真实 Case 抽数据,不要自己编测试用例。直接从线上跑过的真实任务日志里,挑出 10-20 个典型场景(包括成功的和失败的)作为「黄金数据集」。自己编的用例容易脱离实际。

    第三个收获:先跑通单个 Skill 的最小闭环,再叠加 Agent 逻辑。很多人上来就测整个 Agent 流程,出问题了不知道是哪个 Skill 的锅。先把每个 Skill 单独跑通,再测它们之间的协作。

    ② 还没想明白的事

    大模型的非确定性怎么彻底解决?概率思维能缓解,但不能根治。同一个 Skill 跑 100 次,95 次 OK 5 次挂,那 5 次在生产环境里就是事故。

    Skill 之间互相干扰怎么检测?多个 Skill 共享同一个上下文窗口,一个 Skill 的输出可能影响另一个 Skill 的行为。目前没看到好的隔离测试方案。

    涉及写数据库、发生产消息、调用支付接口的 Skill,怎么设计安全拦截和熔断机制?这是下一步需要重点考虑的。

    写在最后

    Skill 测试这件事,说复杂也复杂,说简单也简单。核心就一句话:搞清楚你的 Skill 属于哪一类,然后用对应的策略去测它。

    开发期的 Skill 测语义理解,准备黄金数据集,用 Recall 和 Precision 量化。业务期的 Skill 测流程稳定性,用状态机断点和 Mock 测试覆盖异常场景。工具方面,skill-creator 帮你验证结构,Promptfoo 帮你做 A/B 测试,LangSmith/LangFuse 帮你追踪链路。

    不用一步到位。从 10-20 个真实 Case 开始,先跑通最小闭环,再逐步完善。

    对了,如果你的业务 Agent 涉及比较敏感的外部操作(写数据库、发生产消息、调用支付接口),一定要在关键步骤加人工确认或权限拦截,别让它全自动乱跑。这个比 Skill 本身的测试更重要。

    赞(0)
    未经允许不得转载:171主机测评 » Skill 测试入门:从使用场景出发,搞清楚怎么验证你的 AI 技能
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址