Skip to content

检索查询改写专题

版本:v1.2

最后更新:2026-07-09

很多 RAG 系统失败,并不是因为知识库里没有答案,而是因为:

  • 用户的问题表达太口语
  • 查询词和文档里的标准术语不一致
  • 多轮对话里充满代词、省略和上下文依赖
  • 原始问题同时混着多个意图、多个限制条件

这也是为什么检索查询改写经常是 RAG 优化里性价比很高的一步。它不直接增加知识,也不直接提高模型推理能力,但它会显著改变:

  • 召回到什么证据
  • 是否能命中权威文档
  • 上下文里噪音有多少
  • 最终答案是不是更接近用户真实意图

1. 什么是查询改写

更实用的理解通常是:

  • 在真正检索前
  • 把用户原始问题改写成更适合召回知识的查询表达

它不是简单“换个说法”,而是为了让检索系统更容易命中正确证据。

这个动作通常位于:

text
User Question
 -> Query Understanding
 -> Query Rewrite / Expansion
 -> Retrieval
 -> Rerank
 -> Context Assembly
 -> Answer Generation

查询改写不是回答问题本身,而是在为后续检索做“查询工程”。

2. 为什么原始用户问题经常不适合直接检索

真实用户的问题往往不是为搜索引擎写的,而是为人写的。常见情况包括:

  • 表达省略
  • 指代不明
  • 多轮上下文依赖强
  • 术语口语化
  • 混杂多个意图
  • 把真正问题埋在长段背景里

例如这些问题都很常见:

  • 这个开票后还能退吗
  • 刚才那个审批链要走几级
  • 500 这个错怎么处理
  • 帮我看下企业版那个退款规则

如果把原问题原样送进检索,系统很容易:

  • 命中表面相似但业务无关的内容
  • 错过标准术语文档
  • 召回过宽,导致上下文被噪音填满
  • 把多意图问题误当单意图处理

3. 查询改写到底在解决什么

查询改写通常在解决四类问题。

3.1 语义补全

用户没有把必要上下文说完整,系统需要补足:

  • 产品名
  • 模块名
  • 当前实体
  • 上下文里的主语

例如:

  • 这个开票后还能退吗

在多轮上下文里可能需要改成:

  • 企业版订单开票后是否支持退款

3.2 术语标准化

用户说的是口语,文档里写的是标准术语。

例如:

  • 打钱回去
  • 撤单
  • 关单

文档里实际可能对应:

  • 退款
  • 取消订单
  • 关闭工单

3.3 多意图拆分

一个问题里同时有多个子问题,直接检索会让候选结果混杂。

例如:

  • 帮我看下企业版价格,顺便看开票后还能不能退

这类问题更适合拆成两个检索子任务:

  • 企业版价格
  • 开票后退款政策

3.4 检索展开

不是只生成一个 query,而是生成多个并行检索表达,覆盖不同说法。

这通常适合:

  • 术语别名多
  • 中英混用
  • 业务黑话多
  • 用户表达波动大的系统

4. 查询改写不是越激进越好

查询改写常见误区是:

  • 只要能多召回,就认为改写有效

但真正要看的不是:

  • 改写后召回更多了没有

而是:

  • 改写后是否更接近用户真实意图

因为改写过度会带来新的问题:

  • 改写偏离原意
  • 加入错误约束条件
  • 错把单问题拆成多个不相关问题
  • 用标准术语覆盖掉用户真正问的边界条件
  • 对精确编号、错误码、产品码做了不该做的“语义化”

尤其是下面这些内容,经常不适合被“聪明改写”:

  • 错误码
  • 产品型号
  • 合同条款号
  • 法条编号
  • 工单号
  • 订单号

这类 query 往往更适合保留原词精确检索。

5. 更实用的查询改写分类法

把查询改写分成几类来治理,比一套 prompt 包打天下更稳。

5.1 归一化改写

目标:

  • 去掉明显无意义噪音
  • 保留原始核心意图
  • 标准化格式

适合:

  • 语气词多
  • 口语化严重
  • 中英混杂但结构简单

5.2 上下文补全改写

目标:

  • 从多轮会话里恢复出完整主语、对象和约束条件

适合:

  • 这个
  • 那个
  • 刚才那个规则
  • 上次说的审批

这类问题一定要谨慎,最好保留原 query 和补全后的 query 供回放。

5.3 术语映射改写

目标:

  • 把用户说法映射到知识库标准表达

例如:

  • 打款 -> 退款
  • 报销单 -> 费用报销申请
  • 白名单 -> 允许名单

适合:

  • 企业内部黑话重
  • 术语标准化严格
  • 同义表达很多

5.4 多查询展开

目标:

  • 生成多个等价或互补查询,扩大召回覆盖

适合:

  • 语义别名很多
  • 文档说法不统一
  • 产品线历史文档口径不一致

但要注意控制展开数量,不然会导致:

  • 候选集爆炸
  • rerank 成本飙升
  • 上下文噪音增加

