跳到主要内容

将评估覆盖率作为生产指标:你的测试套件真的在测试用户实际行为吗?

· 阅读需 9 分钟
Tian Pan
Software Engineer

大多数 AI 团队把通过评估套件视为系统正常运行的信号。但事实并非如此——至少不全是。一个稳定得分 87% 的套件只做了一件事:告诉你系统在套件恰好覆盖的那 87% 的场景中表现良好。如果这套测试是六个月前手工整理的,基于团队能想到的示例,从未用真实流量更新过,那它正在以越来越高的置信度测量错误的东西。

这就是评估覆盖率问题。它与你的评估器是否准确无关——而是关于你测试集中的查询分布是否与用户实际发送的查询分布相匹配。当这两种分布出现偏差时,你会得到一个比评估失败更糟糕的结果:一个通过的评估,背后却是悄然劣化的产品。

为什么覆盖率是分布问题,而非数量问题

对评估覆盖率的朴素理解是数量:你有足够多的测试用例吗?但按数量衡量的覆盖率几乎毫无意义。你可以有一万个评估用例,却仍存在严重的盲点——如果这些用例聚集在同一个语义区域的话。

真正的问题是:你的评估集的查询分布是否近似于生产环境的查询分布?

想象一个 AI 客户支持智能体。在发布时构建评估套件时,用户主要询问账户设置和基础导航。八个月后,他们开始询问账单差异、集成错误,以及你在第三季度发布的新产品层级的边缘情况。你的评估集没有更新。模型处理新查询类型尚可,但并不出色——而你对这些查询毫无评估信号,因为它们根本不在你的套件中。由于大多数评估用例(旧的那些)仍然通过,总体分数看起来依然正常。

这就是覆盖缺口:你的评估权重集中的地方与用户实际流量所在位置之间的差距。

用聚类分析衡量覆盖缺口

衡量覆盖缺口最直接的方法是:对生产查询和评估查询进行向量化和聚类,然后比较生成的分布。

操作步骤如下:

  1. 采样生产流量,覆盖有意义的时间窗口——通常是 30 天,并进行分层抽样,避免过度代表周末与工作日模式或促销峰值等不反映稳态行为的情形。
  2. 使用同一嵌入模型对两个集合进行向量化。一致性很重要;混用不同的嵌入模型会引入噪声,掩盖真实的分布差异。
  3. 对生产查询进行聚类,使用 k-means 或 HDBSCAN(后者对查询集中密度变化的处理更好,尤其适合有大量异常输入的长尾场景)。选择有意义的粒度——中型生产系统通常为 20–80 个聚类。
  4. 将评估查询映射到这些聚类上,衡量评估集在每个聚类中的覆盖比例,并按各聚类的流量权重加权。

输出结果是一个覆盖热力图。有些聚类覆盖密集——你在该语义区域有大量评估用例。另一些则覆盖稀疏或完全为空。将聚类大小(代表多少生产流量)与评估密度(该区域有多少评估用例)交叉比对,可以精确定位你的盲点。

一个代表 15% 生产流量却包含零个评估用例的聚类,不是缺口——而是一个风险敞口。

Jensen-Shannon 散度作为覆盖分数

聚类热力图适合诊断,但你需要一个标量指标来随时间追踪并集成到仪表盘中。生产分布与评估分布之间的 Jensen-Shannon 散度(JSD)在此效果良好。

JSD 衡量两个概率分布的差异程度。应用于评估覆盖率时,你计算每个聚类在生产分布下和评估分布下的概率质量,然后计算这两个向量之间的 JSD。结果是一个 0 到 1 之间的数:

  • JSD 接近 0:你的评估分布与生产分布高度近似。覆盖率良好。
  • JSD 在 0.3–0.5 之间:显著偏差。你的评估集中于查询空间中与用户实际使用不同的区域。
  • JSD 超过 0.5:严重不匹配。你的评估套件主要测量的是不代表真实流量的查询类型。

将这一指标与总体评估分数一起随时间追踪。JSD 上升是覆盖缺口扩大的领先指标——你可以在用户开始投诉之前发现它。JSD 稳定但总体评估分数下降,意味着覆盖率没问题,但其他东西变了:模型、提示词或世界本身。

关键洞察在于,JSD 回答了大多数评估仪表盘从未浮现的问题:我们的评估套件还在问正确的问题吗?

