跳到正文
北京时间
原文
Anthropic:Claude.dev 开发者博客· Lance Martin·· 3 天前精选AI 评分67

Anthropic 介绍用 Claude Code 与 claude-api skill 自动化评测设计与 hillclimbing

Automating eval design and hillclimbing with Claude

AI 导读

Anthropic 在 claude-api skill 中新增 /claude-api build-eval 和 /claude-api hillclimb 两个命令,前者在代码库内通过访谈式流程构建评测集并验证 grader,后者以一次一改动、train/test 分离并检测过拟合的方式迭代优化应用。

推荐理由

Anthropic 官方讲解了评测设计的关键原则,并给出 build-eval 和 hillclimb 两个命令的用法与真实优化案例,可迁移到自己的应用调优。

正文 · AI 翻译

评估能提供信号,反映你的应用或技能在特定任务上的表现。但设计评估,并在不欺骗自己的前提下提升其表现,并非易事。我们为这两方面都添加了指导,收录在 claude-api skill 中。

借助该技能,你可以运行 /claude-api build-eval 在你的代码库中构建评估,并运行 /claude-api hillclimb 针对它改进你的应用,一次一个改动,同时用一组留出的示例来捕捉过拟合。

在本文中,我们首先重点介绍良好评估设计的原则和爬山法,然后展示 Claude Code 配合 claude-api 技能如何应用这些原则。最后,我们会展示这些命令的几个示例。

评估设计

设计良好的评估有几个共同要素(图 1):

  1. 评估任务要反映生产环境。 采样你在“生产环境”中关心的任务,即你所测试的能力或应用将被使用的场景。有时任务被选中是因为它们容易生成或容易评分。但重要的是确保任务分布代表你真正关心的内容。
  2. 性能随更强的模型和更多的思考而提升。能力更强的模型和更高的努力程度通常应在评估中表现更好。如果不是这样,模糊的任务或校准不当的评分器往往在拖累性能。
  3. 前沿存在“可通过”的提升空间。能力最强的模型在最高努力程度下,在评估中的表现应远低于 100%,否则你无法可靠地判断改动如何影响性能。重要的是,这一差距不应由不可能或模糊的任务来解释:一个常见的迹象是,无论重复多少次,某个任务在每次评估运行中都失败。好的任务是两位领域专家会得出相同结论,且评分器检查的一切都在任务中明确说明。
  4. 运行间方差低。高方差通常源于设计不佳、模糊的任务,或对相同输出给出不同判定的评分器。方差也可能隐藏在配置中。例如,努力程度可能未被一致地应用。此外,环境也会影响评估结果:先前试验遗留的状态(一个文件、一段 git 历史)可能把答案直接交给智能体。
Score against action tokens per attempt for a smaller, a mid-size and the most capable model at low, medium and high effort. Numbered callouts mark the four elements: scores rise with a more capable model and with higher effort, the top line stays below a perfect score, and the error bars stay tight.
图 1良好评估的四个要素

对抗性采样

模型能力参差不齐。如果你因为今天的模型在这些案例上失败而挑选它们,你就是在采样某个模型能力曲面的低谷(图 2)。评估最终可能衡量的是该模型的失败指纹,而非对你的应用而言本质上困难或有价值的内容。

Two panels plotting capability across task space, each with today’s model as a jagged curve and the next model as a smoother curve above it. On the left, cases sampled where today’s model fails sit only in its valleys; on the right, cases a person judged hard are spread across peaks and valleys, with a few should-not-fire cases.
图 2对抗性采样

挑选困难案例,是因为人类判定它们困难:一个有用的测试是,在纳入某个任务之前,你能说出它为什么困难。纳入源自生产流量、缺陷报告或工单中你应用的具体失败案例。然而,不要盲目信任用户流量:用户有时会尝试他们预期能奏效的东西,因此严格从用户流量中抽取的任务分布可能偏简单。

/CLAUDE-API BUILD-EVAL

claude-api 技能中的 build-eval 命令将这些原则转化为引导式工作流。当你在 Claude Code 中运行 /claude-api build-eval 时,Claude 会采访你,在你的代码库中构建评估,并在特定节点暂停等待批准。

设计示例

Claude 按以下顺序帮助你采样输入以构建评估:

  1. 生产环境转录文本,在询问保留策略和敏感数据之后。
  2. 错误报告和支持工单。
  3. 你手写的五到十个案例。
  4. 从你的代码库合成的案例。