5.5 结构化条件抽取

目标:

  • 从自然语言里提取可过滤字段

例如:

  • 产品线
  • 部门
  • 时间范围
  • 租户
  • 文档类型

这比只做自由文本改写更适合企业知识库。因为很多企业检索失败,不是语义没对上,而是缺少过滤条件。

6. 查询改写应当保留原始问题,而不是覆盖原问题

这是非常重要的一条工程原则。

不要把查询改写做成:

  • 改完就把原 query 丢掉

更稳妥的做法通常是保留三份内容:

  • 原始 query
  • 改写后 query
  • 改写理由或改写类型

例如:

json
{
  "original_query": "这个开票后还能退吗",
  "rewritten_query": "企业版订单开票后是否支持退款",
  "rewrite_type": "context_completion",
  "rewrite_reason": "从上一轮会话补全产品对象为企业版订单"
}

这样做的收益很直接:

  • 方便排查误改写
  • 方便把失败样例回流到评测集
  • 方便比较“原查”和“改写查”的效果差异

7. 查询改写如何进入多轮对话系统

多轮系统里,很多检索失败并不是用户不会问,而是系统没把上下文接对。

查询改写在多轮场景里通常要额外处理:

  • 当前轮的显式问题
  • 上一轮提到的实体
  • 当前会话里的目标对象
  • 已确认的业务约束

但不要把整段聊天历史全拼进检索 query。

更推荐的做法是先做“会话状态抽取”,再改写:

json
{
  "entity": "企业版订单",
  "topic": "退款政策",
  "constraint": "已开票",
  "user_query": "这个还能退吗"
}

然后输出更适合检索的 query:

  • 企业版订单 已开票 退款政策

这通常比把 20 轮聊天都塞进检索更稳。

8. 查询改写和 metadata 过滤应一起设计

很多团队把 query 改写理解成“把文字改得更像搜索词”,但企业检索里常常还需要同步生成过滤条件。

例如问题:

  • 今年生效的华东区企业客户退款规则是什么

除了 query 文本本身,系统还可能需要提取:

  • 时间范围:2026
  • 区域:华东
  • 客户类型:企业客户
  • 文档类型:政策

所以更成熟的输出通常不是一个字符串,而是一份结构化查询对象:

json
{
  "query_text": "企业客户退款规则",
  "filters": {
    "region": "east_china",
    "customer_type": "enterprise",
    "effective_year": 2026
  }
}

这会让后续检索、缓存和回放都更稳定。

9. 改写最好有明确 contract,而不是随手写个 prompt

很多团队会先写一句:

  • “请把用户问题改成更适合检索的问题”

然后就开始上线。

这通常不够,因为系统并没有明确:

  • 哪些信息必须保留
  • 哪些信息可以补
  • 哪些信息禁止猜
  • 输出到底是一条 query 还是一个结构化对象

一个更稳的 rewrite contract,至少应回答:

  • must_preserve:编号、产品名、时间、组织、角色是否必须保留
  • may_normalize:口语表达、术语别名是否允许归一化
  • may_expand:是否允许生成多 query 展开
  • must_not_infer:没有明示的条件能不能猜
  • output_shape:字符串、query 列表,还是 query + filters

9.1 对高风险 query,contract 应更保守

例如制度、审批、价格、权限类问题,通常更适合:

  • 保留原词
  • 限制扩写
  • 限制多 query 展开
  • 强制带出结构化 filters

9.2 同义词映射有时比 generative rewrite 更稳

Azure AI Search 当前 synonym map 文档说明:

  • 同义词映射可以在不改用户原 query 的情况下扩展术语覆盖范围

这给工程实践一个很实用的启发:

  • 术语归一化不一定非要靠模型自由改写
  • 对稳定词表、产品别名、行业术语,静态 synonym map 往往更可控

10. 不同查询类型应该走不同改写策略

并不是所有 query 都该强行改写。

一个实用的分流方式通常是:

查询类型是否建议改写重点
精确编号/错误码谨慎,通常弱改写保留原词精确匹配
FAQ/口语问答建议改写术语映射、口语标准化
多轮指代问题建议改写上下文补全
多条件复杂问题建议改写条件抽取、拆分
高风险制度问答建议谨慎改写避免过度扩写导致误导

如果所有问题都走同一套改写 prompt,后面几乎一定会出现:

  • 某些 query 改得很好
  • 某些 query 被改坏且难以解释

10.1 query 路由表比统一 prompt 更重要

一个更像生产系统的规划方式通常是:

text
exact-id query
 -> no rewrite or weak normalize

multi-turn reference query
 -> context completion rewrite

policy query
 -> rewrite + filters extraction
 -> strict preserve of time / role / org

重点不是改写做得多花,而是:

  • 不同 query 桶有没有正确的改写边界

11. 查询改写要怎么评测

查询改写如果只看“召回多了没有”,很容易把系统带偏。

更建议从四层看:

