用 Claude Code 自动建评测并逐步提分:build-eval 和 hillclimb 怎么用
根据 Claude Code 团队的文章整理:claude-api skill 新增 build-eval 和 hillclimb 两个命令,一个在你的代码库里建评测,一个对着评测一轮改一处地提分。讲清好评测的四个特征、怎么防止过拟合,以及官方的两个例子。
本文根据公开分享整理,本站尚未实测。操作前请对照文末的原始来源。
这是“Claude Code 开发系列”的第七篇。
这一篇解决的问题是:你改了提示词、换了模型,怎么知道是变好了还是变差了,又怎么不被自己骗。 评测(eval)给出的就是这个信号。但设计评测很难,对着评测提分而不自欺更难。Claude Code 自带的 claude-api skill 现在把这两件事做成了两个命令:
| 命令 | 做什么 |
|---|---|
/claude-api build-eval |
在你的代码库里建一套评测 |
/claude-api hillclimb |
对着评测改进你的应用,每轮只改一处,并留一部分样例不看,用来发现过拟合 |
这篇面向的是用 Claude API 做应用、做 skill 的人。如果你只是日常用 Claude Code 写代码,可以直接跳到最后一节。
怎么开始
claude-api skill 随 Claude Code 一起发布,先更新到最新版:
claude update
然后在 Claude Code 里运行:
/claude-api build-eval
/claude-api hillclimb
- 想为某个问题生成一套评测,用
build-eval。可以给它一些样例(比如运行记录)来引导。样例和评分器都要经过你确认。 - 已经有评测,想让 Claude 对着它改进,用
hillclimb,并告诉它目标:效果更好,或者效果不变而成本更低。
下面先讲原则,再讲两个命令各自是怎么落实这些原则的。
好评测的四个特征
- 任务和实际使用一致。 从你真正在意的场景里取样。有些任务被选进来只是因为容易生成、容易打分,这样测出来的不是你关心的东西。
- 更强的模型、更多的思考,分数应该更高。 如果不是这样,多半是任务有歧义,或者评分器没校准。
- 最强的配置也有提升空间。 最强的模型用最高的 effort,分数应该明显低于 100%,否则你没法判断改动的影响。但这个差距不能来自做不了或有歧义的任务:一个常见的迹象是,某个任务无论重复多少次都失败。好的任务是两位领域专家会给出同样的判断,并且评分器检查的每一点都写在了任务里。
- 多次运行的结果波动小。 波动大往往是任务有歧义,或者评分器对同样的输出给出不同的结论。波动也可能藏在配置里(比如 effort 没有一致地生效),或者藏在环境里:上一次试验留下的文件、git 历史,可能直接把答案交给了代理。
别专挑模型做不好的题
模型的能力是参差不齐的。如果你选样例的标准是“现在的模型在这题上失败了”,那你采到的只是这一个模型的短板,评测量的就成了它的失败特征,而不是这件事本身难不难、有没有价值。
原文的建议:
- 选难题的依据是人判断它难。一个有用的检验:收进来之前,你能不能说出它为什么难。
- 收录应用里真实的失败:来自线上流量、bug 报告、工单。
- 也不要盲目相信用户流量。用户有时只会尝试他们觉得能成的事,完全从流量里取样,题目可能偏简单。
build-eval:建评测
运行之后,Claude 会先向你提问,然后在你的代码库里建评测,并在几个节点停下来等你确认。
第一步:定样例
Claude 按这个顺序帮你找输入:
- 线上的会话记录(会先问数据保留和敏感信息的问题);
- bug 报告和工单;
- 你手写的 5 到 10 个样例;
- 从代码库合成的样例。
优先用真实流量,也可以以你给的几个真实样例为基础生成合成数据。它会生成一个简单的页面,把每个输入都展示出来,等你确认。
第二步:定评分器,并验证它
Claude 会提议一个适合你的输出、同时最便宜的评分器:
| 类型 | 什么时候用 | 怎么评 |
|---|---|---|
| 程序检查 | 输出的可能性有限 | 完全匹配、固定集合里的标签、符合 schema 的 JSON、测试通过 |
| 让模型当裁判 | 输出是开放的,有很多种对的答案,但质量标准清楚 | 另一个模型读输入、输出和评分标准,给出分数和理由 |
用模型当裁判时有三个细节:
- 评分标准要写成一条条可以核对的说法,而不是 1 到 5 分的量表。
- 如果有基线可以比较,裁判会以随机顺序读两份输出、不知道哪份是基线,然后选更好的那个。
- 裁判用哪个模型由你选,而且不应该是被测的那个模型。
接着 Claude 给少量样例打分,然后问你:有没有哪个你会打不一样的分?原文强调,相信一个评分器之前,一定要读一部分打过分的记录;评分出错是评测配置错误里最常见的一类。
第三步:跑基线
评分器确认后,它会告诉你这套评测的规模(样例数 × 重复次数 × 模型数,以及大概要多久),然后跑基线,输出带置信区间的分数。
你会得到:样例、评分器、运行脚本、每个样例一行 JSON 和一份完整记录,还有一个列出每个样例得分并链接到记录的页面。想看图表之类的,可以再让 Claude 做一个页面。这些页面默认是在本地打开的静态文件,不从网络加载任何东西。
跑基线时它会顺带做三项检查:
- 评分器:同一份输出打两次分,看结论变没变。
- 管道:检查超时、API 错误、被截断的回答,避免基础设施的噪声被当成模型的波动。
- 提升空间:基线已经在 95% 左右或更高时,它会提醒你,接下来的爬坡应该去探索成本或延迟,而不是质量。
爬坡前要想清楚的三件事
有了可靠的打分办法,才谈得上改进。原文给了三条选择“对什么爬坡”的建议:
- 改起来便宜。 很多内部项目和客户把爬坡集中在文字上,比如提示词和 skill,容易改也容易撤回。相比之下,放开让它改代理的整套外围代码,可能牵涉大量代码改动。
- 分数的变化说得清来源。 比如有几个成功的例子集中在 skill 的触发上:评测指标是 skill 的触发率,被修改的是 skill 的描述,两者直接挂钩。
- 目标要明确。 常见的失败是开放地要求“提升效果”,却没考虑评测还有多少空间。评测接近饱和,或者范围太大,都容易停滞。一个普遍好用的目标是成本:即使评测已经饱和,也可以让 Claude 在效果持平的前提下想办法降成本。
过拟合
设计得再好的评测,也很少和实际使用的任务分布完全一致。所以“对评测过拟合”很常见:系统在评测上比在真实流量上表现好。
原文的例子:某个评测任务用 OCR 会更好,但你的实际任务里 OCR 很少有用。爬坡时可能给应用加上一个 OCR 工具,评测分数涨了,实际使用没有任何变化。更一般地说,爬坡可能加进一些只为应付这几个样例的边角情况的功能。
三个办法:
- 把样例分开。 一份训练集,爬坡时可以读;一份测试集,从不给它看。训练集的分数涨了而测试集持平,就是常见的过拟合信号。
- 不要把失败的内容贴进提示词。 爬坡的代理可以读失败的记录,但不应该把其中的内容粘进提示词。
- 让答案在结构上就够不着。 模型有时会直接去找评测的答案来“刷分”。
hillclimb:对着评测改进
运行时你可以选它能改哪些东西:
- 系统提示词;
- skill 或说明文件;
- 工具的描述;
- 模型、effort 等 API 参数;
- 外围代码。
它的流程:
-
问目标,分样例。 问你要优化什么(效果,或者效果不变时的成本),然后把评测集随机分成训练集和测试集。目标是成本时,它会考虑几个常见的成本来源:提示词缓存、提示词是否适合所选的模型、模型和 effort 的选择。
-
先检查噪声。 确认评测的噪声(分数纯靠运气能波动多少)小于你认为值得采纳的最小改进。不满足就告诉你,并建议增加重复次数或样例。
-
每轮只提一处改动。 读上一轮训练集的记录,提出一个补丁。它瞄准的是效果能超过噪声的改动:从根上修掉导致失败的行为(重写出问题的那一节,或者补一条缺的规则),而不是改某一行的措辞。
-
跑评测,决定留不留:
结果 处理 训练集和测试集都提高 保留 训练集提高,测试集持平 怀疑过拟合,撤回 出现退步 撤回 -
停滞时先归因。 分数两三轮不动,它会把剩下的训练集失败逐个读一遍,按原因分类。如果没有哪一个修复的收益能超过噪声,它也会提前这样做,并建议增加重复次数或样例。这一步能发现有歧义的样例、外围代码的错误和运行间的波动。只有真正的失败才进入后面的轮次。
-
收尾。 把你的代码留在测试集上表现最好的那个版本,报告测试集相对基线的结果和置信区间。如果提升在噪声范围以内,它会直说,并建议不要合并。
官方的两个例子
降成本:客服工单
对一个内部的客服基准运行 hillclimb,目标是降成本并提升效果。共 44 张工单,30 张用于搜索,14 张留出。
| 步骤 | 配置 | 搜索集上的决策准确率 | 每张工单成本 |
|---|---|---|---|
| 起点 | Opus 4.8,默认(high)effort | 74.4% | 4.6 美分 |
| 精简提示词,换模型 | Opus 5.5,low effort | 87.8% | 1.9 美分 |
| 降一档模型 | Sonnet 5,low effort | 88.9% | 约 1 美分 |
| 再改进提示词 | Sonnet 5,low effort | 98.9% | 基本不变 |
几点说明:
- 第一步“精简提示词”删的是:强制的工具调用流程、一个草稿步骤、互相矛盾的规则。这和本系列第五篇讲的是同一件事。
- 省下来的一部分来自 Opus 5.5 的定价:原文说输入和输出比 Opus 4.8 便宜 20%,缓存读取便宜 60%。
- 最后一步加的是分流规则和一处退款上限的交叉引用。
- 在从没参与搜索的 14 张留出工单上,最终配置得分 90.5%,原始配置是 78.6%,成本约为原来的五分之一。注意它比搜索集上的 98.9% 低,这正是要留出测试集的原因。
提效果:claude-api skill 自己
团队用一套从文档里整理出来的评测来测这个 skill 能不能正确写出调用 API 的代码。起点是 66%,爬坡的代理可以查阅文档和 SDK。
| 阶段 | 做了什么 | 分数 |
|---|---|---|
| 起点 | 66% | |
| 补内容 | 发现 skill 缺了八项功能的说明,补上 | 74% |
| 改错 | 修正 C# 和 Java 类型表里的错误 | 77% |
| 停滞后归因,改结构 | 见下 | 80% |
| 修评测本身,继续改 skill | 见下 | 约 88% |
停滞两轮后的归因带来了两个发现:
- 内容在,但模型没照着写。 skill 里有正确的内容,Claude 却在写旧的 API 写法,来自它训练时的印象。对策是在 skill 靠前的位置加一张表,把它记得的旧写法对应到现在的写法(比如固定 token 预算的扩展思考改成自适应思考),并把 C# 和 Java 里“不要用固定预算”的警告挪到示例的上面。
- 怎么改都不涨的题,往往是题或评分器有问题。 一道题要求的代码只捕获一种错误,评分器却要至少三种的链条,Claude 改了题目的措辞。另一个评分器的说明和文档矛盾,用真实的 API 测试后证明文档是对的。
对你有什么用
只是用 Claude Code 的人:
- 你写的 skill 该触发时不触发,就是一个现成的、适合爬坡的问题:指标是触发率,改的是描述。
- 第一个例子给了一个实际的省钱顺序:先把提示词里多余的、矛盾的规则删掉,再试低一档的 effort,再试便宜一档的模型,每一步都用数字确认效果没掉。effort 怎么选见本站的 Claude Code effort 和成本教程。
在用 Claude API 做应用的人:
- 先建评测,再改东西。没有评测时,“换了模型感觉变好了”不可靠。
- 相信分数之前,亲自读一部分打过分的记录。
- 永远留一份测试集不给优化的过程看,最后只报测试集上的数字。
- 提升在噪声范围以内,就当作没有提升。
- 某道题怎么都不过,先怀疑题和评分器。