What is Multi-Query Retrieval
Multi-Query Retrieval is a technique where you take one user question, ask an LLM to generate 3-5 different rephrasings of that question, then run all of them (including the original) in parallel against your vector database, and finally merge all the results.
CN: Multi-Query Retrieval(多查询检索)是一种技术:你把用户的一个问题,交给LLM生成3-5个不同的改写版本,然后把所有这些版本(包括原始问题)并行地对向量数据库做检索,最后把所有结果合并起来。
Imagine you’re a detective trying to find a file in a massive archive. Instead of asking the archivist just one question (“Show me files about ‘the big project'”), you ask 5 different versions:
- “Show me files about ‘the big project'”
- “Give me documents related to ‘Project Alpha'”
- “Find me records about ‘the Q4 initiative'”
- “Show me anything about ‘the CEO’s pet project'”
- “Find me files mentioning ‘the 2024 rollout'”
Each phrasing might find different documents because the archivist’s index uses different keywords. By combining all results, you’re much more likely to find everything relevant.
CN — 人话比喻:
想象你是一个侦探,要在巨大的档案库里找一份文件。你不是只问档案管理员一个问题(”给我看看关于’大项目’的文件”),而是问5个不同版本:
- “给我看看关于’大项目’的文件”
- “给我’Project Alpha’相关的文档”
- “找一下’Q4 计划’的记录”
- “给我看任何关于’CEO的宠儿项目’的资料”
- “找提到’2024 年发布’的文件”
因为档案管理员的索引用的是不同的关键词,每个问法都可能找到不同的文件。把所有结果合并起来,你就更可能找到所有相关的东西。
The Three-Stage Process
Multi-Query Retrieval follows three distinct stages,
Stage 1: Query Expansion(查询扩展)
EN: An LLM takes the original user query and generates 3 to 5 semantically diverse reformulations. Each variant captures a different angle, synonym set, or level of specificity.
CN: LLM 接收用户的原始查询,生成3到5个语义多样的改写版本。每个变体捕捉不同的角度、同义词集合或粒度级别。
Example, Original asking “What causes high latency in microservices?”
- Variant 1: “How to debug slow response times in distributed systems”
- Variant 2: “Network bottlenecks in service-to-service communication”
- Variant 3: “Performance optimization for microservice architectures”
Stage 2: Parallel Retrieval
Each variant query is embedded independently and used to search the vector store, producing separate ranked result sets. The original query is typically included as one of the search queries as well.
CN: 每个变体查询被独立地向量化,用来搜索向量数据库,产生各自独立的排序结果集。原始查询通常也被包含在检索查询中。
Stage 3: Result Fusion
(结果融合)
The system merges these result sets, removes duplicates, and produces a unified ranked list. The most common fusion method is Reciprocal Rank Fusion (RRF).
CN: 系统合并这些结果集,去除重复,产生一个统一的排序列表。最常用的融合方法是 Reciprocal Rank Fusion (RRF)。
Reciprocal Rank Fusion (RRF)
融合算法
RRF scores each document with the formula:
RRF(d) = Σᵢ 1 / (k + rankᵢ(d))
rankᵢ(d) is the rank of document d in the result set from query i (1-indexed)rankᵢ(d) 是文档 d 在第 i 个查询结果中的排名(从1开始)
k is a constant (typically 60) that dampens the influence of high ranks
K 是一个常数(通常为60),用于削弱高排名的影响
example
Let’s say we have 2 user questions (variants) that we searched against our vector database. We’ll track Document A and Document B across these two search result lists.
CN: 假设我们有2个用户问题(变体)对向量数据库进行了检索。我们追踪 文档A 和 文档B 在这两组搜索结果中的表现。
- Original Question (原始问题): “How to handle errors in Python?”
- Variant 1 (变体1): “What are the best practices for exception han
dling in Python?" - Variant 2 (变体2): “How do I debug and fix Python runtime errors?”
We have a vector database with 5 documents (text chunks) inside.
CN: 我们的向量数据库里有5个文档(文本块)。
| Real Document ID (真实文档ID) | Content Snippet (内容片段) |
|---|---|
| doc_001 | “Python uses try-except blocks to catch exceptions…” |
| doc_002 | “Best practices for exception handling include logging and specific exception types…” |
| doc_003 | “Debugging tools like pdb and logging help trace runtime errors…” |
| doc_004 | “Data processing pipelines often fail due to missing values…” |
| doc_005 | “Unit tests with pytest can catch errors before runtime…” |
Step 1: 每个查询被向量化 (Each Query Gets Embedded)
# 伪代码表示 / Pseudo-code representation
embedding_model = OpenAIEmbeddings()
# 生成3个向量 / Generate 3 vectors
vec_original = embedding_model.embed("How to handle errors in Python?")
vec_variant1 = embedding_model.embed("What are the best practices for exception handling in Python?")
vec_variant2 = embedding_model.embed("How do I debug and fix Python runtime errors?")
# 每个vec都是 [0.123, -0.456, 0.789, ...] 这样的浮点数列表 (1536个)
# Each vec is a list of floats like [0.123, -0.456, 0.789, ...] (1536 of them)
Step 2: 每个向量独立检索 (Each Vector Searches Independently)
Each vector is sent to the vector database (e.g., Chroma, Pinecone, Milvus). The database computes cosine similarity between the query vector and ALL document vectors in the store, then returns the top K (e.g., top 3) most similar documents.
CN: 每个向量被发送到向量数据库(如 Chroma、Pinecone、Milvus)。数据库计算查询向量和库中所有文档向量之间的余弦相似度,然后返回最相似的 Top K(比如 Top 3)个文档。
Query 1 (Original) Results:
CN — 查询1 (原始) 返回结果:
| Rank (排名) | Document ID | Similarity Score (相似度) | Content (内容) |
|---|---|---|---|
| 1 | doc_001 | 0.92 | “Python uses try-except blocks to catch exceptions…” |
| 2 | doc_002 | 0.85 | “Best practices for exception handling include…” |
| 3 | doc_005 | 0.72 | “Unit tests with pytest can catch errors…” |
Query 2 (Variant 1) Results:
CN — 查询2 (变体1) 返回结果:
| Rank (排名) | Document ID | Similarity Score (相似度) | Content (内容) |
|---|---|---|---|
| 1 | doc_002 | 0.95 | “Best practices for exception handling include…” |
| 2 | doc_001 | 0.88 | “Python uses try-except blocks to catch exceptions…” |
| 3 | doc_003 | 0.70 | “Debugging tools like pdb and logging…” |
Here,
doc_002is now “Document B” (but it’s the same physical chunk as before).doc_001is “Document A”. A new one,doc_003, appears as “Document C”.
CN: 这里,
doc_002现在成了”文档B”(但它是和之前一样的物理块)。doc_001是”文档A”。一个新的doc_003出现了,作为”文档C”。
Query 3 (Variant 2) Results:
CN — 查询3 (变体2) 返回结果:
| Rank (排名) | Document ID | Similarity Score (相似度) | Content (内容) |
|---|---|---|---|
| 1 | doc_003 | 0.91 | “Debugging tools like pdb and logging…” |
| 2 | doc_001 | 0.80 | “Python uses try-except blocks to catch exceptions…” |
| 3 | doc_004 | 0.65 | “Data processing pipelines often fail…” |
Step 3: RRF 融合 — 将 “A/B/C” 映射回真实ID (RRF Fusion — Mapping A/B/C Back to Real IDs)
Now, let’s build the RRF table using real doc_001, doc_002, etc.
CN: 现在,我们用真实的 doc_001、doc_002 等来构建 RRF 表格。
| 真实文档ID (Real ID) | Q1 (Original) Rank | Q2 (Variant 1) Rank | Q3 (Variant 2) Rank | RRF 计算 (Calculation) | 最终分数 (Final Score) |
|---|---|---|---|---|---|
| doc_001 | 1 | 2 | 2 | 1/61 + 1/62 + 1/62 = 0.016393 + 0.016129 + 0.016129 = 0.048651 | |
| doc_002 | 2 | 1 | — (未出现) | 1/62 + 1/61 + 0 = 0.016129 + 0.016393 = 0.032522 | |
| doc_003 | — (未出现) | 3 | 1 | 0 + 1/63 + 1/61 = 0.015873 + 0.016393 = 0.032266 | |
| doc_005 | 3 | — | — | 1/63 + 0 + 0 = 0.015873 | |
| doc_004 | — | — | 3 | 0 + 0 + 1/63 = 0.015873 |
Final ranking after RRF: doc_001 (1st) > doc_002 (2nd) > doc_003 (3rd).
CN: RRF 后的最终排名:doc_001 (第1) > doc_002 (第2) > doc_003 (第3)。
Key Takeaways
| 要点 (Topic) | EN | CN |
|---|---|---|
| 核心思想 | Generate multiple query reformulations from one user question | 从一个用户问题生成多个查询改写版本 |
| 三步流程 | Query Expansion → Parallel Retrieval → Result Fusion | 查询扩展 → 并行检索 → 结果融合 |
| LLM的作用 | LLM generates diverse query variants covering different angles | LLM生成覆盖不同角度的多样化查询变体 |
| 并行检索 | Each variant is embedded and searched independently | 每个变体被独立向量化并搜索 |
| 结果融合 | RRF (Reciprocal Rank Fusion) merges ranked results without score normalization | RRF(倒数排名融合)无需分数归一化即可合并排序结果 |
| RRF公式 | RRF(d) = Σᵢ 1/(k + rankᵢ(d)), k=60 typically | RRF(d) = Σᵢ 1/(k + rankᵢ(d)),k通常为60 |
| 主要收益 | Overcomes single-point-of-failure in retrieval; improves recall | 克服检索中的单点故障;提高召回率 |
| 适用场景 | Complex questions, vocabulary mismatch, discovery tasks | 复杂问题、词汇不匹配、探索性任务 |
| LangChain实现 | MultiQueryRetriever.from_llm(retriever, llm) | MultiQueryRetriever.from_llm(retriever, llm) |
| include_original | Whether to include original query in the retrieval set | 是否在检索集中包含原始查询 |
| 去重 | Unique union of all retrieved documents | 所有检索文档的唯一并集 |
| 与HyDE的区别 | Multi-Query generates reformulations; HyDE generates a hypothetical answer document | Multi-Query生成改写;HyDE生成假设答案文档 |

