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

RAG 检索结果太多时怎么做去重和上下文预算

来源:17golang原创

时间:2026-09-07 07:10:20 207浏览 收藏

RAG 检索结果太多时,先别急着把 top_k 调小。更稳的做法是把“召回更多候选”“去掉重复片段”“重新排序”和“装入上下文”拆开处理:先用较大的候选池保证覆盖,再按来源与文本指纹去重,最后在扣除系统指令、用户问题和回答空间后,用剩余预算选择证据。这样既能减少模型看到的重复内容,也不会因为硬截断丢掉关键事实。

要点速览
  • 去重解决“同一事实出现多次”,重排解决“相关片段顺序不对”,预算装箱解决“证据太长”。
  • 候选片段应同时记录来源、分数、覆盖主题和估算成本,不能只按相似度排序。
  • 预算要先给系统指令、用户问题和回答留位置,再把余量分配给证据片段。

候选方案怎么分工:去重、重排和预算不是一件事

把检索结果直接送给模型,常见问题不是“结果不够”,而是前十条里有四条来自同一段文档,剩下的片段又把同一个结论换了说法。扩大召回只能提高覆盖,不能自动消除冗余;重排器能判断相关性,却不一定知道两个片段其实在重复;上下文压缩则是在内容已经选定后减少字数,不能替代候选筛选。

实用的候选池可以按四层理解:

方案主要解决适合场景代价
扩大召回漏掉相关证据问题表述多、召回不稳定重复片段增多
去重或 MMR内容同质化文档切块重叠、同源内容多可能牺牲一点单条最高分
重排器相关性顺序关键词命中但语义不准增加一次模型或计算成本
上下文压缩片段过长证据本身有大量背景话术压缩过度会丢限定条件
RAG 检索结果过多时,用户问题、候选片段、去重器、重排器、预算装箱器与模型上下文的静态关系框图
图1:看清候选片段、去重器/MMR、重排器和预算装箱器分别承担的静态职责。

先去重再排序,避免同源片段占满前排

去重不要只比较整段字符串。切块通常有重叠窗口,同一事实可能只差一两句;可以先做空白、大小写和标点归一化,再以来源标识加文本指纹识别完全重复,最后用相似度阈值处理近重复。近重复组里保留分数更高、来源更稳定、包含限定条件更完整的片段,其他片段的主题标签仍可用于计算覆盖度。

下面的示例展示“去重与预算装箱”这两个动作如何分开。rough_tokens 只是工程估算,正式系统应替换为目标模型对应的 tokenizer;不要把字符数当成跨语言通用的精确 token 数。

def pack_context(hits, budget):
    seen = set()
    picked = []
    used = 0

    # 先按相关性排序,实际项目可在这里接入重排分数
    for hit in sorted(hits, key=lambda item: item["score"], reverse=True):
        text = " ".join(hit["text"].split())
        fingerprint = (hit["source_id"], text[:120])

        # 同源同前缀视为重复候选;近重复需换成相似度指纹
        if fingerprint in seen:
            continue
        seen.add(fingerprint)

        # 这是预算估算,不等同于目标模型的真实 token 计数
        rough_tokens = max(1, len(text) // 2)
        if used + rough_tokens > budget:
            continue

        picked.append({"source_id": hit["source_id"], "text": text})
        used += rough_tokens

    return picked

这个片段故意没有把“最高分”当成唯一标准。生产实现还应给不同来源设质量权重,并给每个主题设置最低覆盖数;否则一个写得很长的热门文档,仍可能挤掉回答另一半问题所需的证据。

上下文预算怎么定:先留回答空间,再装高价值片段

预算公式可以先写成:证据预算 = 模型输入上限 - 系统指令 - 用户问题 - 历史对话 - 回答预留 - 安全余量。输入上限和输出上限要以实际部署模型的官方规格为准;不同模型、工具调用和消息格式会改变可用空间。OpenAI 的模型与 API 文档可作为核对入口,不能把别的模型的数字直接套过来。

装箱时建议采用“相关性分数 + 新增覆盖度 - token 成本”的简单收益值。每加入一个片段,就重新计算它带来的新实体、字段或结论;如果只是重复已经覆盖的事实,即使分数很高,也应该让位给能补齐答案的片段。超过预算时优先删掉重复度高、来源弱、没有新增限定条件的候选。

RAG 上下文预算中,系统指令、用户问题、证据片段、来源元数据、回答空间与最终上下文的静态关系框图
图2:上下文预算要同时容纳问题约束、证据片段、来源元数据和回答空间。

用四个指标判断是检索问题还是预算问题

不要只看最终回答是否“像是正确的”。在离线样本上同时记录:候选去重率、主题覆盖率、预算截断率和引用完整度。去重率很低但覆盖率也低,通常是召回或切块问题;覆盖率足够而截断率很高,优先调整片段长度、压缩策略或证据预算;片段都在上下文里但引用遗漏,说明排序、来源元数据或回答约束仍有问题。

  • 去重率:被合并或丢弃的重复候选占比,过低说明候选池可能冗余。
  • 覆盖率:参考答案所需事实被至少一个片段覆盖的比例。
  • 截断率:因预算不足未进入最终上下文的高价值片段比例。
  • 引用完整度:回答中的关键结论能否回指到保留的来源片段。

最容易踩的坑是固定写死 top_k=5。知识库更新、问题长度和模型上下文变化后,这个数字没有稳定含义。更可靠的配置是保留较小的最终证据集,同时把候选数、预算、去重阈值和截断原因写入日志,方便回放同一个问题。

常见问题

去重后只剩两条结果,是不是阈值太严格?

不一定。先检查原候选是否本来就来自同一文档或同一事实,再看主题覆盖率;如果覆盖率仍完整,少量结果反而更健康。

重排器能不能直接替代去重?

不能。重排器优化顺序,去重器减少重复;两者可以串联,也可以让重排分数参与近重复组内的代表选择。

上下文越大,回答一定越好吗?

不一定。过多相似片段会稀释重点并挤压回答空间。应以覆盖率、引用完整度和截断率一起调参,而不是只追求更大的输入。

参考入口:OpenAI API 文档用于核对模型与输入限制;Hugging Face Blog用于观察检索、重排和上下文压缩的工程讨论。本文的示例、阈值和组合策略均为原创说明,不对应某个厂商的默认实现。

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