登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

RAG 检索结果为什么重复:chunk overlap、MMR 与证据合并的排查方法

来源:17golang原创

时间:2026-08-24 21:39:01 259浏览 收藏

做RAG问答时大家经常碰到一类很难排查的问题:生成的回答看起来篇幅很长,实则翻来覆去用不同表述重复同一段知识。排查的时候先别急着调整大模型的温度参数,很多时候根本不是生成层的问题,而是召回结果里本身就带了大量重叠片段,大模型只是忠实地把这些重复的证据拼接成通顺的内容输出而已。

要点速览
  • 先记录每个chunk对应的文档ID、字符区间和相似度得分,再判断重复出现在整个链路的哪一层。
  • chunk重叠度太高时,相邻片段会携带完全相同的句子,这类根因只靠修改提示词完全消不掉。
  • MMR适合在候选召回完成后压低结果之间的内容相似度,同时还要保留同一文档里的关键上下文。
  • 所有候选内容送入大模型之前,还需要按证据ID和文本指纹做一次稳定合并,同时保留完整的来源追溯信息。

先确认重复来自切块、召回还是合并

同一个问题出现两段相似文字,不代表故障点只有一个。可以把链路拆成四个观测点:原文切块、向量库初召回、重排结果、送入模型的 context。每个点都打印 doc_idchunk_id、字符起止位置和分数,先做一轮小样本检查。

for item in retrieved:
    print(item.doc_id, item.chunk_id, item.start, item.end, round(item.score, 4))

如果同一文档的两个片段字符区间明显交叠,问题出在切块环节或者候选筛选规则;如果区间完全不重叠但语义高度相似,才需要去检查MMR策略或者重排逻辑;如果检索返回的列表已经没有明显重复,最后出现的重复通常来自多路检索合并阶段,或是提示词内容拼接环节。

RAG 切块重叠排查:相邻 chunk 共享句子并在召回列表中形成重复证据

chunk overlap 为什么会制造成对重复片段

文本切块时通常会预留一定的重叠部分,避免完整的概念刚好被切到两个片段的边界处。这个权衡本身是合理的,但重叠值并不是越大效果越好。假设chunk长度设为500个字符,重叠180个字符的话,相邻片段就有超过三分之一的内容完全一致;当用户的问题刚好命中边界附近的关键词时,这两个片段很容易同时进入top-k结果里。

这里先看两个事实:一是重复片段是否来自相邻位置,二是重复句子是否跨越了切块边界。可以给每个 chunk 保存 startend,用区间交并比做一个便宜的预警:

overlap = max(0, min(a.end, b.end) - max(a.start, b.start))
ratio = overlap / max(1, min(a.end - a.start, b.end - b.start))
if ratio > 0.35:
    mark_as_neighbor_duplicate(a, b)

这个阈值只是排查的起点,不是适配所有语料的固定标准答案。代码文档、法规条款和带小标题的知识库,更适合按段落或者标题边界切分;客服问答类的语料则要优先保证单条问答内容完整,不能为了降低重复率把原本连贯的上下文切得七零八碎。

把召回结果分成相关性和新信息两件事

纯相似度排序的逻辑会倾向于把所有“和问题最像”的片段全部排在结果前列。MMR的核心思路是:选中的第一个片段要尽可能和问题相关,后续选出来的片段不仅要和问题相关,还要和已经选好的片段保持足够的内容差异。它的常见实现形式可以写成:

MMR(d) = lambda * sim(query, d)
         - (1 - lambda) * max(sim(d, picked) for picked in selected)

lambda 越接近 1,越偏向相关性;越低,越重视多样性。工程上不要直接把它调到很低来“消灭重复”,否则同一问题的关键定义、限制条件和例外情况可能被误删。更稳的做法是先取一个略大的候选集,再在候选里做 MMR,最后仍按来源完整性补回必要上下文。

RAG 证据合并流程:候选召回经 MMR 重排后保留不同来源并稳定去重

证据合并层要做稳定去重

多路检索很容易把同一份证据返回两次,比如关键词检索和向量检索各自返回一份相同内容,或者同一篇文档同时命中了标题和正文部分。合并结果的时候建议保留来源的优先级规则,用稳定的唯一键做判断,不要直接依赖数组的顺序去重:

字段用途重复判断规则
doc_id + chunk_id同一切块的精确去重内容完全相同就直接合并两者的得分
文档区间识别相邻的重叠片段重叠占比过高时保留信息更完整的那一份
文本指纹识别不同ID下的重复内容指纹完全相同的内容只保留一份来源

去重结果仍要保留 source_url、标题和区间,不能只留下一个没有出处的文本字符串。RAG 的答案质量不仅看“有没有重复”,还看读者能不能回到原始证据。

用一组小实验确定该改哪一层

准备20个真实业务场景里的问题和一份固定的文档集,每次只修改一个变量做对照测试:先把重叠值从180调到60,固定切块规则后再比较普通top-k排序和MMR排序的效果,最后再对比单路检索和多路合并的差异。全程记录四个核心指标:重复片段占比、有效独立来源数、答案引用覆盖率、人工判定的事实完整度。

  • 重复片段比例下降、有效来源数不变:可以优先保留当前的切块方案。
  • 来源数下降且答案漏掉限制条件:MMR 多样性过强,调高 lambda 或放宽同文档补回规则。
  • 检索返回的列表已经很干净但送入模型的上下文还是重复:检查提示词模板的拼接逻辑、引用内容的展开规则和多路结果合并逻辑。
  • 调整不同切块参数都还会出现重复:先检查原始文档本身是否存在复制的段落,再判断要不要加文档级的指纹去重步骤。

常见问题

MMR 能不能彻底解决 RAG 重复?

不能。MMR只负责候选结果的重排工作,切块重叠度、原始文档内容复制、最终提示词拼接这些环节的重复问题,还是要各自做单独的检查和去重处理。

把 chunk overlap 设成 0 会更好吗?

不一定。完全零重叠的切块很容易把一个完整的定义拆成两半。要结合段落边界、问题命中位置和答案完整度做多维度验证,不能只靠重复比例这一个指标做判断。

为什么 top-k 越大,重复越明显?

候选召回的数量变大后,相邻的chunk和语义相近的片段会更容易同时进入结果列表。可以先适当扩大候选集供给重排逻辑筛选,再给最终送入上下文的证据总量设置合理的预算上限。

去重后还要保留哪些字段?

至少要保留文档ID、切块ID、来源链接、标题和字符区间这几个字段,这些信息能帮你快速回溯生成的答案到底引用了原文的哪一部分内容。

把排查结果固化成发布前清单

单次调整就能让答案表现变好,但要长期稳定输出效果,得每次做评测的时候都统一记录这些相同字段。提交新的知识库版本之前,至少要复查切块区间规则、候选结果重复比例、MMR参数、合并去重数量和引用覆盖率这几项。下次再碰到生成答案突然变啰嗦的情况,就能快速定位问题到底出在语料更新、检索逻辑调整,还是提示词拼接规则变动上。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>