RAG Query 改写 之 Mulit-Query 多查询改写
1、基础铺垫
想象一下这个场景:有一个智能客服机器人。用户问:“华为公司最新款手机有什么亮点,它和Oppo的旗舰机比怎么样?”
传统的RAG系统会直接拿这个问题去向量库搜索。但结果往往不尽人意,因为这个问题里其实“打包”了好几个问题:
华为最新款手机的亮点(特性、功能)。
Oppo最新旗舰机的特性。
两者的比较。
单一查询可能只召回了一部分相关信息,导致回答不完整或比较肤浅。
这就是Multi-Query要解决的核心问题:一个复杂、复合或多角度的问题,往往需要多个不同的“搜索姿势”才能把相关知识一网打尽。
Multi-Query的核心思路分两步:
查询分析(提问): AI分析用户的原始问题,识别其中的隐含子问题、不同侧面或同义表达。
并行搜索(调查): 同时用多个生成的、角度各异的查询去向向量数据库提问,召回更全面的相关文档碎片。
综合研判(破案): 将所有召回的结果去重、排序、整合,最终交给LLM生成一个全面、准确的答案。
2、实现方式
2.1、基础版 —— 使用LLM直接生成多个查询,只需要一个靠谱的LLM和一句精心设计的提示词。
步骤拆解:
• 接收用户原始查询。
• 构造提示词(Prompt),让LLM生成3-5个相关的、不同的查询。
• 调用LLM生成多查询。
• 并发执行所有查询,搜索向量数据库。
• 合并所有检索结果,进行去重和重排序。
• 将合并后的上下文与原始问题一起,交给LLM生成最终答案。
提示词:
你是一个专业的搜索引擎优化专家。你的任务是为给定的用户问题生成3个不同的搜索查询,以便从知识库中检索相关文档。
这些查询应该是多样化的,涵盖问题的不同角度、同义替换和可能的子问题。
用户问题:{original_question}
请严格按照以下JSON格式输出,不要输出任何其他内容:
{
"queries": ["query1", "query2", "query3"]
}
简单代码示意:
from langchain.chat_models import ChatOpenAI
from langchain_classic.retrievers import MultiQueryRetriever
# 1. 初始化你的向量数据库和LLM
llm = ChatOpenAI(temperature=0)
vectorstore = vectorstore
# 2. 使用LangChain内置的MultiQueryRetriever(它封装了上述逻辑)
retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(), # 基础检索器
llm=llm # 用于生成多查询的LLM
)
# 3. 使用它进行检索
docs = retriever.get_relevant_documents("苹果公司最新款手机有什么亮点,它和三星的旗舰机比怎么样?")
# docs 已经是合并、去重后的相关文档列表了
2.2、控制生成角度(更精准),如果基础版效果发散,可以引导LLM从更具体的角度生成查询。
提示词:
请针对以下问题,分别从 **产品特性、竞争对手比较、用户评价** 三个角度,生成三个搜索查询。
问题:{original_question}
输出格式:
1. [产品特性角度]: ...
2. [竞争对手比较角度]: ...
3. [用户评价角度]: ...
这种方式对检索过程有更强的控制力,特别适合垂直领域(如法律、医疗),需要确保覆盖某些特定方面。
3、隐含的坑
3.1、数量与质量的权衡: 生成3-5个查询通常是最佳点。太少没效果,太多(如10个)会引入大量噪声,拖慢速度,增加成本。
3.2、警惕“过度发散”: 一定要在提示词里强调“与原始问题高度相关”。否则LLM可能生成天马行空的查询,召回完全不相关的文档。
3.3、合并去重是关键: 多个查询必然会召回大量重复或高度相似的文档。务必使用高效的 “最大边际相关性”(MMR) 等算法进行去重和重排序,优先保留信息量高且多样化的文档。
3.4、成本意识: 每次检索都调用LLM生成查询,会产生额外成本。对于简单、事实性问题,也许不需要Multi-Query。可以设计一个“路由判断”逻辑,只对复杂问题启用它。
3.5、评估不可或缺: 上线前,一定要用一批测试问题对比使用Multi-Query前后的效果。关注答案的准确性、完整性,而不仅仅是检索的召回率。
Multi-Query改写就像为RAG系统配上了一副“多角度透镜”,让它能更立体地理解用户问题,从而进行更全面的信息搜集

浙公网安备 33010602011771号