该技能优先使用生产流量,但也可以基于你提供的少量真实示例生成合成数据。该技能会指示 Claude 生成一个简单页面,向你展示每个输入,并等待你确认。作为示例,下面我们展示了一组该技能可能要求用户审阅的电子邮件路由应用输入示例(图 3)。

The skill’s review page for an inbox-routing eval with 24 inputs, listing each case’s email text with tags such as billing, easy and ambiguous. Beside it, Claude asks in chat whether the inputs are representative, and the user answers yes.
图 3该技能生成的示例输入审阅

验证评分器

在输入之后,Claude 会提出最适合你应用输出的最廉价评分器:

  • 程序化验证:如果输出可能性受限,它会使用基于代码的检查(精确匹配、来自固定集合的标签、符合 schema 的 JSON、通过的测试)。
  • LLM 作为评判者:如果输出空间是开放式的,有许多有效答案但有明确的质量标准,它会默认使用这种检查方式。在这种情况下,第二个模型会读取输入、输出以及一份写成可检验声明(而非 1 到 5 分制)的评分标准,并返回分数及其推理。如果你有可比较的基线,评判者则会以随机顺序读取两个输入,不被告知哪个是基线,然后选出更好的那个。评判模型由你选择,且不应是你正在测试的模型。

Claude 会对少量案例进行评分,并询问你是否会对其中任何案例给出不同评分(图 4)。一般来说,在相信你的评估器之前,阅读一部分已评分的转录文本样本很重要;评分失败是评估配置错误最常见的方式之一。

当你验证了评分器后,该技能会告诉你评估集的规模(案例数 × 重复次数 × 模型,以及大致需要多长时间),运行基线,并打印带有置信区间的分数。你会得到:案例、评分器、运行器、每个案例一行 JSON 和一份完整转录文本,以及一个列出每个案例分数并附有转录文本链接的简单页面。如果你想要该页面展示之外的内容(例如图表),只需提出要求,Claude 就会在它旁边构建一个额外页面。默认情况下,这些额外页面是静态文件,在本地打开,不从网络加载任何内容。

The skill’s results page for the inbox-routing eval: a baseline scoring 0.681 mean correct across 24 cases, then a table of per-case scores with a link to each repetition. A rep link opens that case’s raw JSON trace, shown alongside.
图 4生成的结果页面示意图,包含为每个输入建议的评分。

诊断检查

在上述基线运行期间,Claude 会检查若干事项:

  • 评分器:Claude 对同一输出运行评分器两次,并报告判定是否发生变化。
  • 管道:Claude 检查超时、API 错误和截断的答案,以确保基础设施噪声不会被当作模型方差。
  • 余量:如果基线已经得分约 95% 或更高,该技能会警告用户,并提示爬山应旨在探索成本或延迟,而非质量。

爬山

现在你已经有了一种可靠的方法来评估你的应用在任务上的表现,你可以尝试改进它。爬山是调整努力程度或提示等参数的有效方法,这些参数会在成本和性能之间权衡。关于选择在哪里应用它的一些通用建议:

  • 低成本迭代 - 修改你用于爬山优化的目标表面应当成本低廉(在时间、成本和精力方面)。许多内部项目和客户都将爬山优化聚焦于文本,例如提示词和技能。这些内容易于修改和回滚。相比之下,在爬山优化过程中对智能体框架进行开放式修改可能涉及大量代码改动。
  • 可归因 - 评估分数的变化应当可归因于你在爬山优化过程中所修改的表面。例如,若干成功的爬山优化应用都聚焦于技能触发。评估指标(技能的触发率)与被修改的技能描述直接耦合。
  • 目标范围明确 - 一种常见的失败模式是提出开放式请求来提升性能,却没有仔细考虑评估中可用的提升空间;接近饱和的评估或范围界定不清的表面(例如,开放式请求更新框架)更有可能陷入停滞。在各种尝试中,一个普遍有效的目标是成本:即使评估已经饱和,你也可以要求 Claude 在保持性能持平的同时寻找降低成本的方法。

过拟合

即使是精心设计的评估,也很少能完全匹配你在生产环境中真正关心的任务分布。因此,对评估的"过拟合"是一个常见问题,会导致系统在评估上的表现优于在生产流量上的表现。

评估有多种方式可能"泄漏"到你的框架中(即模型周围的代码,包括提示词、工具以及调用 Claude 的循环)。例如,假设某个评估任务能从 OCR 中获益,但 OCR 在你的生产任务中很少有用。评估框架可能会向你的应用添加一个 OCR 工具,从而提升基准测试成绩,但对生产毫无影响。更广泛地说,爬山优化可能会向框架添加一些特性,以应对你所选定的特定评估示例中的边缘情况。这些框架新增内容提升了你的评估分数,但并不能转化为生产环境的改进(图 5)。

