Appearance
9.4.3 为什么线上真实问题和离线样本经常差很多?
先给结论:离线样本和线上真实问题经常差很多,不是因为用户“不会提问”,而是因为离线样本通常更干净、更完整、更标准,而真实用户问题往往更模糊、更跳跃、更依赖上下文。评测集如果不持续吸收线上样本,迟早会和真实表现脱节。
这是 RAG 项目里非常常见的现象:
- 离线评测看起来还不错
- 一上线,用户却不断遇到答偏、漏答、误答
很多人会先怀疑模型、检索器、向量库,但问题常常更早就埋在评测集里了。
为什么离线样本通常更“理想化”
离线样本往往来自这些来源:
- 产品同学手写的问题
- 文档作者自己总结的问题
- 开发和测试同学基于材料整理的问题
这些问题有一个共同特点:
- 提问目标很明确
- 关键词比较标准
- 背景上下文默认完整
- 很少出现口语化、跳步、误写和歧义
可真实用户不是这样提问的。真实线上问题更像:
- 少量关键词
- 半句话
- 上下文没说全
- 把多个问题混在一起
- 带错别字、简称、内部黑话
- 把系统本来不该回答的问题也问进来
所以很多离线样本其实是在测:
- 理想输入下,系统能不能工作
而线上问题测的是:
- 杂音输入、歧义输入、缺失输入下,系统还能不能稳住
线上和离线脱节,常见有四类原因
第一类,问题表达方式不同
离线样本常常是完整句子,线上用户则可能只打两个词,或者默认系统知道前文。
这会直接影响:
- query understanding
- query rewrite
- 检索召回
第二类,任务分布不同
离线样本里,常常是团队最关心、最容易定义的问题;但线上问题里,用户会不断提出边角问题和跨边界问题。
这会造成:
- 你测的不是用户真正高频的问题
- 你没测到最容易出错的问题
第三类,知识环境在变化
线上系统的文档、版本、权限、时间状态都会变化。离线样本如果长期不更新,很容易继续在测试:
- 旧版本知识
- 旧的文档结构
- 已经过时的业务表述
这样即使评测分数稳定,也不代表系统真的稳定。
第四类,用户目标比问题文本更复杂
很多线上问题表面看是问答,实际上背后还包含:
- 希望比较方案
- 希望得到可执行建议
- 希望系统说明不知道
- 希望限定在某租户、某产品线、某时间段
而离线样本往往只保留了问题文本,没有保留提问意图和上下文目标。
为什么这件事对 RAG 特别重要
RAG 对输入分布变化很敏感。因为它不是单纯依赖模型参数,而是依赖一整条链路:
- 问题理解
- 检索
- 过滤
- 重排
- 上下文构造
- 生成
只要真实线上问题的风格和离线样本不同,整条链路都会受到影响。所以评测集不能长期停留在“内部整理的标准题”阶段。
更稳的做法:把线上样本回流成离线资产
真正成熟一点的做法,不是把离线和线上分开看,而是建立一个持续回流机制。
第一步,给线上问题打基本标签
至少先给问题补这些信息:
- 任务类型
- 是否有明确资料依据
- 是否需要过滤条件
- 是否属于资料不足应拒答
- 当前失败属于检索问题、生成问题,还是端到端问题
没有标签的线上问题,只能堆在日志里,很难变成评测资产。
第二步,优先回流高价值失败样本
不是所有线上问题都要立刻进评测集。优先级更高的通常是:
- 高频失败问题
- 高风险错误问题
- 新版本引入的回归问题
- 某一类任务集中退化的问题
这样能让评测集更快贴近真实风险。
第三步,补上证据范围和判定规则
线上失败样本刚进入评测集时,常常只有:
- 用户问题
- 系统回答
- 用户反馈
但这还不够。要让它真正可评测,通常还要再补:
- 正确证据应该来自哪里
- 什么答案算对
- 什么说法必须避免
否则它只能成为案例,不能成为稳定样本。
第四步,定期检查评测集分布有没有被旧样本绑架
一个很常见的问题是,随着时间推移,老问题越积越多,新问题加得很慢,结果评测集开始偏向历史场景。
所以你需要定期检查:
- 不同任务类型占比是否失衡
- 是否过度集中在某一业务域
- 是否缺少新版本、新数据源、新表达方式下的问题
一个很实用的观察角度
如果你的系统出现下面这些现象,往往就说明离线评测和线上真实问题已经脱节了:
- 离线得分稳定,但用户满意度下降
- FAQ 题表现很好,但复杂问答投诉变多
- 新文档上线后,旧评测集分数仍然很好
- 系统在内部演示很稳,但真实用户一问就暴露大量边角错误
这时候不要只继续调模型或调参数,先回头看评测集是否还代表真实流量。
一个最小回流流程示意
python
failed_case = {
"query": "去年签的企业版合同现在升级套餐还能不能按旧折扣算",
"source": "online_feedback",
"task_type": "time_bounded_policy_qa",
"failure_type": "missing_version_constraint",
"need_human_review": True
}
if failed_case["need_human_review"]:
reviewed_case = {
**failed_case,
"expected_evidence_scope": {
"doc_ids": ["contract-upgrade-policy-2025", "pricing-policy-2026"],
"must_consider_time_boundary": True
},
"judging_rule": {
"must_include": ["合同签约时间", "当前升级规则"],
"must_not_claim": ["所有老客户都继续沿用旧折扣"]
}
}这类回流结构的重点不是代码,而是把线上失败样本变成可复用的评测样本。
一句话总结
线上真实问题和离线样本之所以经常差很多,是因为真实世界的问题分布本来就在变化;评测集只有持续吸收线上失败样本,才不会越来越像一套自我感觉良好的内部题库。