news 2026/5/7 15:41:51

RAG 做不好?八成是用户问得太烂了——查询改写实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RAG 做不好?八成是用户问得太烂了——查询改写实战

前阵子帮一个客户优化他们的 RAG 系统,折腾了两周,效果就是提不上去。

数据拆了又拆,chunk size 调了 6 种组合,embedding 模型换了 3 个,reranker 也加了——到头来提升不到 5%。我差点以为这项目要砸手里了。

后来一个偶然的机会,我翻了翻日志里的用户原始查询,发现了一个惊人的事实:

绝大多数用户问的问题,直接拿去向量检索,根本找不到正确的内容。

不是系统不行,是"人和机器之间的语言鸿沟"太宽了。

今天就来聊聊 RAG 系统里最容易被忽略、但性价比最高的一环——查询改写(Query Rewriting)


问题到底出在哪

先给你看几个真实日志里的查询:

  1. “那个会画图的模型是什么来着”
  2. “前两天出的那篇讲 RAG 的文章”
  3. “怎么做”
  4. “之前说过的那个方案”

你看,凭这些问题,你让人来答都答不明白,何况是向量检索?

向量检索干的本质是语义匹配。它把你的查询向量化,跟库里的文档向量做相似度比较。问题越具体,匹配越准;问题越模糊,匹配越像在抽奖。

但用户不是故意的。他们来问问题的时候,脑子里已经有个上下文了。比如《那个会画图的模型是什么来着》——他可能上周刚看完一篇关于 DALL-E 3 的文章,所以觉得"会画图的模型"就够了。但对检索系统来说,这跟大海捞针差不多。

所以查询改写要做的事情就是:把用户模糊的、上下文依赖的、口语化的查询,翻译成检索系统能理解的具体、独立、明确的查询。


我试过的 3 种查询改写方案

花了大概一周时间,试了 3 种不同的方案,记录一下效果。


方案一:LLM 直接改写(最粗暴)

最简单的做法:把用户的原始查询扔给 LLM,让它"把问题写得更具体一些"。

Prompt 模板:

你是一个查询改写助手。用户提了一个问题,它可能很模糊或不完整。 请把它改写成适合搜索引擎使用的、具体的、独立的问题。 只输出改写后的问题,不要解释。 用户查询:{query} 改写结果:

实际效果:

好处是快,一个 LLM 调用就搞定,延迟也就几百毫秒。

但问题很快就暴露了——

LLM 改写有个毛病:它会把问题改写得太"完美"了。

举个例子,用户查"怎么做",LLM 改写成"如何实现 XXX 功能"。看起来没什么问题对吧?但实际上,用户问"怎么做"的时候,他心里想的可能是"怎么安装"、“怎么配置”、“怎么调试”——不同用户心里的"做"是完全不同的概念。LLM 自作主张帮你扩写了,反而可能把检索方向带偏。

我管这个叫"好心办坏事型的过度扩写"。

测试 100 条查询后,有效提升:约 15%。

有提升,但不够。


方案二:多查询扩写 + 融合搜索(推荐)

这个方法是我在一个韩国的 RAG 论文里看到的,实测效果最好。

思路很简单:不要只改写一个版本,而是生成多个不同的改写版本,分别去检索,然后把结果融合。

具体做法:

defrewrite_queries(query,llm,num_versions=3):prompt=f""" 用户查询:{query}请从以下三个不同角度各生成一个改写后的查询: 1. 最完整版:补充所有隐含信息 2. 最简洁版:保留核心关键词 3. 同义替换版:使用不同的表达方式 输出格式: 1. [完整版] 2. [简洁版] 3. [同义版] """response=llm.invoke(prompt)returnparse_versions(response)

融合策略:

多路检索结果先用 Reciprocal Rank Fusion(RRF)合并排序,再用一个轻量级 reranker 重排。

这么做的道理是什么?

用户的原始查询可能颗粒度不匹配,但三个不同的改写版本,理论上总有一个能"碰"到正确的文档。RRF 融合再把这些命中的文档提到前面来。

实测效果:

  • 改写 3 个版本 + RRF 融合:召回率提升约 35%
  • 加 reranker 重排后:首条命中率提升约 42%

这是我测试出来的性价比最高的方案。不需要换 embedding 模型,不需要调整索引策略,就加一个查询改写层,召回率直接拉上去。

代价:

  • 多了一次 LLM 调用(生成本不高,3 个版本一次生成就好了)
  • 检索次数变成了 3 倍(可以用异步并行,延迟基本持平)
  • RRF 计算几乎零开销

这个方案后来我在线上跑了两个星期,效果稳定。


方案三:上下文感知改写(最精细)

这个方案更激进一些——如果 RAG 系统的对话里有历史消息,可以利用聊天历史来帮助改写。

举个例子,如果用户说:

历史:用户问"你们公司今年有什么新产品"
历史:助手答"我们推出了 GPT-Image 2,可以 AI 生图…"
当前:用户问"多少钱"

