Skip to content

7.3.2 为什么高分结果之间也要去重和聚合? ​

先给结论:高分不等于高信息增量。很多看起来都很相关的结果,实际上可能来自同一文档、描述同一事实、只是在切块边界上略有不同。若不去重和聚合,模型看到的会是重复证据,而不是更多有效信息。

这件事在真实系统里非常常见。原因并不复杂:

  • 一个重要段落可能被切成多个相邻块
  • 一个定义可能在文档开头、FAQ、总结页里反复出现
  • 一个高频术语可能让多个相似块都得到高分
  • 一个版本说明可能在多个页面里留下近似内容

所以候选结果分数高,只能说明它们各自都像相关内容,不能说明:

  • 它们彼此之间不重复

不去重会带来什么问题 ​

最直接的问题是浪费上下文预算。

模型的上下文窗口虽然越来越大,但真正高质量的证据位仍然有限。如果前几条结果其实在表达同一件事,系统就会把预算花在重复信息上。

更进一步的问题包括:

  • 真正不同角度的证据被挤掉
  • 模型误以为某个观点更重要,只因为它被重复了很多次
  • 来自同一文档的小片段过多,导致缺少跨文档补充信息
  • 最终回答变得啰嗦、偏科,甚至重复引用

为什么“高分也要去重” ​

很多人会误以为:

  • 高分结果既然都排在前面,说明它们都该保留

这不够稳。因为排序分数解决的是:

  • 每条结果相对问题的相关性

它不自动解决的是:

  • 这些结果彼此之间的信息重复度

也就是说,排序和去重解决的是两类不同问题:

  • 排序回答“哪些更相关”
  • 去重回答“哪些只是重复表达”

常见的重复类型 ​

1. 相邻块重复 ​

同一文档切块时,为了保留上下文,往往会加 overlap。这样召回结果里就很容易出现:

  • 前后两个块都命中了
  • 它们大段内容相同

这类重复最常见,也最值得优先处理。

2. 模板重复 ​

很多知识库文档都有固定模板,比如:

  • 文档头说明
  • 版本声明
  • 版权信息
  • 常规安全提醒

这些内容可能因为高频关键词而一起被召回,但它们对回答当前问题未必重要。

3. 多页面同义重复 ​

同一个规则可能同时存在于:

  • 产品说明页
  • FAQ
  • 帮助中心
  • 更新公告

这些内容不一定完全重复,但它们常常只是在不同地方重复表达同一事实。

去重和聚合分别在做什么 ​

这两个动作经常放在一起说,但侧重点不完全一样。

去重 ​

更偏向移除明显重复或高度近似的候选,比如:

  • 相同 chunk_id
  • 相同 document_id + span
  • 文本高度相似

聚合 ​

更偏向把本来就属于同一证据单元的候选合并处理,比如:

  • 同一文档的多个相邻块
  • 同一章节下的多个命中块
  • 来自同一条 FAQ 的多个拆分片段

去重是防止浪费,聚合是恢复结构。

一个最小示意 ​

python
candidates = retrieve(query, top_k=20)
candidates = deduplicate_by_similarity(candidates)
candidates = merge_adjacent_chunks(candidates)
final_context = select_top_context(candidates, max_chunks=6)

这段代码想表达的是:

  • 候选拿到后,不能立刻直接截前几条
  • 先去重和聚合,才能更准确决定最终该给模型什么

实际落地时怎么判断该不该合并 ​

可以先问三个问题:

  1. 这几个高分结果是不是来自同一文档、同一章节或同一段附近
  2. 它们表达的是同一事实,还是互补信息
  3. 如果只保留其中一条,会不会丢掉回答所需的关键上下文

如果答案更接近“同一事实的重复表达”,就应该偏去重。

如果答案更接近“同一证据链的不同片段”,就应该偏聚合。

一个常见误区 ​

很多人只在索引前做内容去重,却忽略了:

  • 检索后仍然会出现结果级重复

这很正常。因为索引前去重解决的是“库里别放太多重复内容”,而检索后去重解决的是:

  • 当前问题下,最终候选别重复占位

这两层都需要。

一句话总结 ​

高分结果之间也要去重和聚合,因为高分只代表“各自都相关”,不代表“彼此信息不重复”。去重能防止上下文预算被重复内容浪费,聚合能把本来碎掉的证据重新组织成更适合模型使用的上下文单元。