Chapter 4 :查询链路上的 RAG 优化

预览

本章套路 用户问题进入 RAG 系统之后,如何被理解、改写、路由、检索、重排、压缩,最终变成更可靠的上下文

可以把本章理解为:

用户原始问题
-> 查询理解 / 查询重构 / 查询构建 / 查询路由
-> 选择合适的数据源和检索方式
-> 向量检索 / 混合检索 / 元数据过滤 / Text2SQL / Text2Cypher
-> 重排 / 压缩 / 校正
-> 给 LLM 更准确、更干净的上下文
-> 生成答案

分为几个部分

  1. 混合检索:提高召回质量。
  2. 查询构建:把自然语言转成结构化查询。
  3. Text2SQL:让自然语言查询关系型数据库。
  4. 查询重构与路由:让问题变成更适合系统处理的形式。
  5. 重排、压缩、校正:优化检索后的上下文质量。

结论:

让 RAG 检索阶段拿到更有用的信息,而不是盲目相信一次向量搜索。

1. 混合检索

混合检索是把多种检索方式结合起来,最典型的是:

稀疏向量检索 + 密集向量检索

稀疏向量

稀疏向量更像“词典 / 倒排索引”:

词项 -> 出现在哪些文档里 -> 权重是多少

它关注的是:

有没有这个词

适合:

  • 产品型号
  • 人名
  • 代码符号
  • 专有名词
  • 必须精确匹配的关键词

缺点是:不理解语义。

例如“番茄”和“西红柿”可能被当成不同词。

密集向量

密集向量关注的是:

意思像不像

同一个 embedding 模型会把文本映射到同一个向量空间里,语义接近的文本距离更近。

例如:

西红柿炒蛋
番茄炒鸡蛋
家常鸡蛋菜

在语义空间中应该更接近。

缺点是:可能忽略精确关键词,也不太可解释。

为什么要混合

单独使用一种检索方式都有短板:

稀疏检索:精确但不懂语义
密集检索:懂语义但可能漏关键词

混合检索就是:

既看词对不对,也看意思像不像

RRF

RRF 是 Reciprocal Rank Fusion,倒数排序融合。

它不直接比较不同检索器的原始分数,而是比较排名:

一个文档如果在多个检索结果中都排得靠前,它就更可能重要。

RRF 适合融合不同来源的检索结果,因为不同检索器的分数往往不可直接比较。

2. 查询构建

查询构建的核心是:

把用户自然语言问题变成某种结构化查询。

它让 RAG 不只是做语义相似度搜索,还能使用结构化条件。

文本到元数据过滤器

示例:

用户问:时长大于600秒的视频

系统可以把它转换成:

语义查询:视频
元数据过滤:length > 600

然后向量数据库执行:

语义检索 + metadata filter

这就是 SelfQueryRetriever 的作用。

它会让 LLM 根据字段说明,把自然语言拆成:

query string
metadata filter
limit

局限

它对过滤类问题效果比较好,比如:

时长大于600秒的视频
观看次数超过10000的视频

但对排序类问题不一定好,比如:

时间最短的视频
播放量最高的视频

因为这类问题需要:

排序字段 + 排序方向 + 取 top1

普通 metadata filter 不一定能表达完整排序逻辑。

这也是后面查询重构要解决的问题。

文本到 Cypher

Cypher 是图数据库查询语言,类似 SQL 之于关系型数据库。

文本到 Cypher 的思路是:

自然语言问题
-> LLM 根据图谱 Schema 生成 Cypher
-> 图数据库执行查询
-> 返回结果

它和 Text2SQL 的本质一样:都是把自然语言转成结构化查询语言。

3. Text2SQL

用户用自然语言提问
系统生成 SQL
数据库执行 SQL
返回结构化结果

为什么 Text2SQL 需要 RAG

LLM 本身不知道你的数据库结构。

如果直接让它写 SQL,容易出现:

  • 幻觉出不存在的表
  • 幻觉出不存在的字段
  • JOIN 关系写错
  • 条件字段用错
  • SQL 能执行但语义不对

所以需要给它“开卷资料”。

Milvus 在 Text2SQL 中存什么

这里 Milvus 不是存业务数据,而是存 Text2SQL 的知识库:

DDL 表结构
Q-SQL 示例
表和字段描述

这些不是训练数据,而是运行时检索用的参考资料。

可以理解成:

训练数据:用于改变模型参数
RAG 知识库:用于运行时检索,增强 prompt

在 Text2SQL 里,Milvus 存的是“数据库说明书”和“SQL 参考例题”。

4. 查询重构与分发

查询重构的目标是:

把用户原始问题变成更适合检索或推理的形式。

用户的问题往往不是最好的检索输入。

它可能:

  • 太口语
  • 太复杂
  • 有多个意图
  • 缺少关键词
  • 和文档表达不一致
  • 需要排序、聚合或路由

查询翻译

查询翻译就是把问题改写成更适合系统处理的形式。

例如把:

时间最短的视频

改成结构化指令:

{"sort_by": "length", "order": "asc"}

这比普通自然语言更适合程序执行。

Multi-query

