RAG 的核心挑战不在检索,而在召回后的治理

0 阅读19分钟

当所有人都在讨论如何提升召回率时,真正的战场已经转移到了召回之后。


一、为什么召回率 95%,大模型还是答错?

几乎所有 RAG 项目的第一步都是提升召回率:调 Embedding 模型 、换向量数据库、优化 Chunk 策略……一套操作下来,Recall@10 到了 95%,团队觉得稳了。

系统上线后,用户问了个问题,大模型却给了个似是而非的答案。回头查召回的文档——明明挺相关,Top-10 里 8 条都相关,怎么就答错了?

问题不在召回,在召回之后。

召回率陷阱

有个现象挺有意思:当 Recall@5 从 70% 提升到 85% 时,最终问答准确率只提升了 5 个百分点;而当 Recall@10 从 85% 提升到 95% 时,准确率反而下降了 2 个百分点。

Recall@K 这个指标只关心"前 K 条里有多少相关文档",不关心文档排得对不对,也不关心里面混了多少噪音。

K 变大,相关文档确实多了,噪音也跟着多了。更要命的是,向量检索的排序是按相似度来的,但这个相似度是 Embedding 模型理解的"相似"——不等于"对回答问题有帮助"。

向量检索的局限

向量检索把语义相近的内容映射到向量空间里的相近位置。这里有两个损失:

1. 信息压缩必然丢失细节

一段 500 字的文档被压缩成 1024 维的向量,这个过程注定要丢东西。Embedding 能抓住大意,但抓不住细节;能识别主题,但识别不了用户真正的意图。

2. 语义相似不等于问答相关

用户问"如何优化 SQL 查询性能",Embedding 可能把"SQL 注入防护"也召回——因为它们都含"SQL",在向量空间里距离近。

用户问"苹果公司最近的财报怎么样",可能召回"苹果种植技术"——Embedding 分不清这个"苹果"是水果还是公司。

用户问"2024 年 AI 大模型的最新进展",可能召回"2023 年的报告"——语义相近,但过时了。

向量检索的任务应该是:找到一批可能相关的文档,别漏掉重要的

排序和治理的任务则是:从这批文档里找出真正能回答问题的,排出优先级,过滤噪音

这是两件事,得用不同的方法。

RAG 没有二次确认机会

这和传统搜索不一样。

用 Google 搜索时,你输入 query,看到 10 条结果,会扫一眼标题和摘要,决定点哪个、不点哪个——你有二次确认的机会。

但 RAG 系统里,召回的内容直接拼成 Prompt 喂给大模型。大模型没机会"浏览一下召回结果,挑最相关的看",它只能看到你塞给它的东西。

如果召回的前 3 条里,2 条是噪音,1 条相关,大模型会怎么回答?

它会倾向于"综合"所有召回的内容,给出一个四不像的答案,或者被噪音带偏。

所以召回后的治理比召回本身更重要。召回是"把东西拿进来",治理是"把东西挑干净、排好序"。

多轮对话:噪音累积

多轮对话里,问题更明显。

每一轮对话,新召回的内容都会注入上下文。如果不做治理,噪音会不断累积,最终淹没有用的信息。

这个问题在检索层面无解——召回再多相关文档,不做排序、过滤、上下文管理,结果只会越来越差。

RAG 两阶段检索架构图


二、两阶段检索:从粗筛到精排

为什么向量相似度不够?

向量检索的排序依据是全局 语义相似度 ,不是"对回答这个问题有帮助"。

比如用户问:“Python 里如何实现多线程?”

  • 文档 A:“Python 的 GIL 机制导致多线程无法真正并行,这是 Python 的设计缺陷。”
  • 文档 B:“Python 提供了 threading 模块来实现多线程编程,常用方法包括 Thread、Lock、Queue。”

从语义相似度看,文档 A 可能和"多线程"、"Python"这些关键词更匹配。

但从"回答问题"的角度,文档 B 才是真正有用的。

向量检索不知道用户想问什么,只知道文档大概说了什么。

两阶段架构

既然向量检索是"粗筛",那就需要一个"精排"环节。

Query → 向量召回(Top-100)→ 重排模型(Top-10)→ 大模型生成答案

第一阶段:向量召回(Bi-Encoder)

  • 用 Bi-Encoder 把 Query 和文档分别编码成向量
  • 在向量空间里做最近邻搜索(ANN)
  • 速度快,适合大规模召回
  • 目标:别漏掉相关文档

第二阶段:重排(Rerank)

  • 用更精准的模型对候选集重新排序
  • Query 和文档一起输入,考虑交互
  • 目标:把最有用的文档排到最前面