这时候,如果只看当前查询"多少钱",根本无法检索。但如果结合历史,改写结果应该是"GPT-Image 2 的 API 定价是多少钱"。

做法:

把最近 3-5 轮对话历史 + 当前问题一起发给 LLM,让它生成一个"自包含"的查询。

defcontext_aware_rewrite(query,history,llm):messages=[{"role":"system","content":"请根据对话历史,将用户最新问题改写为不依赖上下文的独立查询。"},*histo ry[-4:],# 最近 4 轮{"role":"user","content":query}]response=llm.invoke(messages)returnresponse.content

效果:在多轮对话场景下,准确率比直接改写提升了约 20%。

代价:需要维护对话历史,prompt 更长,每个查询多消耗一些 token。


我最终推荐的方案

如果你在看这篇文章,想在自己的 RAG 系统里加上查询改写,我建议你这样做:

第一步:先做多查询扩写 + RRF 融合(方案二)

这个改造成本最低。你只需要在检索前加一层改写逻辑,然后把索引逻辑从"一次检索"改成"三次检索 + 一次 RRF 融合"。改动量大约 100 行代码。

第二步:如果有多轮对话场景,加上下文感知改写(方案三)

这个也不复杂,主要是改 prompt。

第三步:不要只依赖 LLM 改写

我发现很多人做查询改写,直接把用户问题扔给 GPT 然后取结果,以为就完事了。这样效果其实一般。好的查询改写应该和目标检索系统配合。比如你的检索系统是做稀疏检索(BM25)的,改写方向应该是关键词补充;做稠密检索(向量)的,改写方向应该是语义扩写。


踩坑记录

最后分享几个我亲身踩过的坑:

坑 1:改写后的查询太长。有一次 LLM 把一句 “怎么用” 改写成了 “如何在 Python 环境中使用 LangChain 框架的 Agent 模块来构建一个能够调用外部 API 的智能助手”。全长 50 个字。当这个查询喂给向量检索时,因为噪声太多,匹配结果反而更差了。
解决:在 prompt 里明确限制改写后的查询长度不超过 20 个字。

坑 2:过度依赖改写。有些查询本身已经很明确了(比如"LangChain 的 AgentExecutor 源码分析"),不需要改写。不改写反而更好。所以我加了一个简单的检测:如果原始查询已经包含 4 个以上的实体关键词,就不做改写,直接检索。
结果:这个"跳过改写"逻辑让整体准确率又提升了 8%。

坑 3:改写后丢失专有名词。有一次用户查的是"ChatGPT 的 System Prompt 长度限制",LLM 改写后变成了"大语言模型的提示长度限制"。虽然意思相近,但"System Prompt"这个专有名词被泛化了,导致检索不到相关文档。
解决:在 prompt 里强调"保留所有专有名词、产品名、技术术语不修改"。


写在最后

折腾了这么一圈,我最大的感受是:很多人花大钱买贵的 embedding 模型、搭复杂的索引架构,却在最基础的"用户问的问题本身就没写对"这个环节上翻了车。

查询改写是 RAG 系统里投入产出比最高的优化点之一。不夸张地说,加一层查询改写,比换一个更贵的 embedding 模型带来的提升大得多。

你现在的 RAG 系统有做查询改写吗?用的什么方案?评论区聊聊。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/7 15:40:27

个人八股之stream流

前瞻环节大家好,我是程序员无尽冬 ,欢迎大家来到我的专栏。本篇我们将给大家讲解stream流 同时也会将它整理为我的个人八股分享给大家 希望大家可以喜欢。首先我们了解一下什么是stream流stream流简述java 8 引入的 Stream 是一种对集合 数据进行高效操作…

作者头像 李华
网站建设 2026/5/7 15:32:51

终极免费开源工具:AntiDupl.NET帮你轻松清理电脑重复图片

终极免费开源工具:AntiDupl.NET帮你轻松清理电脑重复图片 【免费下载链接】AntiDupl A program to search similar and defect pictures on the disk 项目地址: https://gitcode.com/gh_mirrors/an/AntiDupl 你是否曾因为电脑中堆积如山的重复图片而烦恼&…

作者头像 李华
网站建设 2026/5/7 15:31:49

从零开始掌握13个机器学习算法:西瓜书代码实战项目详解

从零开始掌握13个机器学习算法:西瓜书代码实战项目详解 【免费下载链接】machine-learning-toy-code 《机器学习》(西瓜书)代码实战 项目地址: https://gitcode.com/gh_mirrors/ma/machine-learning-toy-code 想要学习机器学习但总是被…

作者头像 李华
网站建设 2026/5/7 15:29:32

GetQzonehistory:一站式自动化QQ空间历史数据备份解决方案

GetQzonehistory:一站式自动化QQ空间历史数据备份解决方案 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 在数字记忆日益重要的今天,如何安全高效地备份个人社交…

作者头像 李华