Multi-query 是把一个复杂问题拆成多个子问题。

例如:

刘慈欣在《流浪地球》中如何看待人工智能和未来社会结构?

可以拆成:

《流浪地球》中的人工智能有哪些?
《流浪地球》中的未来社会结构是什么?
刘慈欣对人工智能的观点是什么?

然后分别检索,再合并结果。

Step-Back Prompting

Step-Back 是“退一步问更抽象的问题”。

例如具体问题需要一个物理定律,系统先问:

这个问题背后的通用原理是什么?

再用通用原理回答原问题。

适合需要推理的场景。

HyDE

HyDE 是 Hypothetical Document Embeddings。

它的思路是:

先让 LLM 生成一篇假设性答案文档
-> 把这篇假设文档向量化
-> 用它去检索真实文档

它把:

query-to-document

变成:

document-to-document

适合用户问题很短、关键词不足的场景。

查询路由

查询路由的目标是:

判断这个问题应该交给哪个数据源、检索器、工具或专家链。

比如:

订单问题 -> SQL 数据库
公司关系问题 -> 图数据库
文档问答 -> 向量知识库
川菜问题 -> 川菜专家 prompt
粤菜问题 -> 粤菜专家 prompt

5. 两种路由方式

LLM 路由

LLM 路由是让大模型直接判断分类。

流程:

用户问题
-> LLM 分类
-> RunnableBranch 选择不同 chain
-> 对应专家链回答

优点:

  • 灵活
  • 能理解复杂意图
  • 适合分类边界不清晰的场景

缺点:

  • 有 API 成本
  • 有延迟
  • 分类可能不稳定

Embedding 路由

Embedding 路由不让 LLM 分类,而是用向量相似度。

流程:

先写几段路由描述
-> 把路由描述转成向量
-> 用户问题也转成向量
-> 谁相似度最高,就走谁的 chain

优点:

  • 成本低
  • 适合固定路由集合

缺点:

  • 依赖路由描述写得好不好
  • 不如 LLM 灵活
  • 路由集合复杂时容易误判

可以这样记:

LLM 路由:像人工分诊
Embedding 路由:像语义最近邻匹配

6. 检索进阶:重排、压缩、校正

基础检索拿到的结果不一定适合直接喂给 LLM。

常见问题:

  • 最相关内容不一定排在最前
  • 文档块太长
  • 文档里有很多噪声
  • 多个 chunk 内容重复
  • 检索结果可能不相关
  • 检索结果可能过时或错误

所以需要后处理。

重排

重排是:

先粗召回一批文档
-> 再用更精细的方法重新排序

常见方法:

  • RRF
  • RankLLM
  • Cross-Encoder
  • ColBERT
RRF

RRF 用多个检索器的排名融合结果。

适合多路召回结果合并。

RankLLM

RankLLM 让 LLM 判断哪些文档更相关。

优点是语义理解强,缺点是贵、慢。

Cross-Encoder

Cross-Encoder 把:

query + document

拼在一起送进模型,直接输出相关性分数。

优点是精度高,缺点是每个候选文档都要单独跑一次,比较慢。

ColBERT

ColBERT 是折中方案。

它分别编码 query 和 document,然后在 token 级别做 MaxSim 匹配。

可以理解成:

不只看整句话像不像,也看每个关键 token 能不能在文档里找到强匹配。

压缩

压缩是:

把检索到的长文档变短,只保留和问题相关的部分。

常见方式:

  • 抽取相关句子
  • 丢弃不相关文档
  • 让 LLM 提取重点片段

在代码中:

基础检索 Top-K
-> ColBERT 风格重排
-> LLMChainExtractor 压缩
-> 返回更聚焦的上下文

你运行后能看到,基础检索结果比较泛,但压缩后明显聚焦到:

AI 生成内容不准确
表达流畅但可能严重错误
内部模式僵化
需要改进推理策略

这说明后处理确实能让上下文更干净。

重复问题

压缩后的结果可能有重复。

原因通常是:

原始分块有 overlap
基础检索召回了相似 chunk
LLM 压缩时提取了相近句子

解决方向:

  • 减小 chunk overlap
  • 改分块策略
  • 对检索结果去重
  • 对压缩结果去重

校正检索 C-RAG

C-RAG 是 Corrective RAG。

核心思想:

不要盲目信任检索结果。
先评估检索结果是否真的能回答问题。

流程:

Retrieve 检索
-> Assess 评估
-> Act 行动

行动可能是:

  • 检索结果正确:精炼后生成
  • 检索结果错误:改写查询或外部搜索
  • 检索结果模糊:补充检索

总结

RAG 的关键不只是“检索”,而是“怎么把用户问题变成适合检索的问题”。

基础 RAG 可能只是:

用户问题 -> 向量检索 -> LLM 回答

高级一点的 RAG 会变成:

用户问题
-> 判断意图
-> 改写 / 拆分 / 结构化 / 路由
-> 选择合适检索方式
-> 检索后重排 / 压缩 / 校正
-> 再生成答案

所以本章可以理解为:

Query-time RAG Optimization

也就是查询时优化。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