这个架构的核心就一点:召回追求"全",排序追求"准"

Bi-Encoder vs Cross-Encoder

重排模型为什么比向量检索准?区别在架构。

Bi-Encoder(双编码器)

Query → [Encoder] → 向量 Q ─┐
                           ├→ 余弦相似度 → 得分
Doc  → [Encoder] → 向量 D ─┘
  • Query 和文档分别通过同一个 Encoder,独立编码成向量
  • 相似度计算在编码之后,用余弦相似度或点积比较
  • 优势:文档向量可以预先计算并建索引,查询时只需编码 Query,速度极快
  • 劣势:Query 和文档在编码阶段没有交互,无法捕捉细粒度的语义关联

Cross-Encoder(交叉编码器)

Query + Doc → [拼接] → [Transformer Encoder] → 相关性分数
  • Query 和文档拼接后一起输入,在 Transformer 每一层通过 Self-Attention 交互
  • 相似度计算在编码过程中完成,模型能看到完整上下文
  • 优势:能捕捉词与词之间的精细关联,判断更准确
  • 劣势:每对 Query-Doc 都要过一次完整模型,无法预计算,速度慢

直观类比

  • Bi-Encoder 像"相亲看简历":先把每个人写成简历(编码),然后比较匹配度。效率高,但简历可能丢失细节。
  • Cross-Encoder 像"相亲看真人":让两个人直接见面聊天,当场判断。更准,但没法批量处理。

为什么 Self-Attention 让 Cross-Encoder 更准?

在 Transformer 的每一层,Self-Attention 让每个 token 都能"看到"其他所有 token。这意味着:

  • Query 里的"苹果",能注意到 Doc 里的"公司"、“财报”,从而判断是苹果公司而非水果
  • Query 里的"优化",能关注到 Doc 里的"性能提升 30%“,而不是泛泛而谈的"优化方法”

这种细粒度的交互,Bi-Encoder 分别编码后做向量点积做不到。

Bi-Encoder vs Cross-Encoder 架构对比

维度Bi-EncoderCross-Encoder
速度快(可预计算)慢(每对单独过模型)
精度中等
适合规模百万/千万级文档百/千级候选集
典型用途第一阶段召回第二阶段精排

效果数据

在一个面向技术文档的 RAG 系统里,研究者做了个实验:

方案Top-1 准确率Top-3 准确率Top-5 准确率
仅向量召回45%62%73%
向量召回 + Cross-Encoder Rerank78%89%93%

加入 Rerank 后,Top-1 准确率从 45% 提升到 78%。

原来问 10 个问题只能准确回答 4.5 个,现在能回答 7.8 个。

主流 Rerank 模型

模型类型语言支持优势适用场景
BGE-RerankerCross-Encoder中英开源免费,中文优化通用场景,预算有限
Cohere RerankAPI多语言精度高,开箱即用英文为主,追求效果
Jina RerankerCross-Encoder多语言长文档友好,支持 8K 上下文技术文档、法律文档
bge-reranker-v2Cross-Encoder中英轻量级,延迟低对延迟敏感的场景
LLM Rerank大模型任意推理能力强,可解释高价值场景,复杂 query

选型建议

  • 中文场景:BGE-Reranker 系列(bge-reranker-large / v2)
  • 英文场景:Cohere Rerank 或 Jina
  • 长文档:Jina Reranker(支持 8K 上下文)
  • 高价值场景:LLM Rerank(法律、医疗、金融)

LLM Rerank

除了 Cross-Encoder,还可以让大模型直接判断文档和 Query 的相关性。

优势

  • 能理解复杂的语义关系
  • 能做多跳推理
  • 不需要额外训练 Rerank 模型

劣势

  • 慢:每条文档都要过一次大模型
  • 贵:API 调用成本是 Cross-Encoder 的 10-100 倍

实战用法:先用 Cross-Encoder 过滤到 Top-3,再用 LLM Rerank 做最终排序。这样既能用上大模型的推理能力,又能控制成本。

参数建议

召回阶段:Top-50 到 Top-100

  • 太少可能漏掉长尾 Query
  • 太多会增加 Rerank 的延迟和成本
  • Top-50 比较平衡

Rerank 阶段:Top-5 到 Top-10

  • 重排后的结果送入大模型作为上下文
  • 5-10 条足够,太多会稀释关键信息

延迟预算

  • 向量召回:10-50ms
  • Cross-Encoder Rerank:50-200ms
  • 大模型生成:1-10s

总延迟控制在 200-300ms 以内,用户体验会比较流畅。

混合检索

