Skip to content

6.2.4 为什么对话历史如果处理不好,会直接污染检索? ​

先给结论:因为对话历史里并不只有当前检索需要的信息,还混着旧问题、旧条件、错误假设和无关上下文。如果系统不做筛选就把历史一股脑带进检索,历史就不再是帮助,而会直接变成噪声来源。

所以在多轮 RAG 里,关键不是“有没有带历史”,而是:

  • 带了哪些历史
  • 历史以什么形式参与当前检索

为什么历史天然既有价值,也有风险 ​

历史当然有价值,因为它可能包含:

  • 当前轮省略掉的对象
  • 之前提过的版本、地区、租户边界
  • 当前问题真正依赖的上下文

但历史也天然有风险,因为它同时还包含:

  • 上一轮已经结束的话题
  • 当前轮不再相关的条件
  • 用户曾经提过但后来否定的假设
  • 系统前面答错的内容

如果这些内容未经处理就进入检索,系统就容易把:

  • 旧焦点
  • 错焦点
  • 无关焦点

一起带入当前轮。

历史污染最常见的几种表现 ​

1. 旧主题压过当前主题 ​

用户已经切换话题了,但系统还沿着上一轮主题检索。

2. 旧条件被错误继承 ​

例如用户前面讨论的是个人版,后面已经转到企业版,系统却仍然把个人版条件带进去。

3. 错误答案反向影响下一轮检索 ​

如果系统前一轮已经答错,而当前轮又依赖那条错误答案继续问,系统就可能把错误继续放大。

4. 历史太长,当前轮核心被稀释 ​

如果历史全部拼进去,当前真正需要检索的信号反而会被埋掉。

一个更实际的例子 ​

假设对话历史里依次出现过:

  • 个人版退款规则
  • 定制商品规则
  • 自动续费取消方式

当前用户突然问:

  • “那企业版呢?”

如果系统不先判断当前轮到底承接哪条主线,就可能把:

  • 退款
  • 定制商品
  • 自动续费

这些上下文一起带进检索,结果当然会乱。

为什么“把全部历史拼进去”通常不是好做法 ​

因为对检索器来说,历史不是越多越好,而是越相关越好。

如果全带,常见副作用包括:

  • 查询焦点模糊
  • 无关术语被引入
  • 错误边界被继承
  • 候选分布更散

尤其在混合检索和多路召回场景里,这种污染会被进一步放大,因为:

  • 更多路径都在吃到被污染的查询输入

更稳的历史处理思路是什么 ​

通常更稳的思路不是:

  • 把全部历史直接拼给检索器

而是:

  1. 先判断当前轮是否真的依赖历史
  2. 只抽出当前轮真正需要继承的对象和边界
  3. 必要时先把当前轮重写成独立问题
  4. 再把重写结果送入检索

也就是说,历史更适合参与:

  • 查询理解

而不是直接粗暴参与:

  • 原始召回

一个最小示意 ​

python
history = [
    "个人版普通商品支持七天无理由退货。",
    "定制类商品不支持无理由退货。",
    "自动续费可以在会员中心关闭。"
]

current_query = "那企业版呢?"

clean_query = "企业版普通商品是否支持七天无理由退货"

这段代码想说明的是:

  • 真正进入检索的,不应该是“历史全文 + 当前短句”
  • 而应该是经过筛选和恢复后的当前完整问题

一个常见误区 ​

很多人会把多轮能力理解成:

  • 历史带得越全越强

这通常是误判。

更稳的理解是:

  • 历史带得越准越强

因为历史真正的价值不是增加长度,而是补全当前轮必需的信息。

一句话总结 ​

对话历史如果处理不好,会直接污染检索,因为它里面混着旧主题、旧条件、错误假设和无关信息。多轮 RAG 的关键不是把历史全带上,而是只提取当前轮真正需要继承的那部分上下文。