| 25 | What are the different query transformation techniques that enhance user queries in RAG
P1 · rag
🏷 标签:rag, query-transformation, hyde
1️⃣ 考察意图
面试官想考察你对 RAG 系统中“用户意图与检索空间错配”这一核心问题的理解深度。这不是背概念题,而是工程取舍 + 系统设计题。刁钻点在于:候选人往往只罗列“查询扩展、分解、重写”等名词,却说不清每种技术解决了什么具体问题、在什么场景下失效。答好了能展示你对 RAG 整条链路(query -> retrieval -> generation)的完整流程优化思维,以及从“检索召回率”到“最终答案质量”的因果链把握。
2️⃣ 标准答
RAG 中用户查询往往短、模糊、口语化,与文档库的语义空间存在 gap。查询变换(Query Transformation)就是通过一系列预处理,缩小这个 gap。主流技术分四类,按复杂度递增排列:
1. 查询扩展(Query Expansion)
- 原理:用同义词、相关术语或 LLM 生成的语义变体扩充原始查询。例如用户问“苹果股价”,扩展为“Apple Inc. stock price AAPL market cap”。
- 方法:WordNet 做同义词替换(轻量但泛化差);BM25 配合伪相关反馈(PRF),从初检 top-k 文档中提取高频词;LLM 直接生成扩展词(如“请为以下查询生成 5 个相关搜索词”)。
- 工程取舍:扩展词越多,召回率提升但精确度下降。实践中控制扩展词数量在 3-5 个,并用 TF-IDF 过滤掉停用词和低频噪声。
- 坑:扩展词可能引入歧义。例如“苹果”扩展出“水果”和“公司”,导致检索结果混杂。解法:用上下文 embedding 做语义消歧,只保留与原始查询 embedding 余弦相似度 > 0.7 的扩展词。
2. 查询分解(Query Decomposition)
- 原理:将多跳复杂问题拆成多个单跳子查询,分别检索后合并结果。例如“2023 年诺贝尔物理学奖得主毕业于哪所大学?”拆为“2023 年诺贝尔物理学奖得主是谁?”和“该得主的毕业院校”。
- 方法:LLM 用 few-shot prompt 输出子查询列表;或使用结构化分解(如“Step-back prompting”先问“诺贝尔物理学奖 2023”再问“毕业院校”)。
- 工程取舍:子查询越多,检索成本线性增长,且合并结果时可能引入冲突(如两个子查询返回不同实体)。实践中限制子查询 ≤ 3 个,并用 LLM 做一次“答案融合”步骤。
- 坑:子查询之间可能有依赖关系(第二个子查询依赖第一个的结果)。解法:用链式分解(Chain-of-Thought),让 LLM 先生成中间答案,再基于它生成下一个查询。
3. 查询重写(Query Rewriting)
- 原理:用 LLM 将用户口语化、缺上下文的查询改写为更清晰、更符合文档库表述的形式。例如用户问“它后来怎么样了?”,改写为“[前文实体] 在 [时间] 后的发展情况”。
- 方法:多轮对话中拼接历史上下文;单轮查询用 LLM 做“改写 + 补全”(如“将以下查询改写为完整句子,补充缺失的主语和宾语”)。
- 工程取舍:改写可能改变用户原始意图。实践中保留原始查询作为 fallback,只有当改写查询的检索置信度(如 BM25 最高分)低于阈值时才回退。
- 坑:LLM 改写可能过度“美化”,引入不存在的细节。解法:在 prompt 中加约束“只补充上下文中的已知信息,不编造事实”。
4. 假设文档嵌入(HyDE)
- 原理:先生成一个假设答案(Hypothetical Answer),再用该答案的 embedding 去检索,而非直接用查询 embedding。因为答案与文档的语义空间更接近。
- 方法:用 LLM 生成“假设答案”(如“请根据你的知识回答以下问题”),然后用 Sentence-BERT 或 OpenAI embedding 模型编码该答案,再做向量检索。
- 工程取舍:假设答案的质量直接决定检索效果。如果 LLM 生成的内容偏离事实,检索会引入噪声。实践中只取假设答案的前 50 个 token 做 embedding,避免长尾幻觉。
- 坑:HyDE 在知识密集型任务(如医学、法律)上效果显著,但在开放域闲聊任务上反而降低召回率。因为假设答案可能过于具体,丢失查询的泛化性。解法:对任务类型做分类,仅在需要精确事实时启用 HyDE。
总结:查询扩展适合短查询(< 5 词),查询分解适合多跳问题,查询重写适合多轮对话,HyDE 适合事实密集型场景。实际系统中通常组合使用:先用重写处理上下文,再用分解处理复杂度,最后用 HyDE 提升检索精度。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从四个层面回答:查询扩展、分解、重写和 HyDE。查询扩展通过同义词或 LLM 生成变体提升召回率,但要注意控制噪声;查询分解把多跳问题拆成子查询,但需处理依赖和合并冲突;查询重写补全上下文,但必须保留原始查询作为 fallback;HyDE 先生成假设答案再检索,在事实密集型场景效果显著,但开放域会降低召回率。总结一句:没有银弹,需要根据查询类型和场景组合使用。”
4️⃣ 高频追问 & 应对
追问 1:HyDE 和 Query Rewriting 有什么区别?什么时候该用哪个?
核心区别:HyDE 生成的是“答案”,Query Rewriting 生成的是“更好的查询”。HyDE 适合用户查询已经明确但文档库表述不一致的场景(如“新冠疫苗副作用” vs 文档写“COVID-19 vaccination adverse effects”);Query Rewriting 适合查询本身模糊或缺失上下文的场景(如多轮对话中的“它”)。实践中,如果用户查询长度 < 10 词且包含实体,优先用 HyDE;如果查询包含代词或口语化表达,优先用重写。
追问 2:查询分解时,子查询的顺序如何确定?如果子查询之间冲突怎么办?
顺序由依赖关系决定:先执行不依赖其他子查询的“根查询”,再执行依赖其结果的“子查询”。例如“2023 年诺贝尔物理学奖得主毕业于哪所大学?”先查“2023 年诺贝尔物理学奖得主”,得到实体“Pierre Agostini”后,再查“Pierre Agostini 毕业院校”。冲突处理:如果两个子查询返回不同实体(如“得主”和“毕业院校”不一致),用 LLM 做一次“答案验证”,选择与原始查询语义最一致的实体。实践中,冲突率通常 < 5%,可以忽略。
追问 3:查询扩展中,如何避免引入噪声?有没有具体的评估指标?
噪声控制方法:1)用 embedding 相似度过滤扩展词,只保留与原始查询余弦相似度 > 0.7 的词;2)限制扩展词数量 ≤ 5 个;3)用 TF-IDF 过滤掉在文档库中 IDF < 1.0 的罕见词。评估指标:用“扩展后检索的 NDCG@10”对比“原始查询的 NDCG@10”,如果提升 < 3% 则说明扩展无效。实践中,扩展在短查询(< 5 词)上平均提升 10-15% 召回率,在长查询(> 15 词)上反而可能下降 5%。
5️⃣ 避坑 · 常见错误答法
- ❌ “查询变换就是让 LLM 把用户问题改得更清楚。” → ✅ “查询变换包括扩展、分解、重写、HyDE 四种,每种解决不同问题:扩展解决短查询稀疏性,分解解决多跳复杂度,重写解决上下文缺失,HyDE 解决语义空间错配。”
- ❌ “HyDE 在所有场景下都有效。” → ✅ “HyDE 在事实密集型任务(如医学、法律)上效果显著,但在开放域闲聊或查询本身已很精确时反而降低召回率,因为假设答案可能引入幻觉或丢失泛化性。”
- ❌ “查询分解就是把问题拆成几个小问题,然后分别检索。” → ✅ “查询分解需要处理子查询之间的依赖关系(链式分解)和结果合并时的冲突(LLM 验证),否则可能得到矛盾答案。”
6️⃣ 简历呼应
- 如果你有 RAG 项目:从“我在项目中实现了 HyDE + Query Rewriting 组合,在 MultiHopQA 上召回率提升 12%”切入,强调你对比了不同变换技术的效果,并处理了噪声和冲突问题。
- 如果你只做过传统 NLP:用“查询变换类似于传统信息检索中的查询扩展(如 PRF),但 LLM 让扩展更语义化”类比迁移,展示你对新旧技术的理解。
- 如果你是校招无项目:聚焦“我复现了 HyDE 论文(Gao et al., 2022),在 Natural Questions 数据集上验证了假设答案长度对检索效果的影响”,展示你的论文阅读和实验能力。
- “Precise Zero-Shot Dense Retrieval without Relevance Labels” (HyDE 论文, Gao et al., 2022)
- “Query Expansion by Prompting Large Language Models” (LLM-based query expansion, 2023)
- “Step-Back Prompting Enables Reasoning via Abstraction in Large Language Models” (查询分解技术)
- “ReAct: Synergizing Reasoning and Acting in Language Models” (多轮查询调整)
- LangChain 官方文档:Query Transformation 模块(含 MultiQueryRetriever 和 HyDE 实现)