单一向量检索有局限,可以组合多种方式:

Query
  ├── BM25 召回(关键词匹配)→ Top-20
  ├── 向量召回(语义匹配) → Top-20
  └── 知识图谱召回(实体关联)→ Top-10
        ↓
     融合 + 去重 → Top-50
        ↓
     Rerank(精排) → Top-5
        ↓
     大模型生成答案

BM25 负责精确匹配,向量检索负责语义扩展,知识图谱负责关联推理。三者互补,最后统一用 Rerank 做最终排序。


三、召回后治理:7 个处理环节

召回后治理 7 个环节框架图

3.1 去重

从多个渠道召回文档时,第一件事是去重。

为什么需要去重

  • 同一篇文章的不同 URL(官网、备份站、转载站)
  • 同一个文档的不同版本(v1.0、v2.0、v3.0)
  • 内容高度相似的多篇文档

不去重的话,大模型会看到重复内容,可能重复引用同一个观点,或者浪费上下文窗口。

常用算法

  1. SimHash:Google 提出的局部敏感哈希算法。文档生成 64 位指纹,汉明距离小于 3 视为相似。

  2. MinHash:适合计算 Jaccard 相似度。

  3. Embedding 相似度:用 Embedding 向量计算余弦相似度,阈值 0.95 以上视为重复。

做法

  • 第一层:URL 去重(exact match)
  • 第二层:SimHash 快速过滤
  • 第三层:Embedding 相似度精细筛选

三层去重后,通常能减少 30-50% 的冗余。

3.2 上下文压缩

去重之后是压缩。

大模型的上下文窗口有限。召回 10 条文档,每条 5000 字,加起来 5 万字,但大模型可能只能处理 8000 字。

得选择保留什么、丢弃什么。

截断策略

  1. 固定截断:直接取前 N 个字。简单,但可能截掉关键信息。

  2. 语义切分:用模型判断文档的自然段落或句子边界,在语义完整的地方切分。

  3. 滑动窗口:按固定步长(如 500 字)滑动,每个窗口保留重叠(如 100 字)。关键信息不会被完全切掉。

  4. 关键信息提取:用 LLM 或提取模型,从长文档里提取"核心观点"、“关键数据”、“结论”。

经验

  • 文档结构清晰(标题、段落):用语义切分
  • 长篇大论:用滑动窗口 + 重叠
  • 精度要求高:用关键信息提取(成本更高)

3.3 时效性加权

信息有"保质期"。

  • 用户问"最新发布的 iPhone 怎么样",召回一篇 2022 年的评测,不合适
  • 用户查"2024 年 AI 大模型排名",给一篇 2023 年的报告,准确度打折扣

时间衰减函数

score = base_score * e^(-λ * days_since_publish)
  • λ 越大,旧文档衰减越快
  • 新闻类 λ=0.1(半年衰减 80%),知识类 λ=0.01(一年衰减不到 4%)

做法

  • 在向量数据库里给文档加 publish_time 字段
  • 召回后用时间衰减函数重新加权
  • 时效性敏感的场景(新闻、行情、政策),强制过滤掉 N 天前的文档

3.4 多样化排序

向量检索和 Rerank 都倾向于召回"最相似的",但最相似的往往也是最同质化的。

比如用户问"Python 和 JavaScript 的区别",可能召回:

  • 文档 1:Python 基础语法
  • 文档 2:Python 高级特性
  • 文档 3:Python 与 Java 对比
  • 文档 4:Python Web 开发

Top-4 全是 Python,JavaScript 被淹没了。

解决方案:MMR(Maximal Marginal Relevance)

MMR 在相关性和多样性之间做平衡:

MMR = α * relevance(query, doc) - (1-α) * max_similarity(doc, selected_docs)
  • α 越大,越偏向相关性
  • α 越小,越偏向多样性

做法

  • 第一遍:按相关性排序,选出 Top-20
  • 第二遍:用 MMR 重排,保证 Top-10 里至少有 3 个不同主题

3.5 上下文窗口管理

多轮对话 RAG 的核心挑战。

每一轮对话,大模型看到的上下文包括:

  • 系统提示词(System Prompt)
  • 历史对话记录
  • 本轮召回的文档

GPT-4 Turbo 是 128K tokens,Claude 3.5 是 200K tokens——看起来大,但实际上:

  • 系统提示词占 2-3K
  • 历史对话(10 轮)占 5-10K
  • 召回文档占 50-80K

一不小心就满了。

