你发布了一个模型升级。评估套件的分数从 87% 提升到了 91%。更新日志信手拈来,领导层纷纷鼓掌,然而那些真正重要的仪表盘——用户满意度、工单升级率、点踩率——却毫无动静。毫无起色。甚至可能略微变差了。
这是 AI 工程中最令人迷惑的失败模式之一,因为表面上没有任何东西坏掉。评估运行正常。数字是真实的。在你测试的 600 个示例中,模型确实有所改进。问题在于,这 600 个示例是你构建套件那一周的流量快照,而在那之后的几个月里,你的用户已经走出了画面。
评估集并不是对质量的衡量。它是对特定输入分布下质量的衡量。当你引用一个基准测试数字而不说明其计算分布时,就相当于在报告温度却不说明温度计放在哪里。数字很精确,数字也毫无用处,而在这两个事实之间的鸿沟,正是数周工程心血无声消失的地方。
生产流量是河流,而非湖泊
当你组建评估集时,你会从用户当时的活动中采样。你对它进行整理、标注、冻结,并将其提交到代码库。从那时起,它就是一个静态的制品。它不再改变。
但你的用户并不会表现出同样的“礼貌”。生产流量是一条流动的河流,它至少以三种不同的方式在移动。
它移动是因为用户发现了新的用例。你为重置密码和账单问题构建了一个支持智能体。六周后,人们开始往里面粘贴完整的错误日志,并要求它诊断集成问题。没人在意许可。流量组合在你眼皮底下发生了偏移,而你的评估集仍然认为它的任务是重置密码。
它移动是因为用户抛弃了旧的模式。曾经占评估集 30% 的查询类型,现在可能只占实时流量的 4%,原因可能是你发布了一个无需模型即可处理该问题的 UI 更改,或者是因为竞争对手教会了用户用不同的方式来表达。你的评估仍然花费 30% 的权重去给一个几乎没人问的问题评分。
它移动是因为用户进行对抗性的边界探测。并不总是恶意的——通常只是出于好奇。他们找到了让模型困惑的措辞,并且因为这种困惑很有趣,所以他们会一直这么做。生产中的难题会随着时间推移而累积。而你评估集里的难题,在编写它们的那天就被固定在了琥珀中。
因此,基准测试的提升衡量的是用户早已离开的分布上的进展。这确实是提升,但它只是发生在了一个空无一人的地方。
当满意度下降时,套件依然显示绿色
这种情况最危险的版本是无声的。没有警报,没有失败的 CI 检查,没有红色的数字。评估套件处于通过状态。它甚至比以前通过得更干脆。那个绿色的勾号正在造成实质性的损害,因为它是领导层用来判断 AI 功能是否健康的依据。
算一笔账。假设在你构建评估集时,它对生产流量的代表性为 85%。每个月,偏移都会侵蚀这一点——新的用例、废弃的模式、改变的措辞——让代表性下降几个百分点。两个季度后,也许只有 55% 的评估内容仍能反映用户的实际发送。你那 91% 的得分,现在只是基于略多于一半的现实情况,而剩下的部分全靠运气。
与此同时,你的评估不再覆盖的那一半生产流量,恰恰是增长的那一半,因为增长本身就是导致偏移的原因。评估最明亮的地方,恰恰是活动最稀薄的地方。有团队报告称,模型在静态套件上表现良好,同时却在悄无声息地积累细微的答案退化、缓慢的检索衰减和边缘案例幻觉——所有这些在汇总数据中都是不可见的,因为汇总数据是基于陈旧输入计算出来的。
你不会收到警报。你会看到一系列看起来正常的每周评估报告,以及来自真实人类指标的缓慢、难以归因的下降。等到有人将这两者联系起来时,评估套件已经失去了公信力,而重建对一个数字的信任比重建数字本身要难得多。
幸存者陷阱:你的评估过度代表了已解决的问题
还有第二种更微妙的扭曲,它是一种幸存者偏差。
当你构建评估集时,你倾向于在其中填充你可以自信标注的查询。你需要一个标准答案(ground-truth)来进行评分,因此你会倾向于那些有清晰、可验证答案的问题——而这些问题往往是当前模型已经处理得很好的。那些真正困难、模糊、甚至不知道答案在哪里的查询更难标注,因此它们要么被采样不足,要么被悄悄丢弃。
结果就是一个偏向已解决问题的评估集。这在机器学习领域相当于通过研究返航的轰炸机来决定在哪里加装装甲:你看到的是那些成功返航的飞机。进入你评估集的查询就是那些“返航”的、易于标注的部分。而那些“坠毁”的——混乱的、新奇的、真正令人困惑的输入——从未进入数据集,因此评估无法察觉它们。
这使得新模型版本在特定方面看起来比实际更好。模型升级对那些已经接近决策边界的输入改进最大——即将边缘案例推向正确一侧。你的评估集中充满了这类案例,因为“处于边缘但可标注”恰恰是它的最佳位置。因此,升级显示出了可喜的增量。但用户感到痛苦的输入,是那些远超边界、深陷于你评估从未采样过的区域的输入。模型在那里可能根本没有改进。基准测试无法告诉你这一点,因为它从未关注过那里。
幸存者偏差加上分布偏移是一个复合错误。前者说明你在测试错误的输入;后者说明即使在正确的输入中,你也过分看重了简单的那部分。两者结合,会产生一个表现积极、自信满满但完全错误的评估。
定期对河流采样
解决办法不是搞一个更好的、一次性的评估集。任何静态集合,无论构建得多么精细,从你固定它的那一刻起就开始失效。解决办法是将评估集视为一个动态演进的产物,跟踪流动的河流,而不是捕捉瞬间的照片。
具体来说,这意味着按照固定的周期将生产环境的实时流量采样到评估集中。选择一个节奏——对大多数产品来说,每周或每两周是合理的——在每个周期提取一份真实用户输入的新样本。通常的做法是对生产环境的一小部分(每个端点约为 1–5%)进行随机采样,并进行分层处理,这样那些罕见但重要的查询路径就会被赋予更高的权重,而不是被高流量的主体所淹没。
以下几点能让这一做法在实践中落地,而非流于理论:
- 分层采样,而不仅仅是随机打乱。 纯随机采样会被你最常见的查询类型占据,而这些类型通常也是模型已经处理得很好的。按用例对流量进行分桶,并在桶内采样,这样长尾部分才能真正得到体现。
- 清理和添加一样要果断。 更新意味着丢弃旧例子,而不仅仅是追加。一个只会增长的评估集会变得缓慢、昂贵且依然陈旧——只不过多了几个步骤。如果某个查询模式在实时流量中已缩减为涓涓细流,其在评估中的权重也应随之下降。
- 为标注预留预算。 新的生产样本需要真值(ground truth),这是真实的、需要人工或模型辅助的工作。如果你无法承担标注成本,就减少采样频率,但绝不要从不采样。一个小而新颖的评估集胜过一个巨大而僵化的评估集。
- 保留一个固定的回归核心集。 专门留出一部分稳定的子集,以便你 可以 检测跨版本的回归。重点不是扔掉所有历史——而是停止让历史成为整个数据集。一个充满活力的套件应该是由不断更新的大多数加上一个固定的锚点组成的。
这就是“作为照片的评估”与“作为视频流的评估”之间的区别。照片只拍摄一次,且老化很快。视频流虽然总是比实时慢一点,但它始终对准着河流。
按分群和时效性切分分数
即使是一个新采样的评估集,如果你只看单一的聚合数字,它也会对你撒谎。聚合指标是漂移(drift)隐藏的地方。要看清你的基准测试收益到底换来了什么,你必须对其进行切分。
按**查询分群(query cohort)**切分。将评估集分解为用户实际行使的用例——计费、诊断、操作指南、开放式聊天——并报告每个分群的分数。一个让总分提升 4 个点的模型升级,可能让一个分群提升了 12 点,却让另外两个分群各下降了 3 点。聚合数字隐藏了回归,而切分暴露了它。这也直白地告诉你,收益到底落在了 哪里 ——以及那是否是用户关心的分群,或者仅仅是你的评估集碰巧权重过高的地方。
按**时效性(recency)**切分。为每个评估示例标注其进入集合的日期,并分别计算最新样本群与最旧样本群的分数。如果你的模型在去年添加的示例上得分为 94%,但在上个月采样的示例上得分为 73%,那么你已经直接测量到了你的漂移。这 21 点的差距 就是 评估与生产环境之间的分布差距,它是量化了的。这是你的评估能带给你的最诚实的一个数字,而单一的聚合分数永远不会展示这一点。
当你以这种方式切分时,“基准分数上升了”就不再是一个允许你说的句子。你必须说明是哪个分群、在哪个时效范围内上升了,以及那是否是用户所在的区域。这是一个更高的标准,而达到这个标准正是整件事的意义所在。
评估是对你流量的一种假设
跳出技术细节,更深层的问题是观念上的。团队将评估套件视为真值(ground truth)——一个衡量模型的固定标准。其实不然。评估集是一个假设:一种宣称“这一组输入类似于我们的用户将发送给我们的内容,且权重也与他们发送的方式一致”。
这个假设在编写它的那天可能是正确的。但在那之后的每一天,它的正确性都会降低一点,因为其描述的对象在不断移动,而描述本身却没有。一个未更新的假设不会保持中立。它会腐烂成虚构——一种自信、格式良好、经过版本控制的虚构,而整个组织都在根据它做决策。
组织层面的失败才是代价高昂的。当领导层根据基准测试的增量进行发布、根据它分配下个季度的路线图、并告诉客户产品变得更好了——而这一切都是基于几个月前用户留下的流量计算出来的数字时——代价不仅仅是一个浪费掉的版本。它是对评估本身信任的缓慢侵蚀,直到“评估分数上升了”对房间里的任何人都不再有任何意义。
因此,像对待关于这个不断变化的世界的其他假设一样对待你的评估集:制定更新计划,对聚合指标保持怀疑,并假设它已经有些过时了。对河流采样。切分分数。按日期标注示例并观察时效性差距。下次基准分数上升时,在你写发布日志之前,问一个唯一重要的问题—— 这是在谁的流量上上升了,那些人还在吗?
会员专享
余下内容仅对会员开放。
会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
- —完整文章,包含未公开存档的部分
- —可落地的工作框架,附带权衡与决策依据
- —新文章抢先看,先于公开发布
随时取消 · 一次订阅,畅读全部