11.1 改写质量本身

  • 改写是否保留原始意图
  • 是否错误添加条件
  • 是否错误删掉关键实体

11.2 检索层效果

  • Recall@k 是否改善
  • MRR 是否改善
  • 是否更容易命中权威文档

11.3 证据层效果

  • 改写后进入上下文的证据质量是否更高
  • 是否减少无关候选
  • 是否降低冲突证据比例

11.4 最终答案效果

  • 答案相关性是否更高
  • 引用是否更正确
  • 拒答率是否更合理
  • 高风险场景是否更稳

一个最小评测样例可以长这样:

json
{
  "original_query": "这个开票后还能退吗",
  "rewritten_query": "企业版订单开票后是否支持退款",
  "must_hit_docs": ["refund-policy-enterprise-v3"],
  "must_not_hit_docs": ["invoice-header-change-policy"],
  "expected_answer_behavior": "应回答不能自动退款,需人工审批"
}

11.5 评测最好保留 original / rewritten 并排对比

更稳的评测并不是只跑 rewrite 之后的结果,而是同时保留:

  • original query 结果
  • rewritten query 结果
  • 合并或路由后的最终结果

否则你很难判断:

  • 是 rewrite 真有帮助
  • 还是本来原 query 就够用了

12. 改写链路最好能被 trace 和 replay 完整还原

如果改写只发生在某个黑盒 prompt 里,出了问题几乎很难复盘。

至少建议保留:

  • original_query
  • rewrite_query
  • rewrite_type
  • rewrite_version
  • rewrite_filters
  • rewrite_confidence
  • query_bucket
  • retrieval_strategy_version

如果系统允许多 query 展开,建议再保留:

  • expanded_queries
  • expanded_query_count
  • 每条 expanded query 的命中贡献

这样后面你才能真正回答:

  • 是哪种 rewrite 在变坏
  • 是哪类 query 桶在退化
  • 是哪条 expanded query 把脏结果放大了

13. 查询改写失败时,常见是哪里出了问题

13.1 过度语义化

把用户精确问的对象“智能泛化”掉了。

13.2 胡乱补全上下文

系统自己猜了一个错误主语。

13.3 多查询展开太多

召回是多了,但噪音也一起放大。

13.4 改写链路不可见

出了问题,没人知道检索用的是哪一版 query。

13.5 把生成质量问题误判成 query 问题

有时命中了正确证据,但模型没正确消费,这不是改写层的问题。

13.6 把同义词、过滤、rerank 问题全推给 rewrite

很多问题看起来像“query 不够好”,其实根因可能是:

  • 术语词表没补
  • filter 没带上时间/角色/组织
  • rerank 没看到正确候选

14. 查询改写发布时,最值得盯的是哪类退化

查询改写一旦上线,最危险的不是平均值小幅波动,而是某些关键 query 桶突然变坏。

尤其要单独盯:

  • 编号 / 错误码 query
  • 时间敏感 query
  • 权限敏感 query
  • 高风险制度 / 审批 query
  • 高频客服 query

更稳的做法通常是:

  • 先按 query 桶灰度
  • 对高风险桶保留 original query fallback
  • 让典型 rewrite 失败样例进入 release blocker

15. 一个更稳的落地顺序

如果你准备把查询改写接进生产 RAG,建议按这个顺序推进:

  1. 先收集真实检索失败样例。
  2. 判断失败是否真的由 query 表达导致。
  3. 先做保守型改写,不要一上来搞复杂多 query 展开。
  4. 保留原 query、改写 query 和改写类型日志。
  5. 用固定评测集验证改写是否提升命中和答案质量。
  6. 再逐步加入上下文补全、术语映射和结构化过滤提取。
  7. 最后再做 query 桶灰度和 release blocker 门禁。

这样查询改写才会是可治理能力,而不是一堆不可解释的 prompt 花活。

16. 常见反模式

  • 所有问题都强行改写
  • 改写结果无法回放和解释
  • 只看 top-k,不看最终答案质量
  • 原 query 和改写 query 断链
  • 把 query rewrite 当成弥补知识缺失的手段
  • 改写失败样例不进入回归集
  • 没有 original query fallback 就直接全量放开
  • 本该用 synonym map 的稳定术语,也全交给模型自由改写

17. 推荐搭配阅读

18. 重点官方资源

以下资源已按 2026-07-09 的官方入口重新整理:

说明:

  • Azure 的 query rewrite 文档在 2026-07-09 仍标注为 preview,官方同时说明该预览功能不建议直接用于生产关键负载,所以更适合作为能力参考和实验入口,而不是无条件照搬生产默认方案。

19. 落地检查清单

  • 是否为不同 query 桶定义了不同改写边界
  • 是否保留了 original query、rewrite query 和 rewrite filters
  • 是否能从 trace 还原每次改写链路与 query 路由
  • 是否同时看改写质量、检索效果、证据质量和最终答案效果
  • 是否把高风险 rewrite 失败样例接进回归与发布门禁