大模型应用实战

拆解 Anthropic 官方评测方法论:从「定义成功标准」到 claude plugin eval

Anthropic 同时给出了两份评测文档:Claude 开发者平台的《定义成功标准并构建评估》讲方法论,Claude Code 的《使用 evals 测试插件》讲工程落地。本文把两者放在一起拆解:SMAR 成功标准、六种评分方法的选型、claude plugin eval 的用例/评分器/基线三层结构、with vs without 的 Δ 设计、沙箱隔离与 CI 门控的退出码约定,以及它给我们自建评测平台的几点启示。

·约 17 分钟阅读·AI Engineering

两份文档,一条完整的链

Anthropic 最近有两份关于评测的官方文档,放在一起读很有意思:

  • 《定义成功标准并构建评估》(Claude 开发者平台):讲方法论。先定义什么叫「好」,再设计评估去量它。
  • 《使用 evals 测试插件》(Claude Code):讲工程落地。给插件和 Skill 作者一个开箱即用的评测命令 claude plugin eval。

前者回答「评什么、怎么打分」,后者回答「怎么把评测做成可重复、可门控的工程环节」。本文按这条线拆:先拆方法论,再拆工具,最后提炼值得借鉴的设计。


第一部分:方法论——先定义成功,再谈评估

成功标准的 SMAR 四点

文档要求好的成功标准满足四点:

特性要点
具体 Specific明确目标,不说「性能良好」,而说「准确的情感分类」
可衡量 Measurable用定量指标,或定义明确的定性量表
可实现 Achievable参考行业基准、既有实验和专家知识,不超出当前模型能力
相关 Relevant与应用目的、用户需求一致

它给的对比很直观,哪怕是「安全」这种模糊概念也能量化:

标准
差安全的输出
好在 10,000 次试验中,被内容过滤器标记为有毒的输出少于 0.1%

情感分析的例子则把四点全用上了:在 10,000 条多样化 Twitter 帖子的保留测试集(相关)上,F1 至少 0.85(具体、可衡量),比当前基线提高 5%(可实现)。

一个应用,多个维度

文档强调大多数用例需要多维标准。它列了 8 类常见维度:任务保真度、一致性、相关性和连贯性、语气和风格、隐私保护、上下文利用、延迟、价格。情感分析的「好」标准是这样组合的:

  • F1 ≥ 0.85
  • 99.5% 的输出无毒
  • 90% 的错误只造成不便,而非严重错误
  • 95% 的响应时间低于 200 ms

注意第三条:「不便」与「严重」的界限需要在实际项目里自己定义。错误要分严重程度,这一点后面还会反复出现。

构建评估的三条原则

  1. 针对特定任务。 测试集要反映真实任务分布,并包含边缘案例:不相关或不存在的输入、过长的输入、质量差或有害的输入、连人类都难以达成共识的模糊用例。
  2. 尽可能自动化。 把题目组织成可自动评分的形式。
  3. 数量优先于质量。 更多问题配上信号稍弱的自动评分,好过更少问题配高质量人工评分。

第三条最容易被反直觉地忽略。很多团队习惯精心打磨 20 条题、全部人工看,结果一次换模型就不敢动了。官方的立场是:覆盖面更重要,单条信号可以粗一点。

六种评分方法的选型

文档把评分方法和评估的维度一一对应,这张表几乎可以当选型速查:

评估维度方法衡量内容文档中的测试集规模
任务保真度(情感分类)精确匹配输出规范化后是否等于预定义答案1,000 条人工标注推文
一致性(FAQ 机器人)余弦相似度改写问题的回答在句子嵌入空间中的相似度50 组问题,每组含若干改写
相关性和连贯性(摘要)ROUGE-L候选与参考摘要的最长公共子序列 F1200 篇带参考摘要的文章
语气和风格(客服)LLM 李克特量表让 LLM 按 1–5 给语气(同理心、专业等)打分100 条带目标语气的咨询
隐私保护(医疗)LLM 二元分类响应里是否含 PHI(yes/no)500 条模拟患者查询
上下文利用(对话助手)LLM 序数量表引用并基于对话历史的程度,1–5100 个含依赖上下文问题的多轮对话

规律很清楚:能用代码确定性判断的就用代码(精确匹配、余弦相似度、ROUGE-L),只有主观维度才交给 LLM(语气、隐私判断、上下文利用)。

精确匹配的实现朴素得近乎「简陋」,但这恰恰是重点:

