1. 检索增强生成中的查询重写技术概述
在构建检索增强生成(RAG)系统时,我们经常会遇到一个关键问题:用户的原始查询往往存在表述不准确或语义缺失的情况。想象一下这样的场景——当用户输入"2020年NBA冠军是洛杉矶湖人队!告诉我什么是LangChain框架?"这样的查询时,传统的检索系统很可能会被前半句无关内容干扰,导致返回错误的文档或根本无法给出有效响应。
查询重写技术正是为了解决这类问题而诞生的。它的核心思想是通过对原始查询进行语义重构,使修改后的查询能够更好地与文档库中的内容对齐。这就好比一位专业的图书管理员,当听到读者含糊不清的询问时,能够准确理解其真实需求并转化为图书馆分类系统能够处理的规范查询语句。
从技术架构来看,查询重写在RAG流程中属于预检索(pre-retrieval)环节。如图1所示,它位于用户原始查询和文档检索之间,起到关键的桥梁作用。通过这个环节的优化,我们可以显著提升后续检索结果的质量,进而改善最终生成的回答准确性。

目前主流的查询重写方法可以分为以下几类:
- 假设文档生成类(如HyDE):通过LLM生成假设性文档来扩展查询语义
- 查询重构类(如Rewrite-Retrieve-Read):直接对查询语句进行改写优化
- 抽象推理类(如Step-Back Prompting):将具体问题提升到更抽象的层面进行处理
- 迭代优化类(如ITER-RETGEN):通过多次检索-生成循环逐步改进查询质量
在实际应用中,这些方法各有优劣。HyDE适合处理信息稀疏的查询,但可能生成不准确的假设文档;Rewrite-Retrieve-Read实现简单但对复杂查询效果有限;Step-Back Prompting需要精心设计提示模板;ITER-RETGEN效果最好但计算成本最高。理解这些技术的原理和适用场景,对于构建高效的RAG系统至关重要。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. HyDE:假设文档嵌入技术详解
2.1 HyDE核心原理
Hypothetical Document Embeddings (HyDE)是一种颇具创意的查询重写方法,其核心思想可以概括为"以虚引实"。当面对一个用户查询时,HyDE不是直接使用这个查询进行检索,而是先让LLM生成若干个可能回答该问题的假设文档,然后基于这些假设文档的嵌入向量来进行实际检索。
这种方法背后的直觉是:即使生成的假设文档内容不完全准确,它们在语义空间中的位置也会比原始查询更接近真实的正确答案。就像在黑暗中寻找目的地时,先根据描述想象出可能的场景特征,再根据这些特征去匹配实际地点,往往比直接使用模糊的原始描述更容易找到正确位置。
HyDE的工作流程可以分为四个关键步骤:
- 假设文档生成:使用LLM基于查询生成k个可能的回答文档
- 嵌入向量转换:将这些假设文档通过编码器转换为密集向量
- 向量平均计算:对得到的k个向量进行加权平均,得到最终查询向量
- 向量检索:使用最终查询向量在文档库中进行相似度检索
数学上,最终查询向量v的计算公式为:
code复制v = (1-α) * f(q) + α * (1/k) * Σf(d_k)
其中α是平衡参数,f表示编码函数,q是原始查询,d_k是第k个假设文档。
2.2 HyDE实现与案例分析
让我们通过一个具体例子来理解HyDE的实际效果。假设我们的查询是:"what did Paul Graham do after going to RISD?"(Paul Graham在RISD之后做了什么?)
使用LlamaIndex实现HyDE的代码如下:
python复制from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.indices.query.query_transform import HyDEQueryTransform
from llama_index.core.query_engine import TransformQueryEngine
# 加载文档和创建索引
documents = SimpleDirectoryReader("YOUR_DIR_PATH").load_data()
index = VectorStoreIndex.from_documents(documents)
# 原始查询
query_str = "what did paul graham do after going to RISD"
# 普通查询引擎
query_engine = index.as_query_engine()
response = query_engine.query(query_str)
print("Base query result:", response)
# HyDE查询引擎
hyde = HyDEQueryTransform(include_original=True)
hyde_query_engine = TransformQueryEngine(query_engine,