治理策略

  1. 选择性遗忘:只保留最近 N 轮对话

  2. 摘要压缩:把历史对话压缩成摘要

  3. 按需加载:只在当前 Query 涉及历史内容时才加载

  4. Token 预算分配:给对话历史、召回文档、系统提示分配固定预算

核心:只保留对当前问题有用的上下文

3.6 置信度判断

不是所有问题都能回答。

  • 用户问的内容超出知识库范围
  • 召回的文档相关度都很低
  • 用户问题太模糊

这时候硬要回答,大模型会"编"答案,这就是幻觉(Hallucination)

置信度判断方案

  1. 召回相关性阈值:Top-5 文档平均相关性低于 0.5,触发拒答或反问

  2. LLM 自我评估:让大模型在生成答案前评估"我有足够信心吗?"

  3. 一致性检测:用多个不同 Prompt 生成答案,结果不一致说明置信度低

拒答策略

  • 保守:直接回复"抱歉,这个问题我无法从知识库中找到答案"
  • 中间:只回答确信的部分,不确定的承认不知道
  • 激进:告诉用户"知识库里没有直接答案,以下是推测……"

阈值参考

  • 客服场景:0.4-0.5(宁可拒答,不要乱答)
  • 内部知识库:0.3-0.4(允许容错)
  • 创意生成:0.2-0.3(鼓励发散)

3.7 人工审核

再好的系统也会有漏网之鱼。

  • 召回可能漏文档
  • Rerank 可能排错顺序
  • 置信度可能误判
  • 生成可能产生幻觉

人工审核机制

  1. bad case 收集:用户标记"回答不对"时自动记录

  2. 归因分析:判断是召回、Rerank 还是生成的问题

  3. 定期 review:每周/每月 review 一批 bad case,找出系统性问题

  4. 持续优化

  • 召回漏了 → 补充知识库或调整 Chunk 策略
  • Rerank 排错 → 调整模型权重
  • 幻觉 → 调低置信度阈值或增强 prompt

案例:某公司 RAG 系统上线后满意度 65%,建立了"答案评审"机制(用户点赞/踩,踩的进入审核池,每周 review 20 个 bad case),三个月后满意度升到 88%。


四、落地实践

参数速查表

环节推荐配置备注
召回 Top-K50-100长尾 Query 取大值
Rerank Top-K5-10超过 10 条收益递减
去重阈值0.95Embedding 余弦相似度
置信度阈值0.4-0.5根据业务调整
时间衰减 λ0.01-0.1新闻类取大值,知识类取小值
MMR α0.7-0.9平衡相关性与多样性
延迟预算200-300ms不含大模型生成

案例一:电商客服 RAG

背景

  • 日均咨询 10 万+
  • 主要问题:退换货政策、订单查询、促销活动
  • 痛点:政策频繁更新,旧答案误导用户

问题

  • 召回率 92%,答案准确率只有 68%
  • 用户投诉:按系统回答操作,实际政策已变更
  • bad case 分析:70% 时效性问题,20% 重复内容

改进

第一步:时效性治理

  • 给政策文档加 effective_dateexpire_date 字段
  • 召回后强制过滤过期文档
  • 时间衰减 λ 设为 0.2

第二步:去重优化

  • 发现同一政策有"官网版"、“APP 版”、"客服版"三个版本
  • 建立"唯一可信源",只保留官方最新版
  • 去重阈值从 0.95 调到 0.9

第三步:置信度 + 人工审核

  • 置信度阈值 0.45,低于此值转人工
  • 新政策发布后,旧答案自动标记"待审核"

效果

  • 3 个月后,准确率从 68% 提升到 89%
  • 投诉下降 76%
  • 人工介入率从 35% 降到 18%

案例二:技术文档 RAG

背景

  • API 文档平台,50 万+ 技术文档
  • 痛点:代码示例被切分,召回后无法理解

问题

  • 用户问"如何调用 XX 接口",召回的代码缺少上下文
  • Chunk 策略是固定 512 tokens,代码被拦腰斩断
  • 多轮对话下,历史内容堆积,新内容被稀释

改进

第一步:Chunk 策略重构

  • 代码文档:按函数/类切分,保证每个 Chunk 完整
  • API 文档:按标题层级切分,每个 endpoint 独立
  • 增加"代码上下文"字段:附带文件路径、导入语句

第二步:混合检索

  • BM25:精确匹配 API 名称、参数名
  • 向量:语义匹配功能描述
  • 融合:BM25 前 20 + 向量前 30 → 去重 → Rerank

第三步:上下文压缩

  • 多轮对话用摘要压缩历史
  • 只保留最近 3 轮完整内容