def evaluate_exact_match(model_output, correct_answer):
    return model_output.strip().lower() == correct_answer.lower()

配合提示词里的「只输出标签」约束,一个分类任务的评估就做完了。

测试集里的边缘案例设计

文档示例中的边缘案例很值得抄:

  • 情感分类:反讽(「航班延误 5 小时我真是太喜欢了 #bestdayever」)、混合情感(剧情糟糕但演技出色)
  • FAQ 一致性:错别字(「Wut's yur retrn polcy?」)、冗长啰嗦的问题、夹带无关信息的问题
  • 摘要:多主题文章、误导性标题
  • 隐私:显式 PHI、假设性 PHI、隐式 PHI(「我儿子在吃和他父亲去年一样的药」)
  • 客服:愤怒的客户、复杂问题、以抱怨形式出现的夸奖

这些案例的共同点是:都是模型最容易在语义上栽跟头的位置,而不是随机抽样能轻易覆盖到的。

LLM 评分的两条实操细节

代码注释里有一句不起眼但很关键的话:用 LLM 评分时,通常最佳做法是使用与生成被评估输出不同的模型来评估。另外,评分提示只要求输出「数字」或「yes/no」,便于程序解析。

这两点对应着自评偏差和解析稳定性两个真实问题。


第二部分:claude plugin eval——把方法论做成命令

方法论讲完,进入工具。claude plugin eval 针对一套测试用例运行你的插件,并给结果打分。它的核心设计可以拆成四层。

1. 用例(Case):一个目录一个场景

一个 eval 套件位于插件内的 evals/ 目录,每个用例是一个子目录:

my-plugin/
├── .claude-plugin/plugin.json
├── skills/...
└── evals/
    ├── first-case/
    │   ├── prompt.md          # frontmatter: 用例字段;正文: 提示词
    │   ├── graders/
    │   │   ├── criteria.md    # frontmatter: 类型+选项;正文: 评分标准
    │   │   └── skill-fired.md
    │   └── case.yaml          # 可选:仅用于 context.* 字段
    └── results/               # 每次运行写入;加入 .gitignore

几个值得注意的设计:

  • 文件即配置。 提示词是 prompt.md 的正文,运行限制(max_turns、timeout_seconds、allowed_tools 等)在 frontmatter 里,没有任何数据库或平台依赖,用例天然可以进 Git、走 Code Review。
  • 每个用例至少一个评分器,否则加载失败。没有评分标准的用例不允许存在。
  • 提示词要写成用户真实会说的话,而不是直接点名 Skill。 文档特别强调这一点,否则测不出 Skill 的触发率。

另外有一个脚手架命令 claude plugin eval init:它会读取你的插件,询问你期望的结果,提议「应该触发」和「不应该触发」的提示词,为每个提示词设计评分器,先试运行一次确认评分器的行为,再写入文件。要点在于「不应该触发」也是一等公民,Skill 误触发和漏触发同样是缺陷。

2. 运行(Run):隔离、多次、有上限

每次用例运行,Claude Code 都会启动一个全新的、隔离的非交互式会话,仅加载你的插件,发送提示,直到完成或触及轮次/时间上限。

默认每个用例跑三次,因为「一次非确定性代理的运行告诉你很少」。运行分数是其通过的评分器的比例(可加权),用例分数是多次运行的平均值,达到 --threshold(默认 1.0)才算通过。

隔离做得相当彻底:

隔离项行为
个人与项目配置用户设置、hooks、CLAUDE.md、MCP 服务器、其他插件、memory、skills 全部不加载
项目级配置工作区内的 .claude/、CLAUDE.md、.mcp.json 都不会读取,连脚手架脚本写入的也不读
环境变量只放行允许列表和 EVAL_* 前缀变量
用例定义对被测代理隐藏,Claude 看不到提示词、评分器和兄弟用例
工具权限默认只读;Bash、Write、Edit、WebFetch 等必须用 --allow-tools 显式授予,且 Bash 在 OS 级沙箱下运行
权限提示运行永远不会停下来请求权限,没授予的工具直接从会话里移除

这套隔离的价值在于可重复性:你的本机配置不会污染结果,换一台机器、换一个人跑,结论应该一致。

3. 评分器(Grader):六种类型,成本分两档

评分器是对 Claude 产出的通过/失败检查。六种类型:

类型检查什么成本
regexJavaScript 正则在目标中是否匹配(可要求缺失或恰好 N 次)零
tool_used某个工具被调用的次数,可按输入内容过滤,min/max 控制范围零
tool_order两个工具调用的先后顺序零
file_exists运行期间是否创建了匹配 glob 的文件零
llm评判模型对评分标准至少 3 票中 2 票 PASS调用模型
baseline评判模型认为运行至少与参考记录一样满足标准调用模型

前四种从会话记录和文件计算,不产生模型成本;后两种需要评判模型,会增加成本。llm 评分器采用多票表决(三次投票取多数)来压低评判模型自身的随机性。

评分器可以查看的对象也有明确分类(target / focus):最后一条消息、完整会话记录(trace)、创建的文件路径列表、某个文件的内容,以及对 mock MCP 工具的调用记录。

一个很实用的组合是文档给出的「两个评分器」模式:

---
type: tool_used
tool: Skill
input_match: '"skill"\s*:\s*"(?:[\w-]+:)?your-skill-name"'
---

一个评分器检查结果(最终消息或产物),另一个检查过程(有没有真的调用到你的 Skill)。两者结合才能回答:「答案对不对」和「是不是你的插件产出的」。

文档里的稳定性建议

这部分与我们在自己评测里踩过的坑高度重合:

  • 长输出(例如生成的文件)用 regex 对文件内容评分,每次都以相同方式检查整个文件;llm 评分器留给短输出,并用具体的 PASS/FAIL 条件写评分标准。
  • 如果 tool_used: Skill 通过但 Δ 为负,先怀疑评判模型而不是插件——小型评判模型可能因格式与评分标准描述不同,把正确答案判错。换更强的评判模型重跑,并收紧评分标准,让格式不决定判定。
  • 要验证构建或测试是否通过,让提示词要求 Claude 运行并把结果写入文件,对该文件评分,再用 tool_used 加 input_match 断言命令确实被执行过。
  • 没有自定义代码评分器,文档明确这样说。能力边界被刻意收窄。

4. 基线(Baseline):with vs without 与 Δ

这是整个设计里最漂亮的一环。

仅凭高分不能告诉你插件是否有帮助,因为 Claude 可能在没有插件的情况下也能做得很好。

所以每个用例默认跑两组:加载插件(with-arm)和不加载插件(without-arm),得到 WITH、W/OUT 两个分数,二者之差 Δ 就是插件的净贡献:

CASE        WITH  W/OUT Δ      RUNS COST    NOTES
first-case  1.00  0.33  +0.67  6    $0.41

如果一个用例有无插件都是 1.0,那插件就不是它通过的原因。

这里有一个细节处理:「Skill 被调用了」这类检查在没有插件时永远不会通过,计入分数会把 without-arm 压到 0,从而夸大 Δ。因此这类评分器在两个 arm 里都不计入分数,只在 with-arm 里作为通过/失败指示器展示;需要时可以用 arm: both 强制两边都评(比如「不得调用某 Skill」这类反向检查,min: 0、max: 0)。

文档给的典型首次发现是:Δ 接近零、tool_used: Skill 失败——意味着在自然措辞下,Claude 根本没选你的 Skill。解法不是改代码,而是改 Skill 的 description,再跑一遍对比。

夹具与 Mock:让依赖外部服务的 Skill 也能被测

Skill 常常调用 MCP 工具,而真实服务不可控。plugin eval 的做法是在 evals/mocks/<server>/<tool>.md 里放 Markdown 文件,正文就是工具返回给 Claude 的内容:

---
expect:
  title: string
  priority: [low, medium, high]
---
 
Created issue #4821: {{input.title}}
  • {{input.<field>}} 把调用输入回显进结果
  • expect: 校验 Claude 传给工具的输入,违规则以 0 分中止运行并记录原因——这让你能断言「插件要求服务器做的事对不对」
  • error: true 返回工具错误,用来测错误处理路径
  • type: agent 让评判模型以服务器的身份回答,并支持把答案录制后回放(mock-recordings/ → mocks/.replay/),让 CI 运行可重复且不再产生模型调用

没有 mock 文件的工具对 Claude 不可用;默认不会启动真实 MCP 服务器,除非显式 --allow-real-servers 或 --mocks off。

需要文件或 git 状态时,用 case.yaml 的 context.scaffold_script(脚本在代理沙箱之外运行,因此必须传 --scaffold 才会执行)、context.history_file(恢复一段历史对话)和 context.add_dirs(给 Claude 只读的夹具目录)。


第三部分:进 CI——退出码就是契约

门控场景的推荐命令:

claude plugin eval . \
  --trust-plugin \
  --json results.json \
  --threshold 0.8 \
  --model claude-sonnet-5 \
  --judge-model claude-haiku-4-5 \
  --no-publish \
  --max-cost-usd 20

几个参数背后的工程考虑:

  • --model 与 --judge-model 分别固定:避免模型发布被误认成插件回归,评判模型固定才能保证分数跨时间可比。
  • --max-cost-usd 设成本上限:每次运行开始前检查,超限后不再启动新的运行,已开始的会完成,所以实际花费可能略超。
  • --trust-plugin 让作业不会卡在首次信任提示上。
  • -j 并发最大 8,只缩短耗时,共享账户的速率限制,不会提高吞吐上限。

退出码设计得很清晰:

退出码含义
0套件通过:所有用例得分达到阈值,且无其他失败原因
1有用例低于阈值、用例加载失败、没找到用例、无法启动、或有运行因 API 错误而结束
2部分运行:触及成本上限或凭据被拒,results.json 仍写入并带 partial: true 与原因
130 / 143被中断 / 被终止(如 CI 超时)

两个值得记住的原则:

  1. Δ 只报告,不影响退出码。 门控看的是 with-arm 分数是否达标,基线对比留给人看趋势。
  2. API 错误不静默当作 0 分混过去。 因用量/速率限制而结束的运行会被记为 0 分且不评分,命令以非零退出,哪怕所有用例的分数都够。这避免了「限流导致的假通过/假失败」污染结论。

JSON 结果是版本化的(schemaVersion: 1),脚本应忽略不认识的字段;趋势图要把 partial: true 的文档以及有 skippedPaidGraders 的运行剔除,因为它们的分数不可比。

控制 CI 成本的建议也很具体:每次提交都跑的快速套件只用不调用评判模型的评分器,不需要 Δ 的地方用 --ablation none。


值得借鉴的设计

把两份文档对照着读,我提炼出这几点:

  1. 成功标准先于评分。 没有「0.85 F1、99.5% 无毒、95% 低于 200 ms」这样的数字,评分器写得再漂亮也无从判断好坏。
  2. 确定性评分优先,LLM 评分兜底。 官方示例里六种方法只有三种用到 LLM,而 plugin eval 的六种评分器里有四种零成本。LLM 只用在语气、隐私判断这类没法写规则的地方,并且用多票表决降低随机性。
  3. 一个用例同时评结果和过程。 答案对了不代表是你的 Skill 做的,反之亦然。
  4. 用 with vs without 基线分离「插件的贡献」和「模型自己的能力」。 分数本身不说明问题,Δ 才说明问题。
  5. 非确定性靠多次采样吸收。 默认三次,不是出于洁癖,而是单次运行信息量太低。
  6. 评测配置做成文件,进版本控制。 用例、评分标准、mock 都是 Markdown/YAML,可 Review、可 diff、可回溯。
  7. 把「失败了但不是被测对象的错」单独标识出来。 限流、成本上限、凭据失败、部分结果,都有独立的退出码或字段,不混进分数里。
  8. 评测本身也要被约束。 成本上限、沙箱、信任提示、权限最小化:评测会真实调用模型、真实执行工具,必须像生产系统一样对待。

如果你也在自建评测平台,这八条基本可以当成检查清单。比如我们自己在复测一个 Jira Skill 的时候,就遇到了「AI 评判放过转述错误」和「单 case 结论不可靠」的问题,解决方式(脚本逐字对比、100 case × 3 次采样)与官方的思路是同向的:能确定性判断的绝不交给模型,样本量要足以暴露低频致命错误。


总结

  1. 方法论层: SMAR 成功标准 → 覆盖边缘案例的测试集 → 按维度选评分方法(确定性优先,主观维度用 LLM)。
  2. 工具层: claude plugin eval 把用例、评分器、基线三者做成了文件化、可重复、可隔离的流水线,且默认就包含多次采样与 with/without 对比。
  3. 工程层: 固定被测模型与评判模型、设置成本上限、用明确的退出码区分「真失败」和「运行没跑完」,才能让评测成为可信的 CI 门控。

两份文档合起来传达的只有一个观点:评测不是跑完拿个分,而是一套让分数可信、可比、可追溯的工程体系。


欢迎访问 PrimeSkills —— 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。

更多实用知识和有趣产品,欢迎访问我的个人主页