用于评估刷新的流量分层采样

知道存在覆盖缺口只是成功了一半。缩小缺口需要建立一套从生产流量中刷新评估集的原则性流程。

从生产日志中随机采样是个开始,但这往往会过度代表高频查询类型——而这些类型可能已经被很好地覆盖——同时低估你真正存在盲点的长尾。应该使用聚类分层采样:

  • 对评估覆盖率低的聚类:积极采样,即使聚类较小。一个占 3% 流量却有 0% 评估覆盖率的聚类,比一个占 40% 流量且有 35% 评估覆盖率的聚类更迫切需要补充。
  • 对覆盖率良好的聚类:轻量采样以检测漂移,但不必过度投入。
  • 对极小聚类(占流量不足 0.5%):考虑将其归入"边缘情况"池,从该池整体采样,而不是把每个微聚类当作独立类别。

采样后,这些生产查询需要标注。第一轮标注无法避免人工审核——自动评估器可以对响应打分,但只有人类才能判断一种未被覆盖的查询类型是否应该加入永久评估集,以及正确或可接受的响应是什么样的。初次标注完成后,通常可以用初始批次的少样本示例自动化后续类似查询的标注。

对大多数团队来说,合理的节奏是:每周运行 JSD 覆盖分数,每月进行聚类分析,每季度或当 JSD 超过阈值时进行完整的评估刷新(合理的初始阈值是 0.25)。

复合失败场景

覆盖缺口对多步骤智能体和长上下文系统尤为危险,因为失败模式会跨轮次叠加放大。

如果你的评估套件对第一轮查询分布覆盖尚可,但无法反映真实用户追求的多轮序列,你就错过了整个失败维度。一个 20 步工作流,每步成功率 95%,端到端成功率只有 36%。逐步评估会显示健康的 95%——但用户实际的目标成功率只有 36%。

这里的分布问题不仅仅是哪些查询出现,还有哪些序列出现。生产流量在查询序列上有联合分布,你的评估套件需要反映这种结构,而不仅仅是单个查询的边际分布。

对于智能体系统,将聚类分析扩展到包含会话级特征:轮次数量、工具调用模式、每步的上下文长度,以及会话是以成功还是放弃结束。在这些更丰富的表示上聚类,能发现单轮查询分析完全遗漏的覆盖缺口。

覆盖感知评估流水线的样貌

成熟的评估流水线将覆盖率视为一等指标,而非事后补救。在实践中,这意味着:

  • 评估仪表盘中的覆盖分数:生产分布与评估分布之间的 JSD,与准确率、延迟和成本一起追踪。当 JSD 超过阈值时,触发刷新工作流。
  • 聚类覆盖标注:对每个聚类,记录其生产权重、当前评估密度,以及该聚类中最新评估用例的添加时间。快速演化聚类中的旧用例有效性会下降。
  • 生产到评估的反馈管道:一个轻量级流程,按计划从生产流量采样,通过聚类分类器路由,分发到对应的标注工作流,并将审批通过的用例合并到评估集中。
  • 评估用例溯源:追踪每个评估用例是手工编写、合成生成还是从生产采样而来,以及添加时间。这让你能够审计套件的构成,理解覆盖缺口存在的原因。

这些都不是特殊基础设施。对生产查询向量化、聚类和计算 JSD,是几分钟就能完成且可以完全自动化的操作。主要的投入是文化上的:你必须把评估集当作一个需要维护的活态产物,而不是一次性提交后就束之高阁的静态固件。

那个说谎的绿色仪表盘

在一个陈旧的评估集上通过评估,某种程度上比没有评估套件更糟——它制造了虚假信心,压制了原本会促使人去调查的警觉性。只追踪总体评估分数的团队,可能在用户投诉或支持工单量发出信号之前,已经持续数周发布了回归。

解决方法是显式地检测覆盖率。你的评估分数应该始终由覆盖分数来限定。"87% 通过"在 JSD 为 0.05 和 JSD 为 0.45 时意味着截然不同的事情。前者是关于系统质量的有意义信号,后者是关于测试套件已经偏离用户实际行为的有意义信号。

把评估覆盖率当作生产指标。追踪它。对它发出告警。当它劣化时刷新你的评估集。投入很小;代价是——发布那些更好校准的评估套件本可捕获的静默回归——则不然。

References:Let's stay in touch and Follow me for more thoughts and updates