效果

  • 代码问题准确率从 52% 提升到 81%
  • 平均对话轮次从 4.2 降到 2.8
  • NPS 从 23 提升到 41

五、常见误区

误区一:只盯着召回率

Recall@K 只关心"有没有召回相关文档",不关心"排序对不对"。

Recall@10 是 90%,意味着 10 条里召回 9 条相关。但如果排在前面的 9 条都是噪音,只有最后 1 条相关,回答质量照样差。

除了 Recall@K,还要看

  • Hit@K:Top-K 里有多少次真正命中正确答案
  • MRR:第一个相关文档出现的位置,越靠前越好
  • NDCG:综合考虑相关性和排序位置

误区二:RAG = 向量数据库

很多团队觉得 RAG 就是"搭个向量 数据库 ,接上大模型"。

RAG 的完整流程:

文档 → Chunk → Embedding → 向量索引 → 检索 → 排序 → 上下文压缩 → 生成答案

向量检索只是其中一步。Chunk、Embedding、排序、压缩、生成,每个环节都会影响最终效果。

误区三:Chunk 策略随便搞

很多人用"512 tokens 切一刀"的固定策略。

但这样会切坏语义。一段话被拦腰斩断,召回的内容可能不完整。

代码文档更明显。一段代码被切成三段,用户问"参数校验逻辑是什么",召回了第二段,上下文没了,看不懂。

正确做法

  • 结构化文档(技术文档、API 文档):按标题层级切
  • 代码文档:按函数/类切
  • 纯文本:按句子或段落切,用滑动窗口保留重叠

误区四:Embedding 模型乱选

Embedding 是向量检索的"原材料",选错了后续优化都是事倍功半。

常见问题是盲目追求"最新最大"。OpenAI 的 text-embedding-3-large(3072 维)确实强,但在中文垂直领域,可能不如专门的模型(如 BGE、M3E)。

选型参考

场景推荐模型
通用中文BGE-large-zh
英文为主text-embedding-3-large
代码检索CodeBERT
跨语言text-embedding-3-large、LabSE
垂直领域领域微调的 BGE

选好模型后,在自己的数据集上做离线评测,别只看官方榜单。

误区五:知识库不更新

知识库会"过期"。

  • 产品文档更新了,向量数据库里还是旧版本
  • 政策文件替换了,旧版本还在被检索
  • 新闻过时了,依然被当作有效信息召回

做法

  • 给文档加时间戳(创建时间、更新时间)
  • 超过 N 天的文档自动降权或下架
  • 知识库变更时,触发向量索引增量更新
  • 强时效性内容(新闻、促销、政策)单独建索引

误区六:不上监控

RAG 系统上线后,最大的风险是"不知道出了问题"。

常见问题:

  • Embedding 模型更新了,向量索引没重建,召回质量下跌,没人发现
  • 大模型版本升级,回答风格变了,原来的 prompt 不适用了,没人知道
  • 知识库被污染,低质量文档混入,召回质量下降

监控体系

  1. 召回指标监控:每小时计算 Recall@K、Hit@K,下跌超过 10% 报警
  2. 回答质量抽检:每天随机抽样 100 个回答,人工评估
  3. Bad case 告警:用户踩了自动记录并触发审核
  4. 端到端监控:模拟真实用户 query,定期跑自动化测试

六、总结

回到开篇的问题:为什么召回率很高,大模型还是答错?

因为真正的挑战不在检索,在召回后的治理。

几点结论

  1. 向量检索是"粗筛",任务是别漏掉相关文档。召回率再高,Top-K 里都是噪音,大模型也答不好。

  2. Rerank 是必要的。两阶段检索(向量召回 + Rerank 精排)是主流方案,能带来明显提升。

  3. 召回后处理是系统工程。去重、压缩、时效性加权、多样化排序、上下文管理、置信度判断、人工审核,每个环节都重要。

  4. 避开常见坑:别只盯着召回率,别把 RAG 等同于向量检索,别忽视 Chunk 策略,别不上监控。

如果你正在搭建 RAG 系统,可以按这个顺序推进

RAG 系统 4 周落地实施计划

  1. 第一周:统计当前召回率、准确率,分析 50 个 bad case,确定优先级
  2. 第二周:上线 Rerank(推荐 BGE-Reranker),配置召回 Top-50 → Rerank Top-5,A/B 测试
  3. 第三周:加上去重、时效性加权、置信度判断
  4. 第四周:建立 bad case 收集机制,每周 review,持续优化

检索是基础能力,每家公司都能做。治理才是差异化竞争力。


关于作者:欢迎关注微信公众号「小小寰宇」,获取更多 AI 工程化、大模型落地实战干货。