The benchmark’s traits on the left, each shaping a matching addition to the harness on the right: a task mix that needs OCR adds an OCR tool, tasks in /app add “always cd /app, run pytest”, distinctive phrasings get a tuned prompt, and failures you’ve read get one patch each. A dashed arrow marks the outright leak: a public repo with answers lets the harness curl the reference solution.
图 5框架过拟合的常见原因。

有三件事可以帮助解决这个问题:

  • 拆分用例。使用一个爬山优化器可以读取的训练集,以及一个从未被查看过的测试集。如果训练集分数提升而测试集分数持平,那么这就是一个常见的过拟合警示信号。
  • 永远不要把失败案例粘贴到提示词中。如果爬山优化器读取了失败的记录,它绝不应将失败内容粘贴到提示词中。
  • 让答案在结构上处于模型无法触及的范围。模型有时会通过直接找到评估答案来进行"奖励黑客"。

如下文所述,claude-api 技能会为你应用这些原则。

/CLAUDE-API HILLCLIMB

claude-api 技能中的 hillclimb 命令将这些原则转化为一个引导式工作流。当你在 Claude Code 中运行 /claude-api hillclimb 时,Claude 会针对给定的评估进行迭代改进。你可以选择它能够做出哪些更改,包括:

  • 你的系统提示词
  • 技能或指令文件
  • 工具描述
  • 模型选择、努力程度以及其他 API 参数
  • 你的框架代码

在开始之前,Claude 会询问你想要优化什么(例如性能,或在保持性能的同时优化成本),然后随机将评估集拆分为测试集和训练集。如果目标是成本,它会考虑几个常见的成本驱动因素,包括提示缓存、审查提示与所选模型的兼容性,以及选择模型和努力程度设置。

在第一轮之前,Claude 会检查评估的噪声(仅凭偶然因素分数可能波动的幅度)是否小于你会采取行动的最小改进幅度;如果不是,它会说明这一点,并建议增加重复次数或案例数。

每一轮,Claude 都会阅读上一轮训练集的记录,并作为补丁提出一项更改。它每轮都瞄准一个效果能超出评估噪声的更改:它从根源上修复失败行为(例如重写导致问题的部分或添加缺失的规则),而不是改写某一行。然后它运行带有该补丁更改的评估。此时,Claude 会应用一项检查:如果 train 集有所改善,但 test 集没有变化,Claude 会怀疑过拟合并回滚该补丁。如果出现退化,Claude 会回滚。如果训练集和测试集都有改善,则保留该补丁(图 6)。

The hillclimbing loop: the thing being edited, such as a prompt, feeds a fixed model and harness that is scored on a held-out test split and a train split. An analyzer reads only the train failures and proposes one diff per round; the diff is kept when train and test both rise, and reverted when only train rises or either score drops.
图 6爬山法所使用的过程。

当分数连续两到三轮停滞不前时,Claude 会阅读每个剩余的失败训练案例,并按原因分类。如果没有任何单一修复能带来超过评估噪声的收益,它也会提前这样做,并建议增加重复次数或案例数,而不是把轮次花在太小而无法衡量的更改上。这一步可以捕捉到模糊的评估案例、测试框架错误或运行间差异。

只有合理的失败才会被纳入更多的爬山轮次。

当爬山完成后,Claude 会将你的代码保留在针对你的目标在测试集上表现最好的版本。它会报告相对于基线的测试结果,并附上置信区间(图 7)。如果收益在噪声范围内,它会说明这一点,并建议不要合并。

The inbox-routing results page after hillclimbing, comparing three variants on train and test scores. Variant v1, which defines each queue and adds a tie-break rule, is marked best at 0.875 on both; v2, which adds two worked examples, was reverted because train went up while test stayed flat.
图 7爬山后生成的报告示意图。

示例

用于降低成本的爬山法

我们在一个内部客户支持基准上运行了 /claude-api hillclimb,目标是降低成本并提升性能。该基准包含 44 个工单,其中 30 个用于搜索,14 个留出。它从 Opus 4.8 开始,使用默认(高)努力程度设置,在搜索工单上的决策准确率为 74.4%,每个工单的 token 成本为 4.6 美分。

爬山法首先审查了提示,移除了强制性的工具调用仪式、一个草稿步骤以及相互矛盾的规则。然后它尝试了低努力程度的 Opus 5.5。这以 87.8% 的成绩通过了基线准确率门槛,并将成本降至每个工单 1.9 美分,不到起始成本的一半。

