Hex 用 evals 将 AI 错误编辑率降低 7 倍
Using evals to cut AI errors 7x
Hex 在开发 Quick Edits 功能时用 evals 驱动开发,把错误编辑率从 21% 降到 3%。该功能用 GPT-6 Luna 或 Claude Haiku 4.5 等小模型一次性完成图表样式修改,复杂请求则交给 Hex agent。
Hex 的生成式应用让你可以通过与 Hex 智能体聊天来构建完全自定义的数据应用。上周我们推出了 快速编辑,它使用一个小模型,让你以比完整智能体快 20 倍、成本低 20 倍的速度重新设计图表样式。
我们在 Hex 构建 AI 功能时使用评估已有一段时间。当模型输出具有非确定性时,评估是判断某项改动是否真正让功能变好的唯一可靠方法。我们在快速编辑上采取了不同的方法:从一开始就用评估来驱动其开发,而不仅仅把它当作最后的 QA 步骤。
最初,我们编写了几百个评估用例,随着功能演进,最终创建了 1800 个用例。然后,编码智能体针对这些评估测试了数百项改动,只保留得分更高的那些。这个过程被称为爬山法,将我们的错误编辑率从 21% 降到了 3%。令人惊讶的是,大部分收益来自模型周边的测试框架,而不是提示词。
如果你有兴趣采取类似的方法,Anthropic 的评估设计与爬山法指南是一个不错的起点。以下是我们除了他们分享的内容之外,对我们有效的做法:
从产品体验出发
功能如何工作
快速编辑使用一个小模型(GPT-6 Luna/Claude Haiku 4.5)来读取用户的请求——比如“把 Enterprise 线变成绿色”——并一次性提出对图表属性的编辑建议。
如果用户的请求过于复杂——比如“为什么数字没有涨上去???让它们涨上去!”——它就会移交给 Hex 智能体,由后者对应用进行更复杂的更改。
我们的评估专注于确保小模型能正确处理这些编辑和移交。
选择正确的优化指标
我们的功能,以及因此我们的评估,可能以两种方式失败:
- 错误编辑:进行了用户没有要求的编辑。
- 错误移交:将本应由小模型处理的请求移交给了 Hex 智能体。
人们很容易想要同时最小化这两种失败,并最大化整体通过率。但对于这个功能来说,最小化错误编辑比最小化错误移交重要得多。
错误编辑会以用户没有要求的方式改变用户的图表,这很突兀,会侵蚀信任。错误移交只是导致主智能体更慢地做出正确编辑,这没那么糟糕。
例如,我们采用了 GPT-6 Luna,尽管它的整体通过率比 GPT-5.6 Luna 低约 1 个百分点,但它的错误编辑少了 20%,成本只有一半。
当我们开始爬山时,我们的“错误编辑”率是 21%,到最后降到了 3%。在面向客户的真实使用中,我们预计错误编辑率会远低于此——我们有意让评估尽可能具有挑战性。
从真实使用中编写评估,然后扩展
丰富的评估用例
我们构建了一套超过 1800 个评估用例,最初从内部用户的真实图表编辑请求中提取了几百个。我们想要人们所要求的那类编辑示例,以及他们使用的具体词语(和语言)。
我们将这些核心用例扩展,以覆盖我们想要处理的所有不同类型的图表编辑(和移交)。
我阅读了前约 150 个合成用例并给出了反馈,这足以让 LLM 出色地合成其余部分。
我让 GPT-6 Astra 生成新用例,并使用 Claude Fable 5.1 填补任何空白。使用多个模型让我们确信这些示例是多样且全面的。
我们确保许多测试用例既困难又模棱两可,这给了我们更多可用来爬坡优化的空间。我们想测试模型能否分辨哪些请求该自己处理、哪些该转交。几个例子:
- “让它更吸睛” → 转交(没人知道这是什么意思,模型也不知道)
- “改成每周” / “hazlo semanal” → 转交(这是伪装成样式改动的数据改动)
- “隐藏图例,只显示 2025” → 转交,尽管其中一半是可做的(部分编辑比不编辑更糟)
- “把所有线条都改成灰色,除了加拿大,隐藏图例并把线条加粗” → 三项全部执行(并且不要动加拿大的颜色)
- 在水平条形图上“把 y 轴格式化为美元” → 转交(因为那里的 Y 轴是分类轴)
处理 fixtures
每个评估用例都包含“用户请求”和一个“fixture”——即我们随用户请求一起发送给模型的图表上下文。
对于这个功能,fixtures 以 JSON 表示图表的起始状态,包括之前的编辑,以处理诸如“不,我更喜欢原来的颜色”这样的提示。
像这样的 fixtures 可能出奇地复杂和详细,也更难制作。我们使用了约 50 个基础图表,并配有许多变体和编辑历史,同样受真实使用场景启发,并由 Astra/Fable 扩展。
测试框架比提示词更重要
验证器 > 提示词
验证器是一段代码,在我们用模型输出编辑图表之前,它会检查并清理这些输出。
例如,模型可能返回了正确的十六进制颜色,但漏掉了我们代码期望的引号。尽管模型已经理解了请求,我们之前还是会拒绝这些响应。我们修改了验证器以接受它们。
出乎意料的是,我们爬坡优化中超过 50% 的改进来自扩展验证器以处理更多几乎正确的输出,例如:
- 修复小的格式错误,比如缺少引号,或返回值类型错误
- 将数字舍入到最接近的允许值
验证器还会强制执行模型可能弄错的规则:最小值低于最大值、ISO 日期、某个属性是否真的能在此图表上生效……
验证器的改进使 Luna 的通过率提高了 7 个百分点,Haiku 提高了 10 个百分点。它们将 Haiku 的硬错误(我们的代码无法接受的输出)减少了 99%!
我们学到的一个反直觉的教训是,提示词改动的影响远没有我们预期的那么大。绝大多数纯粹的提示词微调都未能通过我们的评估。事实上,我们最终把一些内容从提示词中拿掉,放进了验证器,或者放进了模型读取的图表属性描述和标签中。
例如,模型经常混淆水平图表的坐标轴。在相关属性标签中加入“(x axis)”并改进其描述,帮助它选择了正确的设置。我们之前无法通过提示词改动解决这个问题。
处理不同模型
我们同时评估了 Luna 和 Haiku,以确保任何调整都能在多个提供商的多个模型上良好运行,从而保证无论客户使用何种模型配置,此功能都能正常工作。
例如,我们最初有一个“无更改”选项,让模型表示图表已经符合请求。Luna 处理得很好,但 Haiku 过度使用它,错误的“无更改”响应比正确的多出 30 倍。这是另一个我们无法通过提示词修复的行为示例;我们移除了该选项,并将这一逻辑改放进验证器。
确保改进是真实的
“留出”用例以避免过拟合
根据我们的经验,让执行爬山优化的智能体看不到足够数量的评估用例至关重要,这样它才不会过拟合(针对你的评估过度优化)。没有这些留出用例,就像学生死记硬背练习题的答案。他们也许能通过考试,但题目一变就吃力了。
我们的留出用例几乎占评估套件的 40%。只有当留出结果改善时,我们才接受所提议的更改。
调优噪声与尝试次数
你还需要考虑确保高质量评估数据需要付出什么。在我们的案例中,我们发现每个用例只运行 3 次尝试噪声太大。重新运行同一套件的结果相差约 8 处错误编辑。每个用例 10 次尝试对我们来说是恰到好处的平衡点,将留出噪声降至 0.2 个百分点。
值得让智能体把同一评估集重新运行几次,看看结果变化有多大,然后再做任何更改。
快速评估意味着更快的产品迭代
即使每次完整运行有 18,000 次尝试(1,800 × 10),在 Luna 上一次运行的成本也不到 10 美元,在高并发下只需几分钟。
这意味着评估不只是最后一步。我们对功能每个部分的每次更改后都会运行它们:提示词、验证器、图表属性、交接规则、用户体验。
在爬山优化运行期间,我们在十天内三次更改了图表的底层属性。每次我们都重新运行套件,并能立即看到是否有任何东西被破坏或需要改进。
反过来也一样。当模型总是出错时,修复往往不在提示词里。我们重命名一个属性、添加一段描述,或更改一条交接规则,然后重新运行以检查是否有帮助。
我们同时针对同一套评估,对 AI 和功能的其余部分进行迭代。
产品体验应驱动你的评估
我们把评估用例、夹具、用于爬山优化的指标以及其他一切,都扎根于我们今天看到人们使用 Hex 的方式,以及我们希望为他们实现的产品体验。
所以,如果你正在构建评估,我的总体建议是仔细思考那种产品体验,并以此为基础设计你的评估。
(另外,欢迎复制这篇文章并粘贴到你的智能体中,这样它也能利用我们学到的东西。)
来源:Hacker News · hex.tech