RAG优化:用户随口一问,RAG为什么就检索不到?
如果用户的问题本身就不适合检索,正确文档压根没进候选集,该怎么办?
真实用户不会像测试工程师一样提问。
知识库里的标题可能是《企业版 macOS 客户端单点登录故障处理》,用户只会丢下一句:
那苹果电脑呢?
如果直接把这句话做 Embedding,检索器看到的只有“苹果电脑”。上一轮在聊什么、用户遇到什么故障、产品是什么,它一概不知道。
这不是向量数据库突然失灵,而是我们把一句不完整的话,当成了一条完整查询。
查询优化要做的事,就是在不改变用户意图的前提下,把自然对话转换成更适合检索的表达。常见方法有三种:
- Query Rewrite:把问题改写完整;
- Multi-Query:从多个角度表达同一需求;
- HyDE:先生成一段“假设答案”,再用它寻找表达相近的真实文档。
它们不是三个越多越好的开关,而是针对三类不同问题的工具。
一、先看查询为什么会失败
生产环境中,不适合直接检索的问题大致有下面几类。
| 类型 | 用户原话 | 检索困难 |
|---|---|---|
| 多轮指代 | 那企业版呢? | 缺少上一轮主题 |
| 口语表达 | 一直转圈进不去 | 文档使用“认证超时” |
| 缩写别名 | SSO 咋开 | 文档写“单点登录” |
| 复合问题 | 能导出吗,失败后怎么补偿? | 两个意图混在一起 |
| 现象描述 | 升级后以前的数据没了 | 文档按原因和模块组织 |
| 过度冗长 | 一大段背景加一个真正问题 | 无关词稀释检索信号 |
先不要急着上复杂方案。把线上失败查询按这些类型分桶,你会更容易判断该用哪种方法。
查询失败与对应策略
二、Query Rewrite:把对话变成独立查询
Query Rewrite 最适合处理指代、口语、错别字和上下文缺失。
例如对话是:
用户:Windows 客户端出现 1007 错误怎么处理?助手:可以先关闭代理并清理缓存。用户:那 Mac 呢?用于检索的独立查询应该是:
macOS 客户端出现 ERR_CONN_RESET_1007 时如何处理?关键在“独立”两个字。检索查询离开聊天记录后,仍然应该让人看得懂。
一个可控的改写 Prompt
你是企业知识库的查询改写器。任务:结合对话历史,将用户最后一个问题改写为一条独立、可检索的查询。规则:1. 保留产品、平台、版本、错误码、时间等已知实体。2. 只补全对话中已经出现的信息,不猜测缺失条件。3. 不回答问题,不提供解决方案。4. 如果原问题已经完整,原样返回。5. 只输出改写后的查询。实现时不要把无限长的聊天历史全部塞给模型。通常只保留最近几轮与当前问题相关的消息,并把已确认的结构化实体单独保存。
def build_rewrite_input(history, current_query, known_entities): return { "recent_history": history[-6:], "current_query": current_query, "known_entities": known_entities, }改写最大的风险:擅自补条件
原问题是“企业版怎么导出”,模型改成“企业版 Windows 客户端如何导出 PDF”,看起来更完整,实际上凭空增加了 Windows 和 PDF。
这会让检索结果更精确地走向错误方向。
生产环境建议做三层保护:
- 同时保留
original_query和rewritten_query; - 抽取两者的实体,检查产品、版本、金额、日期等关键字段是否被篡改;
- 对高风险场景只允许消歧和补全,不允许自由扩写。
三、Multi-Query:别把希望押在一种说法上
同一个问题,在用户和文档里可能有完全不同的表达。
用户问:
Pod 一直自己重启,怎么查?
知识库可能分别写成:
CrashLoopBackOff 排查;- 容器进程异常退出;
- 存活探针失败;
- OOMKilled 内存溢出。
只改写成一句标准问题,仍然可能覆盖不全。Multi-Query 会生成几条意图一致、角度不同的查询:
1. Kubernetes Pod 频繁重启的排查步骤2. CrashLoopBackOff 常见原因及处理方法3. 容器因健康检查失败反复重启如何定位4. Pod OOMKilled 与进程异常退出如何排查每条查询独立检索,再把结果合并、去重、RRF 融合,最后交给 Reranker。
def retrieve_multi_query(queries, retriever, per_query_k=10): result_lists = [] for query in queries: docs = retriever.invoke(query)[:per_query_k] result_lists.append(docs) return reciprocal_rank_fusion(result_lists)这里最重要的不是代码,而是约束生成的查询必须覆盖“不同表达”,不能偷偷变成“不同问题”。
什么场景值得用 Multi-Query
- 术语不统一,同一概念有多个别名;
- 问题较复杂,可能对应多种原因;
- 多跳问题需要从不同角度找证据;
- 单查询的 Recall 长期上不去。
什么场景不值得用
- 错误码、订单号、API 名称等精确查询;
- 原问题已经非常明确;
- 对延迟极其敏感;
- 知识库很小,单路召回已经稳定命中。
生成 5 条查询,往往意味着更多检索、更多候选和更多 Rerank 开销。它应该由评测结果触发,而不是默认给每个问题都上。
四、HyDE:用“答案的样子”去找答案
HyDE 全称是 Hypothetical Document Embeddings。名字听起来很复杂,思路其实很直白:
- 让大模型根据问题写一段可能的答案;
- 不把这段内容当真,只对它做 Embedding;
- 用这个向量去找表达方式相近的真实文档。
问题:升级后历史数据看不到了怎么办? ↓假设文档:升级后若历史数据暂不可见,应检查数据迁移任务、索引重建状态和租户映射,并确认旧版本数据是否完成同步…… ↓ Embedding检索真实的升级迁移与索引重建文档为什么这可能有效?因为短问题和正式文档在语言形态上差别很大。假设答案更像知识库正文,向量空间里可能更容易靠近真正的说明文档。
HyDE 的安全边界
那段假设答案可能包含幻觉。它只能是检索桥梁,绝不能直接作为最终回答,也不能作为可靠证据写入日志之外的业务流程。
def hyde_retrieve(question, llm, vector_store, k=20): hypothetical_doc = llm.invoke( "请为下面的问题生成一段可能出现在技术手册中的说明。" "内容仅用于检索,不要求事实正确,不要添加具体版本和数值。\n" f"问题:{question}" ).content return vector_store.similarity_search(hypothetical_doc, k=k)HyDE 更适合概念解释、故障现象、研究资料等“问题短、文档长”的场景。对于合同编号、政策日期、产品型号等精确查询,BM25 和 Metadata Filter 通常更直接。
五、三种方法到底怎么选
可以用下面的路由思路:
问题是否依赖对话或表达不完整? 是 → Query Rewrite 否 ↓问题是否存在多种叫法或多个检索角度? 是 → Multi-Query 否 ↓问题很短,且与长文档表达差距明显? 是 → HyDE 否 → 原查询直接检索实际系统也可以组合,但建议逐步增加:
| 方案 | LLM 调用 | 检索次数 | 主要收益 | 主要风险 |
|---|---|---|---|---|
| 原查询 | 0 | 1 | 快 | 口语查询召回差 |
| Rewrite | 1 | 1~2 | 补全意图 | 改变原意 |
| Multi-Query | 1 | 3~5 | 扩大覆盖 | 延迟、噪声增加 |
| HyDE | 1 | 1~2 | 缩小问答表达鸿沟 | 假设内容带偏 |
一个实用技巧是:**原始查询不要丢。**即使启用了 Rewrite 或 HyDE,也可以让原查询保留一路召回,再通过融合和 Rerank 决定最终结果。这相当于给查询优化加了一条保险绳。
六、如何评测查询优化,而不是只看几个 Demo
继续使用前面建立的固定评测集,但这次多记录几项数据:
{ "original_query": "那苹果电脑呢", "rewritten_query": "macOS 客户端出现 1007 错误时如何处理", "generated_queries": ["...", "..."], "strategy": "rewrite+multi_query", "retrieved_chunk_ids": ["doc-42#3", "doc-19#7"], "latency_ms": 486 }重点看:
- Recall@K 是否真的提高;
- 正确文档的首个排名是否前移;
- 改写后的实体是否忠于原问题;
- 不同查询返回的结果是否高度重复;
- 最终答案是否改善;
- P95 延迟和单次成本增加多少。
建议把评测集按multi_turn、colloquial、acronym、multi_intent、exact_match等类型分桶。总体分数上涨,不代表每类问题都适合查询扩展。
一个值得单独统计的指标:意图保持率
随机抽样改写结果,让人工或可靠 Judge 判断:
改写是否保留原意?A. 完全一致B. 基本一致,但有无害补充C. 增加了未经确认的条件D. 改变了问题查询优化如果让 Recall 上涨 5%,却有 3% 的查询被改错,在财务、法务和权限场景中可能完全不值得。
七、生产落地最容易踩的坑
把三种方法全部默认开启
链路看起来很高级,延迟和故障点也一起增加。先用失败类型路由,简单问题直接检索。
让模型补全用户没说过的信息
改写器的任务是整理,不是脑补。缺失的关键条件应该追问用户。
Multi-Query 生成同义句凑数
“如何处理”“怎么解决”“解决办法是什么”只是换了语序,没有增加召回覆盖。应该要求每条查询覆盖不同术语或原因角度。
把 HyDE 文本当作事实
HyDE 输出只能用于检索。最终回答必须引用真实知识库文档。
只比较最终答案
同时比较原查询、改写查询、每路候选和最终排名,否则无法知道提升来自哪里。
总结
查询优化解决的是“用户怎么问”和“文档怎么写”之间的距离。Query Rewrite 补全语境,Multi-Query 扩大表达覆盖,HyDE 用接近文档的语言寻找文档。
学AI大模型的正确顺序,千万不要搞错了
🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!
有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!
就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋
📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇
学习路线:
✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经
以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!
我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~