概述
本教程将帮助你熟悉 LangChain 的文档加载器、嵌入和向量存储抽象。这些抽象旨在支持从(向量)数据库和其他来源检索数据,以与大语言模型(LLM)工作流程集成。它们对于需要获取数据作为模型推理一部分进行推理的应用非常重要,如检索增强生成(RAG)的情况,参见 RAG。 在这里,我们将基于 PDF 文档构建一个搜索引擎。这将允许我们检索 PDF 中与输入查询相似的段落。本指南还包括在搜索引擎之上的最小 RAG 实现。概念
本指南聚焦于文本数据的检索。我们将涵盖以下概念:设置
安装
本教程需要langchain-community 和 pypdf 包:
LangSmith
使用 LangChain 构建的许多应用程序将包含多个步骤和多次大语言模型(LLM)调用。 随着这些应用程序变得越来越复杂,能够检查链或智能体内部到底发生了什么变得至关重要。 最好的方法是使用 LangSmith。 在上述链接注册后,确保设置环境变量以开始记录追踪:1. 文档和文档加载器
LangChain 实现了 Document 抽象,旨在表示一个文本单元及其关联的元数据。它有三个属性:page_content:表示内容的字符串;metadata:包含任意元数据的字典;id:(可选)文档的字符串标识符。
metadata 属性可以捕获有关文档来源、与其他文档的关系以及其他信息。请注意,单个 Document 对象通常表示较大文档的一个片段。
我们可以根据需要生成示例文档:
加载文档
让我们将一个 PDF 加载为一系列Document 对象。这里是一个示例 PDF——Nike 2023 年的 10-K 文件。我们可以查阅 LangChain 文档了解可用的 PDF 文档加载器。
PyPDFLoader 为每个 PDF 页面加载一个 Document 对象。对于每个对象,我们可以轻松访问:
- 页面的字符串内容;
- 包含文件名和页码的元数据。
分割
对于信息检索和下游问答目的,一页可能是过于粗粒度的表示。我们最终的目标是检索能够回答输入查询的Document 对象,进一步分割 PDF 将有助于确保文档相关部分的含义不会被周围文本”冲淡”。
我们可以使用文本分割器来实现这一目的。这里我们将使用一个简单的基于字符的文本分割器。我们将文档分割成 1000 个字符的块,块之间有 200 个字符的重叠。重叠有助于减轻将一条语句与其相关重要上下文分离的可能性。我们使用 RecursiveCharacterTextSplitter,它将使用常见的分隔符(如换行符)递归分割文档,直到每个块达到适当的大小。这是通用文本用例的推荐文本分割器。
我们设置 add_start_index=True,以便每个分割的 Document 在原始 Document 中的起始字符索引被保留为元数据属性 “start_index”。
2. 嵌入
向量搜索是存储和搜索非结构化数据(如非结构化文本)的常用方式。其思路是存储与文本关联的数值向量。给定一个查询,我们可以将其嵌入为相同维度的向量,并使用向量相似度指标(如余弦相似度)来识别相关文本。 LangChain 支持来自数十家提供商的嵌入。这些模型指定了如何将文本转换为数值向量。让我们选择一个模型:- OpenAI
- Azure
- Google Gemini
- Google Vertex
- AWS
- HuggingFace
- Ollama
- Cohere
- MistralAI
- Nomic
- NVIDIA
- Voyage AI
- IBM watsonx
- Fake
- Isaacus
3. 向量存储
LangChain VectorStore 对象包含向存储中添加文本和Document 对象的方法,以及使用各种相似度指标查询它们的方法。它们通常使用嵌入模型初始化,这些模型决定了如何将文本数据转换为数值向量。
LangChain 包含一套与不同向量存储技术的集成。一些向量存储由提供商托管(如各种云提供商),需要特定的凭证才能使用;一些(如 Postgres)运行在可以本地运行或通过第三方运行的独立基础设施上;其他一些可以在内存中运行以支持轻量级工作负载。让我们选择一个向量存储:
- In-memory
- Amazon OpenSearch
- AstraDB
- Chroma
- FAISS
- Milvus
- MongoDB
- PGVector
- PGVectorStore
- Pinecone
- Qdrant
VectorStore,就可以查询它了。VectorStore 包含以下查询方法:
- 同步和异步;
- 通过字符串查询和通过向量;
- 带和不带相似度分数;
- 通过相似度和最大边际相关性(在与查询的相似性和检索结果的多样性之间取得平衡)。
4. 检索器
LangChainVectorStore 对象不是 Runnable 的子类。LangChain Retrievers 是 Runnable,因此它们实现了一组标准方法(例如同步和异步的 invoke 和 batch 操作)。虽然我们可以从向量存储构造检索器,但检索器也可以与非向量存储数据源(如外部 API)接口。
我们可以自己创建一个简单的版本,无需子类化 Retriever。如果我们选择使用哪种方法来检索文档,就可以轻松创建一个 Runnable。下面我们将围绕 similarity_search 方法构建一个:
as_retriever 方法,可以生成一个 Retriever,具体来说是一个 VectorStoreRetriever。这些检索器包含特定的 search_type 和 search_kwargs 属性,标识调用底层向量存储的哪些方法以及如何参数化它们。例如,我们可以用以下方式复制上面的操作:
VectorStoreRetriever 支持 "similarity"(默认)、"mmr"(最大边际相关性,如上所述)和 "similarity_score_threshold" 搜索类型。我们可以使用后者按相似度分数阈值筛选检索器输出的文档。
检索器可以轻松地整合到更复杂的应用程序中,例如检索增强生成(RAG)应用程序,它将给定的问题与检索到的上下文组合成大语言模型(LLM)的提示词。要了解更多关于构建此类应用程序的信息,请查看 RAG 教程。
下一步
你现在已经了解了如何基于 PDF 文档构建语义搜索引擎。 有关文档加载器的更多信息: 有关嵌入的更多信息: 有关向量存储的更多信息: 有关 RAG 的更多信息,请参见:连接这些文档到 Claude、VSCode 等工具,通过 MCP 获取实时答案。

