副标题:从入门到精通
📖 本书简介
本书系统地介绍了 RAG(检索增强生成)系统中的查询优化技术,从基础概念到高级应用,从理论原理到实践代码,帮助读者全面掌握提升 RAG 检索效果的核心技术。
🎯 适合读者
- 初学者:想了解 RAG 检索优化的入门读者
- 开发者:正在构建 RAG 系统的工程师
- 面试官:想了解 RAG 技术面试要点的招聘者
- 研究者:关注信息检索与 LLM 结合的研究人员
📚 核心内容
- Query Rewriting(查询重写) - 让问题更清晰
- HyDE(假设文档嵌入) - 用答案搜答案
- Multi-Query(多查询检索) - 多角度问问题
- 评估指标 - MRR、NDCG 详解
- 结果融合 - RRF 倒数排名融合
- 五大策略 - 速度/召回/平衡/成本/质量优先
💡 本书特色
- ✅ 12 岁能听懂:复杂概念用比喻和故事解释
- ✅ 面试导向:每个章节都有面试回答模板
- ✅ 代码实战:完整的 Python 实现示例
- ✅ 成本分析:详细的性能与成本对比
- ✅ 策略选择:不同场景的最优方案
版本信息
- 版本:v1.0
- 整理日期:2026-04-13
================================================================================
RAG 查询优化技术 学习指南 目录
第一部分:基础概念
第 1 章 Query Rewriting(查询重写)
- 通俗理解(12 岁能听懂)
- 三种主要方法
- 为什么需要它
- 面试回答指南(3 分钟版本)
- 技术架构
- 常见追问
第 2 章 评估指标:MRR 和 NDCG
- MRR 通俗理解与计算
- NDCG 通俗理解与计算
- MRR vs NDCG 对比
- 面试回答模板
第二部分:核心技术
第 3 章 HyDE(假设文档嵌入)
文件: 04-hyde.md
- 通俗理解(12 岁能听懂)
- 面试回答指南
- 为什么有效(4 个原因)
- 反直觉的事实
- 适用场景
- 与 Query Rewriting 对比
第 4 章 Multi-Query(多查询检索)
- 通俗理解(12 岁能听懂)
- 核心概念拆解
- 与 Query Rewriting 对比
- 面试回答指南
- 优势与成本分析(6-8 倍详解)
- 优化策略
第 1 章 Query Rewriting(查询重写)
1.1 通俗理解(12 岁能听懂)
问题从这里开始 📚
想象你有一个特别聪明的图书管理员朋友,但你不会说话,总是说不清楚自己想要什么书。
假设你想找关于"苹果"的资料,但你只说了两个字:
"苹果"
图书管理员会想:
- 是要找苹果水果的营养资料?
- 还是要找苹果公司的产品?
- 还是要找苹果手机的评测?
你说的话太简单了,图书管理员帮不到你。
Query Rewriting 就像一个"翻译官" 🔄
查询重写的作用就是:把你说的简单问题,翻译成清楚的问题。
| 你说的 | 重写后变成 |
|---|---|
| "苹果" | "苹果公司的历史和主要产品" |
| "怎么胖了" | "如何通过饮食和运动健康增重" |
| "python list" | "Python 编程语言中列表的使用方法" |
三种主要方法 🔧
1. 补全信息
把缺少的部分补上。
- 你说:"怎么变强?"
- 重写:"如何通过锻炼让肌肉变强?"
2. 换个说法
用更容易理解的方式说同一件事。
- 你说:"AI 咋回事?"
- 重写:"人工智能的基本原理是什么?"
3. 拆开问
一个大问题拆成几个小问题。
- 你说:"怎么学好编程?"
- 重写:
- "编程入门需要学什么?"
- "如何提高编程能力?"
- "有哪些编程学习资源?"
为什么需要它?🎯
在 RAG(检索增强生成)系统里,如果查询不清楚,就找不到正确的资料。
就像一个搜索引擎:
- 你搜 "python" → 可能找到蛇的资料 🐍
- 重写后搜 "Python 编程语言教程" → 找到正确的编程资料 💻
查询重写让你的问题更容易被搜索引擎理解,找到更准确的答案。
一张图总结
原始问题 → [查询重写] → 清晰的问题 → [搜索] → 更好的答案
❌ ✅ ✅ ✅ ✅
模糊 翻译一下 容易搜索 找到资料 解决问题
就像你有一个会说话的朋友,帮你把磕磕巴巴的话变成清楚的问题!
1.2 面试回答指南
回答框架(3 分钟版本)
1️⃣ 先给定义(15 秒)
"Query Rewriting 就是把用户的原始查询转换成更适合检索的形式,目的是提高检索的准确率。"
2️⃣ 说明为什么需要(30 秒)
"用户查询通常有两个问题:
- 太简短 —— 比如只搜 'python',不知道是蛇还是编程语言
- 表述模糊 —— 比如 '怎么变强',缺少上下文
直接拿这种查询去检索,召回的文档质量会很差,后续生成也会受影响。"
3️⃣ 讲核心技术(1 分钟)
"主要有三种方法:
① 查询扩展(Query Expansion)
- 添加同义词或相关词,比如 '手机' → '智能手机 评测 推荐'
- 技术:可以用 LLM 生成、可以用词向量找近义词
② 查询改写(Query Reformulation)
- 换个更清晰的说法,比如 'AI 咋回事' → '人工智能基本原理'
- 技术:通常用 LLM 做 paraphrase
③ 查询分解(Query Decomposition)
- 把复杂问题拆成多个子问题,比如 '对比 iPhone 和华为'
- 'iPhone 的主要特点'
- '华为手机的主要特点'
- 技术:LLM + 提示词工程"
4️⃣ 结合实际应用(30 秒)
"在 RAG 系统里,查询重写通常放在检索之前:
用户查询 → [Query Rewriting] → [检索] → [生成]我在项目里用过 LLM 来做重写,比如用这样一个 prompt:
将以下查询改写成更适合搜索引擎的形式: 原始查询:{query} 要求:补充上下文,使用明确术语效果提升很明显,尤其是处理简短查询时。"
5️⃣ 加分项(可选,展示深度)
"进阶做法还有:
- 多查询检索:生成 3-5 个变体并行检索,然后去重融合
- 用户历史感知:结合用户之前的查询补充上下文
- 假设文档嵌入(HyDE):让 LLM 生成一个假设答案,用答案的嵌入去检索"
1.3 面试小贴士
| 要点 | 说明 |
|---|---|
| 先给定义 | 让面试官知道你真的懂 |
| 结构化 | 用 1、2、3 分点说,显得有条理 |
| 结合实际 | 说一个你用过的具体方法/项目 |
| 不要背概念 | 用自己的话讲,可以举例 |
1.4 常见追问
Q: 怎么评估查询重写的效果?
"看检索阶段的指标,比如 MRR、NDCG,或者看最终答案质量(人工评估或 LLM-as-a-judge)"
Q: 重写会不会引入噪声?
"会,所以要控制重写幅度。可以用少样本提示让 LLM 保持原意,或者设置置信度阈值,低置信度时用原始查询"
Q: 和 RAG 其他优化方法比怎么样?
"查询重写是查询侧优化,和索引侧优化(比如 chunk 策略、元数据过滤)是互补的,可以一起用"
1.5 技术架构
┌─────────────┐ ┌──────────────────┐ ┌──────────┐ ┌──────────┐
│ 用户查询 │ → │ Query Rewriting │ → │ 检索器 │ → │ 生成器 │
│ (原始问题) │ │ (查询重写模块) │ │ (Retriever)│ │ (Generator)│
└─────────────┘ └──────────────────┘ └──────────┘ └──────────┘
│
├──→ 查询扩展 (同义词、相关词)
├──→ 查询改写 (Paraphrase)
└──→ 查询分解 (多子问题)
1.6 核心要点总结
关键概念
- 定义:将原始查询转换为更适合检索的形式
- 目标:提高检索准确率
- 位置:检索前的预处理步骤
三种方法
| 方法 | 做法 | 示例 |
|---|---|---|
| 查询扩展 | 添加同义词 | "手机" → "智能手机 评测 推荐" |
| 查询改写 | 换说法 | "AI 咋回事" → "人工智能基本原理" |
| 查询分解 | 拆问题 | "对比 A 和 B" → "A 的特点"+"B 的特点" |
面试关键词
- 翻译官比喻
- 检索前优化
- 补充上下文
- LLM 生成
================================================================================
第 2 章 评估指标:MRR 和 NDCG
2.1 MRR(平均倒数排名)
通俗理解
MRR 只关心:第一个正确答案排在第几名?
计算例子
假设有 3 个用户查询,每个查询的检索结果如下(✓ 表示正确答案):
| 查询 | 排名 1 | 排名 2 | 排名 3 | 排名 4 | 排名 5 | 第一个正确答案的排名 | 倒数 (1/排名) |
|---|---|---|---|---|---|---|---|
| 查询 1 | ✗ | ✗ | ✓ | ✗ | ✗ | 3 | 1/3 ≈ 0.333 |
| 查询 2 | ✓ | ✗ | ✗ | ✗ | ✗ | 1 | 1/1 = 1.0 |
| 查询 3 | ✗ | ✓ | ✗ | ✗ | ✗ | 2 | 1/2 = 0.5 |
MRR = (0.333 + 1.0 + 0.5) ÷ 3 = 1.833 ÷ 3 ≈ 0.611
公式
其中:
- = 查询总数
- = 第 i 个查询的第一个正确答案的排名
特点
| 优点 | 缺点 |
|---|---|
| 计算简单,好理解 | 只关心第一个正确答案 |
| 适合只要找到一个答案就足够的场景 | 不关心后面还有多少正确答案 |
| 值域 [0, 1],1 最好 | 如果前 10 个都没答案,MRR=0 |
适用场景
- 问答系统(用户只需要一个正确答案)
- 客服机器人
- 事实性查询("珠穆朗玛峰多高")
2.2 NDCG(归一化折损累计增益)
通俗理解
NDCG 关心两件事:
- 正确答案有没有排在前面?
- 越相关的答案是不是排得越靠前?
核心思想
NDCG 有三个关键概念:
① 相关性打分 (Gain) 给每个结果打分(0-3 分):
- 3 分 = 非常相关
- 2 分 = 比较相关
- 1 分 = 有点相关
- 0 分 = 不相关
② 折损 (Discounted) 排名越靠后,价值越低。公式:
折损后的增益 = 相关性得分 / log₂(排名 + 1)
| 排名 | 折损因子 | 说明 |
|---|---|---|
| 1 | 1.0 | 无折损 |
| 2 | 0.63 | 打 6 折 |
| 3 | 0.5 | 打 5 折 |
| 5 | 0.35 | 打 35 折 |
| 10 | 0.21 | 打 2 折 |
③ 归一化 (Normalized) 除以"理想情况下的最高分",让结果在 0-1 之间。
完整计算例子
用户搜 "python 教程",检索结果和相关性打分:
| 排名 | 文档 | 相关性 (0-3) | 折损因子 | 折损后增益 |
|---|---|---|---|---|
| 1 | Python 入门教程 | 3 | 1.0 | 3.0 |
| 2 | Python 进阶 | 2 | 0.63 | 1.26 |
| 3 | Python 网站 | 3 | 0.5 | 1.5 |
| 4 | Python 新闻 | 1 | 0.39 | 0.39 |
| 5 | 蟒蛇饲养指南 | 0 | 0.32 | 0 |
DCG@5 = 3.0 + 1.26 + 1.5 + 0.39 + 0 = 6.15
理想排序(IDCG) 应该是把最相关的排前面:
| 排名 | 理想相关性 | 折损因子 | 折损后增益 |
|---|---|---|---|
| 1 | 3 | 1.0 | 3.0 |
| 2 | 3 | 0.63 | 1.89 |
| 3 | 2 | 0.5 | 1.0 |
| 4 | 1 | 0.39 | 0.39 |
| 5 | 0 | 0.32 | 0 |
IDCG@5 = 3.0 + 1.89 + 1.0 + 0.39 + 0 = 6.28
NDCG@5 = DCG / IDCG = 6.15 / 6.28 = 0.98
(越接近 1 越好,0.98 说明排序非常接近理想状态)
2.3 MRR vs NDCG 对比
| 维度 | MRR | NDCG |
|---|---|---|
| 关心什么 | 第一个正确答案 | 所有结果的相关性 + 排序 |
| 相关性分级 | 只有对/错 | 可以有 0-3 多级 |
| 适用场景 | 问答、事实查询 | 搜索、推荐 |
| 计算复杂度 | 简单 | 较复杂 |
| 如果第一个就对了 | MRR=1 | NDCG 可能 <1(后面排错了) |
2.4 面试回答模板
如果面试官问:"怎么评估 RAG 的检索效果?"
"检索阶段的评估主要看两个指标:
MRR(平均倒数排名):只关心第一个正确答案排第几名。适合问答系统,因为用户通常只需要一个正确答案。计算公式是 1/排名,MRR 越接近 1 越好。
NDCG(归一化折损累计增益):同时考虑相关性和排序质量。它假设:① 相关性有等级(0-3 分),② 排名越靠后价值越低。NDCG 也适合搜索场景,因为用户会浏览前几条结果。
在 RAG 里,如果更关注答案质量,用 MRR;如果更关注检索文档的整体相关性,用 NDCG。实际项目中,我通常会同时监控这两个指标。"
2.5 一张图总结
┌─────────────────────────────────────────────────────────────┐
│ MRR vs NDCG 对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ MRR(平均倒数排名) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 只关心:第一个正确答案排第几? │ │
│ │ 公式:1/排名 │ │
│ │ 场景:问答系统、事实查询 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ NDCG(归一化折损累计增益) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 关心两件事: │ │
│ │ ① 正确答案有没有排前面? │ │
│ │ ② 越相关的是不是越靠前? │ │
│ │ 场景:搜索、推荐 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 选择建议: │
│ ├── 用户只需要一个答案 → MRR │
│ ├── 用户会浏览多个结果 → NDCG │
│ └── 实际项目 → 两个都监控 │
│ │
└─────────────────────────────────────────────────────────────┘
2.6 核心要点总结
MRR 关键点
- 只看第一名:只关心第一个正确答案的排名
- 计算简单:1/排名,然后求平均
- 适合问答:用户只需要一个正确答案的场景
NDCG 关键点
- 看全部:考虑所有结果的相关性
- 看排序:越相关的应该越靠前
- 多级相关:可以有 0-3 分的细致打分
面试关键词
- 倒数排名
- 折损累计增益
- 相关性分级
- 排序质量
================================================================================
第 3 章 HyDE(假设文档嵌入)
3.1 通俗理解(12 岁能听懂)
一个故事
情景 1:直接去找
你想找一本关于**"恐龙"**的书,跑到图书馆对图书管理员说:
"恐龙"
图书管理员很困惑,可能给你一本恐龙图片书、恐龙知识书、或恐龙故事书——不一定准确。
情景 2:先描述答案,再去找
这次你先请一个很聪明的朋友帮你想象:
"一本讲恐龙的书,里面应该有:霸王龙、三角龙、侏罗纪、化石、灭绝原因..."
然后你拿着这个描述去找图书管理员:
"我想找一本讲霸王龙、三角龙、侏罗纪时期、恐龙化石和灭绝原因的书"
图书管理员马上就知道你要什么了!
HyDE 就是这个"聪明的朋友"。
HyDE 的核心思想
先编一个"假答案",再用这个"假答案"去找"真答案"
工作流程
你问:"恐龙怎么灭绝的?"
↓
┌────────────────────┐
│ HyDE (聪明朋友) │
│ 帮你编一个假答案: │
│ "恐龙灭绝是因为..." │
└────────────────────┘
↓
用"假答案"去搜索
↓
找到"真答案"的文档
3.2 面试回答指南(2-3 分钟版本)
1️⃣ 先给定义(20 秒)
"HyDE 是 Hypothetical Document Embeddings 的缩写,中文叫'假设文档嵌入'。
它的核心思想是:先让 LLM 生成一个假设的答案,再用这个假设答案的向量表示去检索真实文档。
简单说,就是'用答案搜答案',而不是'用问题搜答案'。"
2️⃣ 说明为什么需要(30 秒)
"直接检索用户查询有两个问题:
① 问题空间和答案空间不一致
- 用户问:'怎么减肥?'
- 文档写:'控制饮食摄入,增加运动频率...'
- '减肥'和'控制饮食'字面不同,但语义相关
② 查询太简短,信息密度低
- 用户只搜 'python list',嵌入向量包含的语义信息很少
这两种情况都导致检索效果不好。"
3️⃣ 讲工作原理(40 秒)
"HyDE 的流程分三步:
第一步:生成假设答案 用 LLM 根据用户问题生成一个假设的答案文档。
第二步:嵌入假设答案 把假设答案转换成向量表示。
第三步:检索相似文档 用假设答案的向量去检索,找到语义相似的真实文档。
关键在于:即使假设答案内容不准确,它的语言风格、关键词、语义方向都和真实文档接近,所以向量表示也接近。"
4️⃣ 说明为什么有效(40 秒)
"HyDE 有效有三个原因:
① 填补语义鸿沟 把'问题空间'映射到'答案空间',让查询和文档在同一语义空间里。
② 利用 LLM 的预训练知识 LLM 读过大量文本,知道答案通常长什么样、包含哪些关键词。
③ 增加信息密度 假设答案比原始查询更长、更具体,嵌入向量包含更多语义信息。
实验表明,HyDE 在开放型问答、复杂查询上效果提升明显。"
5️⃣ 结合实际应用(20 秒)
"在我的 RAG 项目里,我试过 HyDE 的方法:
# 伪代码 hypothetical_doc = llm.generate(f"请为以下问题生成一个详细的答案:{query}") query_embedding = embedder.encode(hypothetical_doc) results = vector_db.search(query_embedding, top_k=5)对于简短查询和复杂问题,检索质量确实有提升,但会增加一次 LLM 调用和一点延迟。"
3.3 HyDE 为什么有效?(深入理解)
原因 1:填补"问题 - 答案"的语义鸿沟
问题空间和答案空间不一样
| 问题 | 答案 |
|---|---|
| "怎么减肥?" | "控制饮食摄入,增加有氧运动..." |
| "手机坏了怎么办?" | "设备故障排除指南:重启..." |
- 问题用疑问句,答案用陈述句
- 问题用口语,答案用专业术语
- 问题说目标,答案说方法
HyDE 的做法
让 LLM 生成一个假设答案,把问题翻译成答案的风格:
问题:"怎么减肥?"
↓
HyDE 翻译成答案风格:
"减肥需要控制饮食摄入,增加有氧运动..."
↓
用这个去搜,就能找到写"控制饮食"的文档了!
原因 2:利用 LLM 的世界知识
LLM 在预训练时读过大量文本,它知道:
- 答案通常长什么样
- 答案会用哪些关键词
- 答案的结构是什么
即使 LLM 生成的假设答案内容不对,它的向量表示仍然能和真实答案对齐。
原因 3:缓解"词汇不匹配"问题
传统检索的问题
用户搜:"手机坏了怎么办" 文档里写:"设备故障排除指南"
手机 vs 设备,坏了 vs 故障 —— 字面不一样。
HyDE 的做法
LLM 生成假设答案:
"如果手机出现故障,可以尝试以下方法:1. 重启设备 2. 恢复出厂设置 3. 联系售后服务中心..."
这个假设答案会同时包含用户的词和文档的词,起到词汇桥接的作用。
原因 4:增加查询的信息密度
| 原始查询 | 嵌入向量信息量 |
|---|---|
| "python list" | 低(就两个词) |
| "Python 中列表的使用方法,包括创建、访问、修改列表元素的示例代码" | 高 |
HyDE 生成的假设答案更长、更具体,包含更多可嵌入的语义信息。
3.4 一个反直觉的事实
HyDE 的假设答案不需要正确!
实验表明,即使假设答案内容是错的,只要:
- 语言风格像答案
- 关键词覆盖到位
- 语义方向正确
就能有效提升检索效果。
这是因为嵌入空间里,相似主题的文档聚在一起,假设答案只需要落在正确的"语义区域"即可。
3.5 适用场景
| 适合 | 不适合 |
|---|---|
| 问答型查询("什么是 X") | 导航型查询("某某官网") |
| 开放性问题 | 事实性查询("珠穆朗玛峰多高") |
| 需要解释的问题 | 简单检索("python 官网") |
3.6 与 Query Rewriting 对比
| 方法 | 做法 | 比喻 |
|---|---|---|
| Query Rewriting | 把问题说得更清楚 | 翻译官 |
| HyDE | 编一个答案去找答案 | 美食家 |
两者都是让检索更准确,但方法不同!
3.7 常见追问及回答
Q: HyDE 和 Query Rewriting 有什么区别?
"两者目标相似但方法不同:
维度 Query Rewriting HyDE 做法 改写问题 生成答案 嵌入对象 改写后的问题 假设答案 核心优势 让问题更清晰 桥接问题 - 答案空间 延迟 低(一次 LLM) 中(一次 LLM+ 嵌入) 实际项目里可以一起用:先重写查询,再用 HyDE 检索。"
Q: 假设答案如果错了怎么办?
"这是 HyDE 反直觉的地方——假设答案不需要正确。
因为我们要的不是答案内容,而是它的向量表示。只要:
- 语言风格像答案
- 关键词覆盖到位
- 语义方向正确
就能找到正确的文档。实验表明,即使假设答案有事实错误,检索效果依然提升。"
Q: 怎么评估 HyDE 的效果?
"看检索阶段的指标:
- MRR:第一个正确答案的排名
- NDCG:整体排序质量
- Recall@K:前 K 个结果里有多少正确答案
也可以看最终答案质量,用人工评估或 LLM-as-a-judge。
我在项目里对比过,HyDE 对简短查询的 MRR 提升约 10-15%。"
3.8 一张图总结
┌──────────────────────────────────────────────────────────┐
│ HyDE 工作流程 │
├──────────────────────────────────────────────────────────┤
│ │
│ 用户问题 HyDE │
│ ┌─────────┐ ┌─────────────┐ │
│ │ "如何 │ │ 假设答案: │ │
│ │ 减肥?" │ ────────────→│ 控制饮食、 │ │
│ └─────────┘ 生成假设 │ 增加运动... │ │
│ └─────────────┘ │
│ ↓ │
│ 传统检索:问题 → 文档 用假设答案嵌入检索 │
│ 鸿沟大 ❌ 鸿沟小 ✅ │
│ │
│ 结果:找到"科学减重指南"等真实文档 │
│ │
└──────────────────────────────────────────────────────────┘
3.9 核心要点总结
HyDE 关键点
- 核心思想:用答案搜答案
- 三步流程:生成假设答案 → 嵌入 → 检索
- 反直觉:假设答案不需要正确
为什么有效
- 填补问题 - 答案语义鸿沟
- 利用 LLM 预训练知识
- 缓解词汇不匹配
- 增加信息密度
面试关键词
- Hypothetical Document Embeddings
- 用答案搜答案
- 语义鸿沟
- 向量表示对齐
================================================================================
第 4 章 Multi-Query(多查询检索)
4.1 通俗理解(12 岁能听懂)
你有一次提问的机会
想象你在玩一个寻宝游戏,面前有一个神秘的宝箱,里面装着你要找的答案。
游戏规则是:你只能对宝箱管理员说一句话,然后他帮你从仓库里找宝物。
第一次尝试
你问:
"怎么变强?"
管理员想了想,给你拿了一本《健身入门》。但你心里想的是:"我是想变编程高手啊!"
问题出在哪里?
你的问题太模糊了!"变强"可以有很多种意思:
- 💪 身体变强(健身)
- 🧠 大脑变强(学习)
- 💻 编程变强(写代码)
- 🎮 游戏变强(打游戏)
Multi-Query 就像一个"聪明的分身术" 🔄
Multi-Query 的做法:
你不是只说一句话,而是同时说好几句不同的话:
原始问题:"怎么变强?"
↓
┌─────────────────────────────┐
│ Multi-Query 分身术 │
└─────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ "如何通过健身让身体变强?" │
│ "如何提高编程能力?" │
│ "如何在游戏中变强?" │
└─────────────────────────────────────┘
↓
用这 3 个问题分别去搜索
↓
把找到的所有结果合并在一起
↓
去掉重复的,选出最好的
↓
给用户一个完整的答案!
一个比喻
| 方法 | 比喻 | 结果 |
|---|---|---|
| 单次查询 | 派 1 个人去找东西 | 可能找错 |
| Multi-Query | 派 3 个人从不同角度去找 | 更可能找到对的 |
为什么这样更好?
就像你问朋友问题:
- 问 1 个朋友,可能他只想到一个角度
- 问 3 个朋友,能得到 3 种不同的想法,最后综合起来更全面!
4.2 核心概念拆解
什么是 Multi-Query?
Multi-Query 是一种检索优化技术,它的核心思想是:
用多个不同角度的查询变体并行检索,然后合并结果
工作流程
- 生成变体:用 LLM 把原始查询改写成 3-5 个不同的版本
- 并行检索:每个变体同时去检索
- 结果融合:合并所有结果,去掉重复的,重新排序
- 返回答案:给用户一个更全面的结果
举个例子
用户问:"python list 怎么用?"
Multi-Query 生成的变体:
- "Python 列表的基本语法"
- "Python list 创建和访问方法"
- "Python 列表操作示例代码"
- "如何在 Python 中使用列表存储数据"
每个查询都能找到一些不同的文档,合并起来就更全面了!
4.3 与 Query Rewriting 的对比
| 维度 | Query Rewriting | Multi-Query |
|---|---|---|
| 目标 | 把问题说清楚 | 从多个角度问问题 |
| 生成数量 | 1 个改写后的问题 | 3-5 个变体问题 |
| 检索次数 | 1 次 | 多次(并行) |
| 比喻 | 翻译官 | 分身术 |
| 延迟 | 低 | 中(但并行可以加速) |
| 覆盖率 | 单一角度 | 多角度覆盖 |
形象比喻
- Query Rewriting:你说的不清楚,我帮你翻译成清楚的一句话
- Multi-Query:你可能想问多个角度,我帮你同时问好几个问题
4.4 面试回答指南(2 分钟版本)
1️⃣ 先给定义(20 秒)
"Multi-Query 是一种检索优化技术,核心思想是生成多个查询变体并行检索,然后合并结果。
简单说,就是用'分身术'从多个角度问同一个问题,找到更全面的答案。"
2️⃣ 说明为什么需要(30 秒)
"用户查询有两个问题:
① 歧义性
- 比如'怎么变强',可能是健身、编程、学习
- 单次查询只能命中一个角度
② 覆盖不全
- 即使用户问题清楚,单次检索也可能漏掉相关文档
- 不同表述的文档可能只被某些变体命中
Multi-Query 通过多个变体来解决这两个问题。"
3️⃣ 讲工作原理(40 秒)
"Multi-Query 分三步:
第一步:生成变体 用 LLM 根据用户查询生成 3-5 个不同角度的变体。
第二步:并行检索 每个变体同时去检索(可以并行执行,延迟不增加太多)。
第三步:结果融合 合并所有结果,去掉重复的,然后用 RRF(Reciprocal Rank Fusion)或其他方法重新排序。
关键是:不同变体可能命中不同但相关的文档,合并后覆盖率更高。"
4️⃣ 结合实际应用(20 秒)
"在 RAG 系统里,Multi-Query 通常和 Query Rewriting 一起用:
用户查询 → [Query Rewriting] → [Multi-Query 生成变体] → [并行检索] → [结果融合] → [生成]我在项目里试过,对于开放型问题和歧义查询,效果提升明显。"
4.5 优势与成本分析
核心优势
| 优势 | 说明 | 数据 |
|---|---|---|
| 召回率提升 | 不同变体命中不同但相关的文档 | Recall@10 +30%~80% |
| 歧义处理 | 同时覆盖多个可能的含义 | 歧义查询提升 81% |
| 多角度覆盖 | 每个变体找到不同角度的文档 | 答案更全面 |
| 鲁棒性强 | 某个变体不好,其他可以弥补 | 容错率高 |
成本分析:为什么是 6-8 倍?
详细成本拆解(基于典型云 API 价格估算)
| 组件 | 单次查询 | Multi-Query (3 变体) | Multi-Query (5 变体) | ||
|---|---|---|---|---|---|
| LLM 调用(生成变体) | 0 次 × $0.002 | 1 次 × 0.002 | 1 次 × 0.002 | ||
| 嵌入(Embedding) | 1 次 × $0.0001 | 3 次 × 0.0003 | 5 次 × 0.0005 | ||
| 向量检索 | 1 次 × $0.0005 | 3 次 × 0.0015 | 5 次 × 0.0025 | ||
| 总计 | $0.0006 | $0.0038 | $0.0050 | ||
| 倍数 | 1x | 6.3x | 8.3x |
倍数计算过程:
单次查询总成本:$0.0001 + $0.0005 = $0.0006
Multi-Query (3 变体) 总成本:$0.002 + $0.0003 + $0.0015 = $0.0038
倍数 = $0.0038 ÷ $0.0006 = 6.33 倍
Multi-Query (5 变体) 总成本:$0.002 + $0.0005 + $0.0025 = $0.0050
倍数 = $0.0050 ÷ $0.0006 = 8.33 倍
成本构成分析
┌─────────────────────────────────────────────────────────────┐
│ Multi-Query 成本构成(3 变体) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 单次查询:$0.0006 │
│ ├── 嵌入:$0.0001 (16.7%) │
│ └── 检索:$0.0005 (83.3%) │
│ │
│ Multi-Query:$0.0038 │
│ ├── LLM 生成变体:$0.002 (52.6%) ← 新增 │
│ ├── 嵌入:$0.0003 (7.9%) ← 3 倍 │
│ └── 检索:$0.0015 (39.5%) ← 3 倍 │
│ │
│ 倍数 = $0.0038 / $0.0006 = 6.33 倍 │
│ │
└─────────────────────────────────────────────────────────────┘
关键点说明
-
LLM 调用是主要成本增量
- LLM 生成变体:$0.002,占总成本 52.6%
- 这是纯新增的成本,单次查询没有这一步
-
嵌入和检索成本按变体数量线性增长
变体数 嵌入成本 检索成本 总成本 倍数 1 次(单次) $0.0001 $0.0005 $0.0006 1x 3 次 $0.0003 $0.0015 $0.0038 6.3x 5 次 $0.0005 $0.0025 $0.0050 8.3x -
实际倍数取决于变体数量
- 3 个变体 → 约 6 倍
- 4 个变体 → 约 7 倍
- 5 个变体 → 约 8 倍
⚠️ 注意:以上价格是基于典型云 API 的示例估算,实际成本取决于:
- 使用的 LLM 模型(GPT-4 比 GPT-3.5 贵)
- 嵌入模型(商业 API vs 本地部署)
- 向量数据库(云服务 vs 自建)
- 查询长度(tokens 数量)
如果是本地部署模型,边际成本接近零,但前期投入大,成本倍数仍然适用(6-8 倍的资源消耗)。
4.6 优化策略:如何降低成本
策略 1:条件触发
def should_use_multi_query(query):
"""只对特定查询使用 Multi-Query"""
# 查询太短(< 5 词)→ 用 Multi-Query
if len(query.split()) < 5:
return True
# 查询有歧义(包含泛化词)→ 用 Multi-Query
ambiguous_words = ["怎么", "如何", "什么", "为什么"]
if any(word in query for word in ambiguous_words):
return True
# 事实性查询 → 不用 Multi-Query
if query.endswith("吗") or "?" in query:
return False
# 默认不用
return False
策略 2:动态调整变体数量
| 查询类型 | 变体数量 | 延迟 | 成本 |
|---|---|---|---|
| 简短模糊 | 5 个 | 高 | 高 |
| 一般查询 | 3 个 | 中 | 中 |
| 明确查询 | 2 个 | 低 | 低 |
策略 3:并行化优化
# 串行(慢)❌
results1 = retriever.search(query1)
results2 = retriever.search(query2)
results3 = retriever.search(query3)
# 并行(快)✅
import asyncio
results1, results2, results3 = await asyncio.gather(
retriever.search(query1),
retriever.search(query2),
retriever.search(query3)
)
策略 4:缓存变体生成
# 常见查询的变体可以缓存
cache = {
"python 教程": ["Python 入门教程", "Python 基础语法", "Python 学习路径"],
"怎么减肥": ["如何科学减肥", "减肥饮食指南", "减肥运动方法"],
}
def get_variants(query):
if query in cache:
return cache[query] # 直接返回,省去 LLM 调用
else:
variants = llm.generate_variants(query)
cache[query] = variants
return variants
4.7 一张图总结
┌─────────────────────────────────────────────────────────┐
│ Multi-Query 工作流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ 用户问:"怎么变强?" │
│ ↓ │
│ ┌──────────────────────────┐ │
│ │ LLM 生成 3-5 个变体问题 │ │
│ └──────────────────────────┘ │
│ ↓ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ 健身变强 │ │ 编程变强 │ │ 学习变强 │ │
│ │ [搜索] │ │ [搜索] │ │ [搜索] │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ ↓ ↓ ↓ │
│ ┌───────────────────────────────────────────┐ │
│ │ 合并结果 + 去重 + 排序 │ │
│ └───────────────────────────────────────────┘ │
│ ↓ │
│ 最终答案(更全面、更准确) │
│ │
└─────────────────────────────────────────────────────────┘
4.8 核心要点总结
Multi-Query 关键点
- 核心思想:多角度问问题,找到更全面的答案
- 四步流程:生成变体 → 并行检索 → 结果融合 → 返回答案
- 成本:6-8 倍基准成本
优势
- 召回率提升 30%~80%
- 歧义处理能力强
- 答案更全面
- 鲁棒性强
优化策略
- 条件触发(不是所有查询都用)
- 动态调整变体数量
- 并行化检索
- 缓存常见查询变体
面试关键词
- 分身术比喻
- 多角度覆盖
- RRF 结果融合
- 成本 6-8 倍