探索 MultiQueryRetriever:提升向量数据库检索效果的利器

69 阅读2分钟
## 引言

在高维空间中基于距离的向量数据库检索,通过嵌入查询和文档来查找相似项。然而,查询措辞的细微变化或嵌入无法很好地捕捉数据语义时,检索结果可能会有所不同。为了手动解决这些问题,通常会进行提示工程或调整,但这往往很繁琐。`MultiQueryRetriever`通过使用大型语言模型(LLM)为给定的用户输入生成多个查询,从不同的视角自动化地进行提示调整。这样可以获得一个更大、更具潜在相关性的文档集合。

## 主要内容

### 构建示例向量数据库

我们将使用Lilain Weng在RAG教程中的博客文章来创建一个向量数据库。

```python
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用于查询生成,其余工作由检索器处理。

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?', ...]

自定义提示

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

# 输出解析器将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_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))  # 输出文档数量

常见问题和解决方案

  1. 查询生成不理想:尝试调整LLM的温度参数以获得更多样化的查询。
  2. 文档重复:确保使用适当的文档去重策略以获取唯一结果。

总结和进一步学习资源

MultiQueryRetriever为复杂查询带来了更高的灵活性,为开发者解决了基于距离的相似性搜索的一些局限性。通过此工具,您可以优化数据检索,获得更全面的结果集。

进一步学习资源

参考资料

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

---END---