RAG查询改写

RAG查询改写
Chase WooRAG 的效果不只取决于 Embedding、分块和向量数据库。很多时候,真正拖垮召回率的是用户输入本身:它可能口语化、缺少上下文、包含多个意图,甚至只是一句“刚刚说的那个呢?”。
**查询改写(Query Rewriting / Query Transformation)**位于用户问题与检索器之间,目标不是把句子写得更漂亮,而是把问题转换成更适合检索的表达,同时保留原始意图与约束。
一、为什么原始 Query 往往不适合检索
1. 用户语言与知识库语言存在语义鸿沟
用户倾向于使用口语、缩写或业务黑话,知识库则使用规范术语。例如用户问“怎么让模型记住前文”,文档中可能写的是“对话状态管理”“长上下文”或“持久化记忆”。即使语义接近,短 Query 的向量也可能无法稳定命中目标文档。
2. Query 缺少必要背景
“它支持本地部署吗?”对人类来说可以结合上文理解,但检索器只看到这一句时,并不知道“它”指的是哪个模型。多轮对话中的指代、省略和话题切换,都会使检索输入失真。
3. 一个问题包含多个检索目标
“比较 Milvus 和 Elasticsearch 的混合检索能力,并给出低成本部署建议”至少包含三个任务:
- Milvus 的混合检索能力;
- Elasticsearch 的混合检索能力;
- 两者在成本和部署复杂度上的比较。
用整句做一次向量检索,结果往往只覆盖其中一个方面。
4. 用户问题过窄或表达方式与答案不同
查询通常是疑问句,而文档通常是陈述句。比如用户问“为什么 temperature=0 仍然不稳定?”,相关文档可能描述“浮点误差、并行规约顺序和相同概率下的 token 选择”。Query 与答案在长度、结构和词汇上都不一致。
二、查询改写在 RAG 中的位置
一个更完整的检索链路可以表示为:
1 | 用户问题 + 对话历史 |
这里需要区分三个概念:
- Query Rewriting:重写措辞与结构,得到一个更明确的查询;
- Query Expansion:保留原查询,同时增加同义词、别名或多个查询变体;
- Query Decomposition:把复杂问题拆成多个可独立检索的子问题。
它们可以组合使用,但不应对所有请求无差别地全部开启。
三、六类常用策略
1. 规范化表达
基础改写负责纠错、补全术语、去除无意义口头语,并保留时间、版本、对象和否定条件等关键约束。
1 | 原始问题:最新版那个模型在 Mac 上能跑吗? |
适合短文本、错别字较多、术语不规范,但意图相对单一的场景。
2. 多查询扩展
让 LLM 生成 3~5 个语义不同但意图一致的 Query,分别检索,再合并结果。变体可以覆盖:
- 同义词与别名;
- 专业术语与口语表达;
- 原因、机制、限制等不同视角;
- 中文名、英文名和缩写。
1 | 原问题:vLLM 为什么快? |
多查询会提升召回率,但也会带来重复结果和噪声。工程上通常使用 Reciprocal Rank Fusion(RRF) 合并不同结果列表:
$$
score(d)=\sum_{r \in R}\frac{1}{k+rank_r(d)}
$$
RRF 只依赖文档在各路结果中的排名,不要求不同检索器的分数处于同一量纲,适合融合 BM25 与向量检索。
3. HyDE:用“假设文档”靠近答案空间
HyDE(Hypothetical Document Embeddings)的做法不是直接编码问题,而是先让 LLM 生成一段可能的答案或相关文档,再对这段假设文档进行 Embedding,并用它检索真实文档。
1 | Query → LLM 生成假设文档 → Embedding → 向量检索 → 真实文档 |
它解决的是问题表达和答案表达不在同一个语义空间的问题。需要注意:假设文档可能包含事实错误,但它只用于寻找语义邻域,不能作为最终答案的事实依据。
HyDE 更适合:
- Query 很短,语义信息不足;
- 知识库文本偏长、偏专业;
- 零样本场景,缺少相关性标注数据。
它不适合精确实体、编号、错误码和日期查询,这类请求通常应优先使用关键词检索或元数据过滤。
4. Step-back:先退一步检索上位概念
Step-back Prompting 会先把具体问题抽象为更高层的问题,再同时检索原问题与上位概念。
1 | 原问题:为什么把 vLLM 的 tensor_parallel_size 从 1 调到 2 后输出出现差异? |
原问题负责找具体答案,Step-back Query 负责补充原理、规则和背景。它适合知识密集型、原理解释和多跳推理,不等于把复杂问题拆成多个子问题。
5. 子查询分解
当问题含有比较、并列、多跳关系或多个约束时,可以生成若干相互独立的子查询,并行检索后再聚合。
1 | 原问题:比较 LangGraph 与传统 Workflow 在状态管理和故障恢复上的差异。 |
拆分时要避免两个极端:子问题过少会遗漏信息,过多则会导致延迟、成本和上下文膨胀。一般先限制在 2~5 个,并要求每个子问题可独立检索。
6. 多轮对话改写
多轮 RAG 不应直接把完整聊天历史拼到 Query 中,否则无关信息会污染向量。更稳妥的做法是结合最近若干轮对话,把当前问题改写成一条脱离历史也能理解的独立问题。
1 | 历史:用户正在比较 Qwen2.5-7B 与 Qwen2.5-14B 的显存占用。 |
改写器必须继承历史中的实体与约束,但不能擅自补充用户没有表达的条件。对话很长时,可只提供近期窗口、当前话题摘要和已确认实体,而不是全部原始消息。
四、不要让改写器自由发挥
一个可用于生产环境的基础 Prompt 可以这样设计:
1 | 你是 RAG 检索查询改写器。请根据对话历史,把当前问题改写为可独立理解、适合知识库检索的查询。 |
在支持结构化输出的模型中,应直接约束 JSON Schema,而不是只靠“请输出 JSON”。filters 可进一步承载时间范围、产品版本、文档类型和租户权限等元数据条件。
五、生产级架构:先路由,再改写
最常见的错误,是任何 Query 都调用最重的改写链路。更合理的方案是先做轻量分类:
| Query 类型 | 推荐策略 |
|---|---|
| 明确的单一事实问题 | 原 Query + 混合检索 |
| 口语化、术语不规范 | 基础改写或多查询扩展 |
| 依赖对话历史 | 独立问题改写 |
| 复杂比较、多目标问题 | 子查询分解 |
| 原理解释、多跳推理 | 原 Query + Step-back |
| 短 Query 与长文档语义不匹配 | HyDE |
| 编号、专有名词、错误码 | 关键词检索 + 精确过滤 |
注意,最终重排序应优先使用原始问题计算相关性,防止改写后的 Query 把检索结果带偏。
六、三类核心风险
1. 查询漂移
LLM 可能把用户的范围改宽、改窄,或把不确定的指代直接猜成某个实体。
可采用以下约束:
- 原 Query 与改写 Query 同时检索,而不是完全替换;
- 计算两者的 Embedding 相似度,低于阈值时回退;
- 对实体、数字、时间、版本号和否定词做前后校验;
- 低置信度或存在多个候选实体时,向用户澄清;
- 用原始问题对召回结果做 Cross-Encoder 重排序。
2. 延迟与成本
多查询、HyDE、重排序都会增加模型调用和检索次数。优化方式包括:
- 使用小模型完成分类与基础改写;
- 子查询并行检索;
- 对规范化后的 Query 做缓存;
- 限制生成数量、长度和超时时间;
- 只有在首轮召回质量较低时,才触发二次改写;
- 为简单 Query 提供零改写快速路径。
3. 召回增加,但噪声也增加
更多 Query 不等于更好。多路结果需要去重、融合和重排序,还要根据 token 预算控制最终上下文。如果只是盲目扩大 Top K,生成模型反而更容易被无关片段干扰。
七、如何评估查询改写是否有效
不能只观察最终回答看起来更好了。建议分层评估:
检索层
- Recall@K:相关文档是否进入前 K 条;
- MRR:第一个相关文档出现得有多靠前;
- nDCG@K:多个相关文档的排序质量;
- Hit Rate:是否至少命中一条相关文档;
- Query Drift Rate:改写后丢失或改变关键约束的比例。
生成层
- 答案正确性;
- 对检索证据的忠实度;
- 引用是否覆盖关键结论;
- 完整性与拒答准确率。
系统层
- P50 / P95 延迟;
- 单次请求 token 与费用;
- 平均检索次数;
- 缓存命中率;
- 触发澄清和回退的比例。
评测集应覆盖单轮、多轮、错别字、别名、否定、版本号、时间范围、复合问题和无答案问题。上线时使用 A/B 测试,比较“无改写”、“统一改写”和“路由式改写”,而不是只测试某一种 Prompt。
八、工程实践建议
- 先打好基础,再做高级改写。 如果分块、Embedding、权限过滤和混合检索本身有问题,Query 改写只能掩盖问题。
- 保留原始问题。 原 Query 用于回退、重排序、生成和审计,改写 Query 只服务于检索。
- 优先混合检索。 向量检索处理语义,BM25 处理实体、代码、编号和术语,两者互补。
- 结构化输出。 把查询文本、关键词、过滤条件和置信度分开,避免从自然语言中二次解析。
- 按场景路由。 基础改写、多查询、HyDE、Step-back 和分解解决的是不同问题。
- 建立可观测性。 记录原 Query、改写结果、路由类型、召回文档、融合分数、重排序结果及最终引用。
- 设置回退机制。 模型超时、结构化输出失败或相似度异常时,直接使用原 Query 检索。
九、总结
查询改写的本质,是在不改变用户意图的前提下,把人类表达转换成检索器更容易理解的表达。它不是单一 Prompt,而是一套包含意图识别、上下文补全、查询扩展、任务分解、结果融合、重排序和评估的系统工程。
对于多数生产级 RAG,可以从以下路径逐步演进:
1 | 原 Query |
与其为每个请求都生成更多 Query,不如让系统先判断这个问题究竟缺了什么,再选择成本最低、最有针对性的改写策略。








