如何使用多向量检索文档

在现代信息检索系统中,使用多个向量来检索单个文档是一个非常有用的技术。这种方法在多个应用场景中都有其优势,比如可以将文档分割为多个块,对这些块分别进行嵌入,从而提高语义检索的准确性。LangChain 提供了一个 baseMultiVectorRetriever 类,为我们简化了这一过程。本文将详细讲解如何生成这些向量,并使用 MultiVectorRetriever 进行检索。

1. 技术背景介绍

在信息检索中,仅依赖于单一向量来表示一个文档可能无法捕获其完整的语义。因此,使用多个向量来表示文档的不同部分或层面,可以提高检索的准确性。例如,可以将文档切分为更小的块分别进行嵌入,或者为文档生成摘要和假设性问题,以便更加多样化的查询。

2. 核心原理解析

关键在于如何生成多个向量:

  • 小块切分:将文档分割为更小的块进行嵌入。
  • 摘要生成:为每个文档创建摘要,并使用摘要进行检索。
  • 假设性问题:生成文档可能回答的问题,并使用这些问题进行检索。

3. 代码实现演示(重点)

文档加载和切分

首先,我们加载文档并将其分割为更小的片段:

from langchain.storage import InMemoryByteStore
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 加载文档
loaders = [
    TextLoader("paul_graham_essay.txt"),
    TextLoader("state_of_the_union.txt"),
]
docs = []
for loader in loaders:
    docs.extend(loader.load())

# 文档切分
text_splitter = RecursiveCharacterTextSplitter(chunk_size=10000)
docs = text_splitter.split_documents(docs)

# 使用 Chroma 向量存储进行索引
vectorstore = Chroma(collection_name="full_documents", embedding_function=OpenAIEmbeddings())

多向量检索设置

我们创建存储层和检索器:

import uuid
from langchain.retrievers.multi_vector import MultiVectorRetriever

store = InMemoryByteStore()
id_key = "doc_id"

retriever = MultiVectorRetriever(
    vectorstore=vectorstore,
    byte_store=store,
    id_key=id_key,
)

doc_ids = [str(uuid.uuid4()) for _ in docs]

索引子文档

将文档分割为更小的块并进行嵌入:

child_text_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
sub_docs = []
for i, doc in enumerate(docs):
    _id = doc_ids[i]
    _sub_docs = child_text_splitter.split_documents([doc])
    for _doc in _sub_docs:
        _doc.metadata[id_key] = _id
    sub_docs.extend(_sub_docs)

retriever.vectorstore.add_documents(sub_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))

检索示例

我们可以通过检索较小的嵌入块来获取语义相关的上下文,然后返回完整的文档:

# 检索小块
retriever.vectorstore.similarity_search("justice breyer")[0]
# 返回父文档
retriever.invoke("justice breyer")[0].page_content

4. 应用场景分析

这种多向量检索方法适用于需要精确上下文检索的场景,比如法律文档分析、学术论文检索等。通过将文档切分为更小的块进行嵌入,可以提高检索的准确性,并能够捕获更多语义信息。

5. 实践建议

  • 灵活调整切分粒度:根据文档类型和应用需求,灵活调整文档切分的粒度。
  • 结合人类知识:在生成假设性问题或摘要时,可以结合特定领域的人类知识,以提高检索效果。
  • 混合使用多种方法:对于复杂结构的文档,可以结合小块切分、摘要生成和假设性问题生成以获得最佳效果。

如果遇到问题欢迎在评论区交流。
—END—

你可能感兴趣的:(服务器,linux,运维,python)