Appearance
6.2.4 为什么对话历史如果处理不好,会直接污染检索?
先给结论:因为对话历史里并不只有当前检索需要的信息,还混着旧问题、旧条件、错误假设和无关上下文。如果系统不做筛选就把历史一股脑带进检索,历史就不再是帮助,而会直接变成噪声来源。
所以在多轮 RAG 里,关键不是“有没有带历史”,而是:
- 带了哪些历史
- 历史以什么形式参与当前检索
为什么历史天然既有价值,也有风险
历史当然有价值,因为它可能包含:
- 当前轮省略掉的对象
- 之前提过的版本、地区、租户边界
- 当前问题真正依赖的上下文
但历史也天然有风险,因为它同时还包含:
- 上一轮已经结束的话题
- 当前轮不再相关的条件
- 用户曾经提过但后来否定的假设
- 系统前面答错的内容
如果这些内容未经处理就进入检索,系统就容易把:
- 旧焦点
- 错焦点
- 无关焦点
一起带入当前轮。
历史污染最常见的几种表现
1. 旧主题压过当前主题
用户已经切换话题了,但系统还沿着上一轮主题检索。
2. 旧条件被错误继承
例如用户前面讨论的是个人版,后面已经转到企业版,系统却仍然把个人版条件带进去。
3. 错误答案反向影响下一轮检索
如果系统前一轮已经答错,而当前轮又依赖那条错误答案继续问,系统就可能把错误继续放大。
4. 历史太长,当前轮核心被稀释
如果历史全部拼进去,当前真正需要检索的信号反而会被埋掉。
一个更实际的例子
假设对话历史里依次出现过:
- 个人版退款规则
- 定制商品规则
- 自动续费取消方式
当前用户突然问:
- “那企业版呢?”
如果系统不先判断当前轮到底承接哪条主线,就可能把:
- 退款
- 定制商品
- 自动续费
这些上下文一起带进检索,结果当然会乱。
为什么“把全部历史拼进去”通常不是好做法
因为对检索器来说,历史不是越多越好,而是越相关越好。
如果全带,常见副作用包括:
- 查询焦点模糊
- 无关术语被引入
- 错误边界被继承
- 候选分布更散
尤其在混合检索和多路召回场景里,这种污染会被进一步放大,因为:
- 更多路径都在吃到被污染的查询输入
更稳的历史处理思路是什么
通常更稳的思路不是:
- 把全部历史直接拼给检索器
而是:
- 先判断当前轮是否真的依赖历史
- 只抽出当前轮真正需要继承的对象和边界
- 必要时先把当前轮重写成独立问题
- 再把重写结果送入检索
也就是说,历史更适合参与:
- 查询理解
而不是直接粗暴参与:
- 原始召回
一个最小示意
python
history = [
"个人版普通商品支持七天无理由退货。",
"定制类商品不支持无理由退货。",
"自动续费可以在会员中心关闭。"
]
current_query = "那企业版呢?"
clean_query = "企业版普通商品是否支持七天无理由退货"这段代码想说明的是:
- 真正进入检索的,不应该是“历史全文 + 当前短句”
- 而应该是经过筛选和恢复后的当前完整问题
一个常见误区
很多人会把多轮能力理解成:
- 历史带得越全越强
这通常是误判。
更稳的理解是:
- 历史带得越准越强
因为历史真正的价值不是增加长度,而是补全当前轮必需的信息。
一句话总结
对话历史如果处理不好,会直接污染检索,因为它里面混着旧主题、旧条件、错误假设和无关信息。多轮 RAG 的关键不是把历史全带上,而是只提取当前轮真正需要继承的那部分上下文。