详细解释
Query Transformation(查询改写 / 查询变换) 一句话定义:用户输入的原始查询往往不适合直接做向量检索(比如太短、有口语噪声、有歧义、是多问题合在一起),所以在进向量库之前,先让一个便宜小模型(8B 级别足够,20ms,¥0.0002)把原始查询改写成 1-N 条更适合检索的查询,再用多条查询分别检索,合并去重后再送后续环节。这一步是 RAG 性能优化里成本最低、收益最高的前三技巧之一——只增加几乎可以忽略的成本,就能让 Top-K 召回率涨 10% 至 20%,很多团队 RAG 搜不到东西不是因为 chunk 切得不好,是查询本身没写对。
最主流的三种改写范式:(1) Query Expansion(查询扩展)——把一个短查询扩成 3 至 5 条同义/相关查询(比如用户问「年假规则」,扩展成「员工年假天数规定 / 年休假怎么计算 / 入职不满一年年假怎么算 / 年假可以跨年用吗」),每条都去检索,合并结果;(2) Sub-Query Decomposition(子查询拆分)——把多意图复合查询(「对比一下 A 和 B 产品的价格和售后服务并给购买建议」)拆成 4 个子查询分别检索,最后再合并给 LLM 生成;(3) HyDE(Hypothetical Document Embedding,假设文档嵌入)——不改写查询,而是让 LLM 先「假设写一段完美回答这个问题的文档内容」,然后用这段假设文档去 embedding 检索,因为假设文档和真实知识库中的 chunk 语言风格更像,相似度匹配更准。
唯元智创 的 RAG 服务默认开启了「自动查询改写策略选择器」——每条查询先判断是单意图短查询 / 多意图复合查询 / 模糊开放式查询,自动在 Expansion / Decomposition / HyDE 三种模式里选最优的一种,改写 3 条,合并召回结果后自动去重(按 chunk id 和内容 hash),业务方完全感知不到,只看到召回率显著上涨。
六种改写范式对比表(按查询类型选最合适的)
| 改写范式 | 处理流程 | 适合查询类型 | 成本倍数 | 召回提升 | 注意事项 |
|---|---|---|---|---|---|
| ① 查询扩展 Query Expansion | 原始查询 → LLM 扩 3-5 条同义查询 → 多路召回合并 | 短查询、FAQ 类、关键词模糊 | ×1.2(小模型便宜) | +10% 至 +15% | 不要扩太多,最多 5 条,否则引入噪声 |
| ② 子查询拆分 Decomposition | 多意图查询 → 拆成 N 个单意图子查询 → 每路子查询独立召回 → 按子查询分组排序 | 含「对比/分别/汇总/排名/和」等复合词的长查询 | ×1.3 至 ×2 | +15% 至 +25% | 必须拆成原子查询,子查询之间不能重叠 |
| ③ HyDE 假设文档 | 原始查询 → LLM 写一段假设的完美答案 → 假设答案 embedding → 用答案向量检索 | 开放式长问题、技术问题、要求有推理链的问题 | ×1.5(假设答案要写长一点) | +10% 至 +20% | 假设答案不能写太假,否则歪楼;必须用强模型写假设答案 |
| ④ 查询抽象/标准化 | 原始口语化查询 → 抽象成领域术语查询 → 用术语版去检索 | 用户口语化表达、错别字、行业黑话 | ×1.1 | +5% 至 +10% | 结合术语词典做改写 |
| ⑤ Step-Back Prompting(退一步提问) | 原始具体问题 → 先让 LLM 问一个更高层的抽象问题 → 先检索抽象问题的知识 → 结合抽象知识回答具体问题 | 需要背景知识的推理题、跨领域问题 | ×1.8 至 ×2.5 | +15% 至 +25% | 谷歌 DeepMind 2023 年论文提出,推理任务提升显著 |
| ⑥ 查询转述 + 回译 | 原始查询 → 翻译成英文 → 翻译回中文 → 用回译后的中文去检索 | 中文场景下口语化严重、训练数据中文覆盖不足的 embedding 模型 | ×1.5 | +5% 至 +8% | 适合 embedding 模型中英混训的场景(如 bge-m3) |
工程落地的四个关键护栏(防止改写引入噪声反而更差)
护栏 1:改写后多路召回的结果必须做「融合打分 + 去重」,不能简单拼接 Top-K。举反例:每条改写查询各召回 Top-10,3 条改写就有 30 条结果,如果直接拼,同一个 chunk 被 3 条改写都命中就占了 3 个位置,其他相关 chunk 被挤出去了。正确做法是 Reciprocal Rank Fusion(RRF)融合打分:每个 chunk 的最终分 = Σ 1/(rank_i + 60),被多条改写命中的 chunk 分数累加但不会线性膨胀;最后按 RRF 分数排序,按 chunk_id 去重,保留 Top-20。RRF 是工业界公认的多路召回融合标准算法,比加权平均更鲁棒。
护栏 2:必须设「改写置信度下限」,低置信度的改写直接丢弃,用原始查询。LLM 也会改写胡来——把「退款流程」扩成「公司 CEO 是谁 + 退款流程」。所以每条改写出来的查询,必须再过一个极小的二分类器(输入=原始查询+改写查询,输出=「改写是否相关」的概率),相关概率 <0.8 的改写直接丢;或者更简单:让改写 LLM 同时输出 0-1 的置信度分,分不够就丢。一般 3 条改写里丢 1 条差的,剩下 2 条质量够高,整体召回反而更好。
护栏 3:改写只作用于「召回阶段」,后续送给 LLM 生成的用户问题永远用原始查询。这是新人最常犯的错——把改写后的查询当最终用户问题送给生成模型,结果 LLM 回答的是改写的问题而不是用户真正问的,驴唇不对马嘴。记住铁则:改写后的查询只存在于「进向量库检索」的一刹那,用完就扔;生成模型的上下文里,用户问题永远是原始输入,改写痕迹完全隐藏。
护栏 4:A/B 实验驱动,不要一上来全量开。查询改写对不同知识库和不同查询分布的收益差异极大——在法律合同库上 HyDE 能涨 20%,在商品 FAQ 库上可能反而降 3%。上线前必须做严格的 A/B:对照组不用改写,实验组开三种改写中你选的那种,跑 1 周人工标注 200 条召回结果,确认「Recall@10 统计显著提升 ≥5% 且 Precision@10 下降 ≤3%」才允许全量,否则回调参数。