返回博客列表

RAG 回答总是不准?这 7 个环节才是真正的瓶颈

2026-05-22T14:07:00+08:00
RAGLLM准确率RerankingEmbedding向量检索

RAG 回答总是不准?这 7 个环节才是真正的瓶颈

搭过 RAG 的人都知道那种挫败感:文档明明写得很清楚,LLM 就是答不对。你怀疑是模型不够强,换了 GPT-4o、换了 Claude,结果还是一样。

问题大概率不在模型,而在检索。

RAG 的核心链路是 检索 → 拼接 → 生成。大部分团队把 90% 的精力花在生成环节(换模型、调 prompt),但真正决定准确率的,是你喂给模型的那些上下文质量。Garbage in, garbage out。

本文提纲

  1. RAG 准确率的瓶颈在哪
  2. 分块策略:别再按固定字数切了
  3. Embedding 模型:选错模型,检索全废
  4. 混合检索:单靠向量搜索不够
  5. Query 改写:用户的提问和文档的语言不在一个频道
  6. Reranking:把最相关的排在最前面
  7. 上下文压缩:塞太多反而降低准确率

RAG 准确率的瓶颈在哪

先看一个典型的 RAG 链路:

用户提问 → Query 向量化 → 向量检索 → 取 Top-K → 拼接到 Prompt → LLM 生成回答

这条链路上,每个环节都可能出错。但数据告诉我们,检索质量是最大的变量

斯坦福大学的研究表明,当检索到的 Top-K 片段中包含正确答案时,LLM 能正确回答的概率超过 90%。但如果检索不到相关片段,即使是最强的模型也无能为力。

换句话说:只要检索对了,大部分模型都能答对;检索错了,什么模型都白搭。

所以接下来的内容,我们聚焦在检索链路的 7 个关键环节,逐一分析瓶颈和解决方案。

分块策略:别再按固定字数切了

大部分 RAG 入门教程教你按 512 token 或 1000 字切分,加个 50 token 的重叠。这种方式简单粗暴,但对准确率的伤害很大。

问题在哪?

固定长度切分会把完整的语义单元硬生生拆开。一段描述产品定价的文字,前半句在 chunk A,后半句在 chunk B。检索时只命中了 chunk A,LLM 看到的是半截信息,回答当然不完整。

怎么改?

  1. 按语义边界切分:不要按字数,按段落、标题、章节来切。一份产品文档,每个 H2/H3 下的内容就是一个 chunk。
  2. 递归切分(Recursive Chunking):先按最大结构(章节)切,超长的再按段落切,还超长的再按句子切。LangChain 的 RecursiveCharacterTextSplitter 就是这个思路。
  3. 语义切分(Semantic Chunking):把文本转成 Embedding,计算相邻句子的相似度,在相似度骤降的地方断开。这样每个 chunk 内部语义高度相关。

一个实用的判断标准:每个 chunk 应该能独立回答一个完整的问题。如果切出来的 chunk 读起来像半句话,那就是切错了。

Embedding 模型:选错模型,检索全废

Embedding 模型决定了你的文本被表示成什么样的向量。不同模型之间的差距,比大多数人的想象大得多。

几个关键维度:

多语言能力

如果你的文档包含中英文混合内容(代码注释、技术文档),用只支持英文的 Embedding 模型检索中文内容,召回率会惨不忍睹。

推荐选择

  • multilingual-e5-large(Microsoft):多语言场景的标杆,支持 100+ 语言
  • bge-m3(BAAI):中文表现尤其好,同时支持 dense + sparse + multi-vector 三种检索
  • Cohere Embed v3:商用级别,多语言表现优秀

领域适配

通用 Embedding 模型在特定领域(医疗、法律、金融)的表现可能很差,因为这些领域有大量专业术语,通用模型没有学过。

解决方案:微调 Embedding 模型。你只需要准备几百到几千条(query, relevant_doc, irrelevant_doc)三元组,用 contrastive learning 微调,就能在垂直领域获得显著提升。

一个容易被忽略的坑

查询和文档要用同一个模型编码,但可能需要不同的前缀。 很多 Embedding 模型要求在查询前加 "query: ",在文档前加 "passage: "(比如 E5 系列)。不加前缀直接编码,检索质量会下降 20-30%。

混合检索:单靠向量搜索不够

纯向量检索有一个盲区:它擅长语义匹配,但不擅长精确匹配。

比如用户问 "订单号 ORD-20240315-8821 的物流状态",向量检索可能找到其他包含 "物流状态" 的文档片段,但精确匹配不到那个订单号。

解决方案是混合检索(Hybrid Search):把向量检索(dense)和关键词检索(sparse)结合起来。

混合得分 = α × 向量相似度 + (1 - α) × BM25 得分

α 通常取 0.5-0.7,根据你的场景调整。语义理解为主的场景 α 大一些,精确匹配重要的场景 α 小一些。

工具选择:

  • Milvus:原生支持混合检索
  • Weaviate:内置 hybrid search
  • Qdrant:支持 sparse vectors
  • Elasticsearch 8.x:内置 kNN search + BM25,开箱即用

实践经验:混合检索几乎总是比纯向量检索好。如果你的 RAG 还在只用向量搜索,加上 BM25,通常能立刻看到准确率提升。

Query 改写:用户的提问和文档不在一个频道

用户问 "怎么退款",但文档里写的是 "取消订单与退款流程"。语义相近,但向量空间里的距离可能很远。

几种有效的 Query 改写技术:

1. HyDE(Hypothetical Document Embedding)