这一节省部分来自 Opus 5.5 的定价:输入和输出 token 的成本比 Opus 4.8 低 20%,缓存读取成本低 60%。由于 Opus 5.5 通过了门槛,爬山法随后降低一个层级,检查更便宜的模型是否也能通过。低努力程度的 Sonnet 5 得分大致相同,为 88.9%,成本约为一半,即每个工单 1 美分(图 8)。

Decision accuracy on the train split against cost per ticket, tracing the adopted path: from the Opus 4.8 high-effort baseline at 74.4% and just over 4¢, to Opus 5.5 at low effort, to Sonnet 5 at low effort near 1¢, and finally Sonnet 5 with an improved prompt near 100%.
图 8以成本为重点的爬山法。

最后,Claude 通过路由规则和退款上限交叉引用改进了提示,使 Sonnet 5 在成本大致相同的情况下达到 98.9%。在搜索从未见过的 14 个留出工单上,最终配置的得分为 90.5%,而原始设置为 78.6%,成本约为其五分之一。

通过爬山法提升性能

另一个例子是我们的 claude-api 技能,它提供了使用我们 API 的指导以及与 Claude 协作的通用技巧(包括本文讨论的子命令)。我们希望确保该技能能够正确实现使用我们 API 的代码,因此我们基于文档构建了一个评估集来测试该技能。

在我们的评估中,该技能初始得分为 66%。我们让爬山器访问文档和我们的 SDK,使 Claude 能够识别错误并自我纠正(图 9)。Claude 发现该技能遗漏了八项功能的覆盖。

在技能中为这些功能添加章节后,性能提升至 74%。随后它又发现了 C# 和 Java 类型表中的错误,将性能提升至 77%。

Pass rate across hillclimbing rounds on the claude-api skill’s eval, rising from 66.1% at baseline to 87.9% at round 24. Shaded phases mark the work: adding missing sections and type tables, then fixing how the skill tells Claude to write code, then fixing graders plus more skill edits.
图 9以性能为导向的爬山法。

在得分连续两轮停滞之后,Claude 分析了剩余的失败案例,并按根本原因对其进行了分类。普通轮次会针对最常见的失败做一次编辑。而这一步不做任何编辑;它只是按原因对每一个剩余失败进行排序。这一反思步骤在几个方面都很有用:

  • 通过反思一系列失败案例,爬山器发现技能内容本身是存在的,但 Claude 只是在写出较旧的 API 形式(例如,来自其训练先验的形式)。为了解决这个问题,爬山器在技能顶部附近添加了一个表格,引导 Claude 从它记忆中的形式转向当前的形式:例如,从使用固定 token 预算的扩展思考(API 现在在最新的 Opus 模型上已拒绝这种形式)转向自适应思考,以及从旧版本的网页搜索和网页抓取工具转向当前版本。它还将针对固定预算思考的 C# 和 Java 警告移到了各自的自适应思考示例之上。这将性能提升至 80%。
  • 那些尽管解决了明显的内容缺口却始终没有提升性能的任务,表明示例或评分器存在缺陷。有一个任务要求编写捕获一种错误类型的代码,而它的评分器却要求至少三种错误的链条。Claude 重新表述了该任务。另一个评分器的指令与我们的文档相矛盾,而测试真实 API 表明文档是正确的。解决这些问题,再加上更多的技能编辑,将性能提升至约 88%。

快速上手

这些子命令可以通过 claude-api 技能直接在 Claude Code 中使用:

如果你想为某个特定问题生成评估集,请运行 /claude-api build-eval。你可以通过提供对示例(例如,追踪记录)的访问来引导它。Claude 将运用本文中分享的指导来设计示例和评分器,并确保你批准这些示例和评分器。

如果你已有评估集,并希望 Claude 在你的目标(例如,更好的性能,或在保持性能的同时降低成本)指导下对其进行改进,请运行 /claude-api hillclimb。Claude 将运用本文中分享的指导,在爬山过程中检查过拟合,并检查评估本身的缺陷,例如将看起来正确的答案判为错误的评分器或测试框架错误,这些检查既会在第一轮之前进行,也会在得分停滞时进行。

特别感谢 Misha Khalman 在技能开发方面的贡献。感谢 Misha Khalman、Michael Segner、Matt Bell 和 Matt Thanabalan 的审阅、贡献和产品支持。

来源:Anthropic:Claude.dev 开发者博客 · claude.dev