生产分布差距:为什么内部测试人员找不到用户遇到的Bug
你的 AI 功能在内部测试中表现出色。工程师拍手叫好,产品经理竖起大拇指,评估套件在基准测试中显示了 94% 的准确率。然后你上线了,两周之内,用户就遇到了你从未见过的故障模式——错误的答案、混乱的输出,以及让模型显得极为糟糕的边缘情况。
这就是生产分布差距(production distribution gap)。这不是一个新问题,但对 AI 系统来说,它比确定性软件严重得多。理解其背后的原因——并制定具体的解决方案——是决定 AI 功能悄然侵蚀用户信任还是随着使用不断改进的关键分水岭。
这一差距的存在,是因为测试 AI 的人不是使用它的人。内部测试人员是工程师、产品经理和 QA 专家,他们对"正确"行为有清晰的心理模型。他们会探测正常路径,验证预期输出,并编写符合自身假设的测试用例。真实用户则截然不同:他们的表述模糊,在对话中途切换上下文,将指令以无人预料的方式组合,并提出训练数据几乎未曾涉及的问题。
对于传统软件,这种错配尚在容忍范围内,因为确定性系统中的 错误通常很明显——一个返回错误值的函数,要么通过测试,要么失败。AI 系统的失败则是优雅的。模型产生的内容听起来很合理。测试人员就此放行。用户在三周后提交了一个工单,询问为什么助手告诉他们做了错误的事情。
为什么 AI 会放大这一差距
在传统软件中,溜过测试的故障模式大多是罕见的边缘情况——没人想到要检查的输入。而在 AI 系统中,有三种结构性力量使这一差距大得多。
不确定性掩盖了故障。 确定性错误要么出现,要么不出现。AI 故障存在于概率分布之上。一个 20% 时间内微妙出错的响应,如果每个测试用例只运行一次,看起来没问题。内部测试人员倾向于手动或小批量运行测试用例,这意味着低频故障模式在测试期间几乎不可见,只有在规模扩大时才会浮现。
经过清洗的测试数据造成了盲点。 测试数据集由了解"好"是什么样子的工程师策划而成。他们使用整洁、格式良好的输入、具有代表性的示例,以及他们自己会问的那类问题。生产流量则更混乱:错别字、不完整的句子、隐含的上下文、在单条消息中跨越多个意图的请求,以及不能整齐归类的输入。研究表明,在经过清洗的数据上训练或评估的模型,与在真正从生产环境中采样的分布上测量时相比,性能可能下降 23-40%。模型本身没有问题——它们只是遇到了从未以实际到来的形式见过的输入。
长尾查询进不了测试套件。 测试覆盖率自然地集中在常见 情况上。长尾——罕见但完全合理的用户查询——长期处于代表性不足的状态。这不是对抗性输入;它们只是用户自然提出但没有工程师预料到的不寻常措辞、小众领域或多步问题。长尾很重要,因为失败往往在那里不成比例地聚集。一个能够处理 90% 查询的检索系统,如果在需要稍微不同理解的 10% 查询上持续失败,仍然会让用户感到沮丧。
高级用户测试员问题
在内部测试 AI 的人,不仅仅是"不是真实用户"——他们系统性地偏向于模型处理得最好的分布。
内部测试人员知道系统被设计来做什么。他们会提出能够发挥其优势的查询,在发现问题时迅速调整,并且对模糊性的容忍度很低(他们会不断改写,直到成功)。真实用户不会这样做。他们只问一次问题,照单全收答案,可能永远不会进一步追问。
结果是:内部测试成为了一个最佳情况的基准。你在测量系统在明确了解其能力的人引导下的表现。这有用,但你测量的是错误的人群。
典型的内部测试设置——50 到 500 个手工制作的、带有已知预期输出的查询——大致相当于让厨师自己品尝食物来评价一家餐厅。输出很出色。问题在于,陌生人从菜单点菜时它是否依然如此。
生产环境中实际破损的东西
通常 能逃脱内部测试的故障模式,归属于可识别的类别。
多轮对话中的推理漂移。 在受控测试中,每个测试用例都是独立的。在生产中,用户进行长时间的对话,上下文不断累积。在单轮基准测试中看起来连贯的智能体,在长时间会话中开始漂移——早期轮次以复合错误的方式影响后续轮次。一个每步可靠性为 95% 的 20 步工作流,端到端正确完成的概率大约只有 36%。没有哪一步看起来有问题;系统因累积而失败。
工具调用智能体中的错误级联。 当智能体调用一个工具、获得一个部分结果,并用该结果指导下一步行动时,早期步骤中的错误可能会放大为最终的无意义输出。分别测试每个工具——这是自然的直觉——完全会错过这一点。这种复合故障模式只有在工具与模型推理在多轮之间交互时才会出现。
语义边界情况。 用户用工程师从未预料到的数十种方式描述同一件事。针对一种措辞分布校准的检索系统,无法匹配语义等价但措辞不同的查询。这些不是错误的查询;它们是人类语言的自然变体,而经过清洗的测试数据系统性地将其排除在外。
并发和会话状态 Bug。 内部测试通常是顺序的和单用户的。生产流量是并发的,多用户 AI 系统(共享的 Slack 机器人、团队工作区)会引入上下文泄漏、竞争意图和竞争条件,这些在单线程测试运行中根本不会出现。