思路很巧妙:先让 LLM 根据用户的问题,生成一个"假想的答案",然后用这个假想答案去做向量检索。

用户问题: "怎么退款"
→ LLM 生成假想答案: "用户可以在订单详情页面点击取消订单,选择退款原因,提交退款申请..."
→ 用假想答案做 Embedding 检索

假想答案的语言风格和文档更接近,所以检索效果通常比直接用 query 好很多。

2. Multi-Query

把用户的一个问题扩展成多个不同角度的问题,分别检索,然后合并结果。

原始: "怎么退款"
扩展:
  1. "退款流程是什么"
  2. "如何申请退款"  
  3. "取消订单后退款多久到账"

这样可以从不同角度命中相关文档,大幅提高召回率。

3. Step-back Prompting

让 LLM 先问一个更宏观的问题,检索背景知识,再用原始问题检索具体细节。

原始: "Python 的 GIL 对多线程有什么影响"
→ 宏观问题: "Python 的线程模型是怎样的"
→ 先检索宏观知识,再检索具体问题

4. Query Compression(多轮对话场景)

多轮对话中,用户的提问往往依赖上下文:

用户: "Python 和 Go 哪个快?"
模型: "Go 在并发场景下通常更快..."
用户: "那 Web 开发呢?"  ← 脱离上下文根本不知道在问什么

需要把历史对话和当前 query 压缩成一个独立的检索 query:"Python 和 Go 在 Web 开发场景下的性能对比"

Reranking:把最相关的排在最前面

向量检索召回的 Top-K 结果,相关度排序往往不准。原因是向量检索做的是粗筛——它用单一的向量相似度去近似文本相关性,但真正的相关性要复杂得多。

Reranking 就是在粗筛之后做精排。

把检索到的 Top-K(比如 Top-20)交给一个专门的 Reranking 模型,让它对每一对 (query, document) 做精细的相关性打分,然后重新排序,取 Top-N(比如 Top-5)喂给 LLM。

Reranking 模型的选择:

模型 特点 适用场景
bge-reranker-v2-m3 开源,中英文表现好 中文场景首选
Cohere Rerank API 调用,效果好 不想自建服务
Jina Reranker v2 开源,速度快 低延迟场景
cross-encoder/ms-marco-MiniLM 轻量级 资源受限场景

Reranking 是提升 RAG 准确率性价比最高的一步。 很多团队的实践经验是:加一个 Reranker,准确率直接从 60-70% 跳到 80-90%,投入产出比极高。

一个小技巧:Reranking 之前取 Top-20 甚至 Top-50,Reranking 之后取 Top-5。给 Reranker 更多的候选,它才有更大的概率把真正相关的片段排上来。

上下文压缩:塞太多反而降低准确率

"Lost in the Middle" 是 LLM 的一个已知问题:放在 Prompt 中间位置的信息,被模型"看到"的概率显著低于开头和结尾。

这意味着你塞了 10 个 chunk,排在第 5、6 位的那个最相关的片段,可能被模型忽略了。

解决方案:

1. 少即是多

不要贪多。Reranking 之后取 Top-3 到 Top-5 就够了。与其塞 10 个质量参差不齐的 chunk,不如只给 3 个高度相关的 chunk。

2. 相关片段放两头

把最相关的 chunk 放在 Prompt 的开头和结尾,次相关的放中间。这个简单的位置调整就能带来明显的提升。

3. 上下文压缩(Context Compression)

用一个小模型对每个 chunk 做摘要,只保留和 query 相关的部分。比如一段 500 字的文档片段,压缩成 100 字的相关内容。这样同样的 token 预算下,你能塞入更多的信息。

4. Metadata 过滤

在检索之前,先根据 metadata 做过滤。比如用户问的是"2024 年的销售数据",你先用 metadata 过滤掉所有非 2024 年的文档,再做向量检索。这样既减少了噪音,也降低了检索范围。

用户: "2024年Q3的销售数据"
→ Metadata 过滤: year=2024, quarter=Q3, type=financial_report
→ 在过滤后的子集中做向量检索
→ Reranking
→ Top-5 喂给 LLM

完整的优化链路

把上面 7 个环节串起来,一个高准确率的 RAG 系统应该是这样的:

flowchart LR
    A[User Query] --> B[Query Rewrite]
    B --> C[Multi-Query Expansion]
    C --> D[Dense + Sparse Hybrid Search]
    D --> E[Metadata Filter]
    E --> F[Top-K Recall]
    F --> G[Reranking]
    G --> H[Top-N Selection]
    H --> I[Context Compression]
    I --> J[LLM Generation]
    J --> K[Answer]

每个环节都在提升信息的信噪比。最终喂给 LLM 的,应该是少量、高度相关、没有冗余的上下文。

不需要一步到位。 优先级建议:

  1. 先加 Reranking——性价比最高,当天就能见效
  2. 再改分块策略——从固定长度切分改成语义切分
  3. 然后上混合检索——加上 BM25,几乎总是比纯向量好
  4. 接着做 Query 改写——HyDE 或 Multi-Query,看场景选择
  5. 最后考虑 Embedding 微调——垂直领域效果明显,但需要准备数据

别一上来就换模型、调 prompt。先看看你喂给模型的东西对不对。


作者: itech001
来源: 公众号:AI人工智能时代
网站: https://www.theaiera.cn/
每日分享最前沿的AI新闻资讯和技术研究。

关注公众号,获取更多 AI 技术干货!

觉得文章不错?分享给更多人!