Skip to main content
本教程将帮助您熟悉 LangChain 的文档加载器嵌入模型向量存储 抽象层。这些抽象层旨在支持从(向量)数据库及其他来源检索数据,以便与大语言模型(LLM)工作流集成。对于需要在模型推理过程中获取待分析数据的应用(例如检索增强生成 RAG),它们至关重要。 在本教程中,我们将基于一份 PDF 文档构建一个搜索引擎,用于检索与输入查询相似的 PDF 段落。此外,本指南还将在该搜索引擎基础上实现一个最小化的 RAG 应用。

核心概念

本指南聚焦于文本数据的检索,涵盖以下核心概念:
  • 文档与文档加载器;
  • 文本分割器;
  • 嵌入模型;
  • 向量存储与检索器。

环境设置

安装依赖

本教程需要安装 langchain-communitypypdf 包:
更多详情请参阅我们的 安装指南

LangSmith

使用 LangChain 构建的许多应用会包含多个步骤及多次 LLM 调用。随着应用日益复杂,能够检查链或代理内部具体发生了什么变得至关重要。最佳方式是使用 LangSmith 注册上述链接后,请设置环境变量以开始记录追踪信息:
或者,在笔记本环境中可这样设置:

文档与文档加载器

LangChain 实现了 Document 抽象类,用于表示一段文本及其关联元数据,包含三个属性:
  • page_content:代表内容的字符串;
  • metadata:包含任意元数据的字典;
  • id:(可选)文档的字符串标识符。
metadata 属性可用于捕获文档来源、与其他文档的关系等信息。注意,单个 Document 对象通常代表较大文档的一个片段。 我们可以按需生成示例文档:
然而,LangChain 生态系统实现了文档加载器可对接数百种常见数据源,便于将这些数据源的数据整合到您的 AI 应用中。

加载文档

让我们将一份 PDF 加载为一系列 Document 对象。LangChain 仓库中有一个示例 PDF 在此处 —— 耐克公司 2023 年的 10-K 文件。我们可以查阅 LangChain 文档中的 可用 PDF 文档加载器
PyPDFLoader 为每页 PDF 创建一个 Document 对象。每个对象均可轻松访问:
  • 页面的字符串内容;
  • 包含文件名和页码的元数据。

文本分割

无论是为了信息检索还是后续问答任务,以整页作为粒度可能过于粗糙。我们的最终目标是检索能回答输入查询的 Document 对象,进一步分割 PDF 有助于确保相关段落的含义不会被周围文本“稀释”。 为此,我们可以使用文本分割器。这里我们使用一个基于字符的简单文本分割器,将文档分割为 1000 字符的块,并在块间保留 200 字符的重叠部分。重叠有助于避免将语句与其重要上下文分离。我们使用 RecursiveCharacterTextSplitter,它会递归地使用常见分隔符(如换行符)分割文档,直到每个块达到合适大小。这是通用文本场景推荐的文本分割器。 我们设置 add_start_index=True,以便在初始文档中每个分割文档的起始字符索引作为元数据属性 “start_index” 保留下来。

嵌入模型

向量搜索是存储和检索非结构化数据(如非结构化文本)的常用方法。其核心思想是将文本关联的数值向量存储起来。给定一个查询,我们可以将其嵌入为相同维度的向量,并使用向量相似度度量(如余弦相似度)识别相关文本。 LangChain 支持来自数十家提供商的嵌入模型。这些模型规定了如何将文本转换为数值向量。让我们选择一个模型:
有了生成文本嵌入的模型后,下一步便是将它们存储在一个支持高效相似度搜索的特殊数据结构中。

向量存储

LangChain 的 VectorStore 对象包含向存储中添加文本和 Document 对象的方法,以及使用各种相似度度量进行查询的方法。它们通常使用嵌入模型初始化,这些模型决定了文本数据如何转换为数值向量。 LangChain 提供了一系列与不同向量存储技术的集成。一些向量存储由提供商托管(如各类云服务商),需要特定凭证才能使用;一些(如 Postgres)可在本地或通过第三方运行的独立基础设施上运行;还有一些可内存运行以处理轻量级负载。让我们选择一个向量存储:
实例化向量存储后,我们现在可以对文档建立索引。
请注意,大多数向量存储实现允许您连接到现有的向量存储——例如,通过提供客户端、索引名称或其他信息。有关更多详细信息,请参阅特定集成的文档。 一旦我们实例化了一个包含文档的 VectorStore,就可以对其进行查询。VectorStore 包含以下查询方法:
  • 同步和异步查询;
  • 通过字符串查询和通过向量查询;
  • 返回和不返回相似度分数;
  • 通过相似度和最大边际相关性(在检索结果的相关性与多样性之间取得平衡)。
这些方法的输出通常包含一个 Document 对象列表。

使用示例

嵌入模型通常将文本表示为“稠密”向量,使得语义相似的文本在几何空间中彼此接近。这使我们只需传入一个问题即可检索相关信息,而无需了解文档中使用的任何特定关键词。 根据与字符串查询的相似度返回文档:
异步查询:
返回相似度分数:
根据与嵌入查询的相似度返回文档:
了解更多:

检索器

LangChain 的 VectorStore 对象并非 Runnable 的子类。LangChain 的 Retrievers 是 Runnable,因此它们实现了一组标准方法(如同步和异步的 invokebatch 操作)。虽然我们可以从向量存储构造检索器,但检索器也可以与其他非向量存储数据源(如外部 API)交互。 我们可以自己创建一个简单的版本,无需继承 Retriever。如果我们选择希望用于检索文档的方法,可以轻松创建一个可运行对象。下面我们将围绕 similarity_search 方法构建一个:
向量存储实现了 as_retriever 方法,用于生成一个检索器,即 VectorStoreRetriever。这些检索器包含特定的 search_typesearch_kwargs 属性,用于标识调用底层向量存储的哪些方法以及如何参数化它们。例如,我们可以用以下方式复制上述操作:
VectorStoreRetriever 支持的搜索类型包括 "similarity"(默认)、"mmr"(最大边际相关性,如上所述)和 "similarity_score_threshold"。我们可以使用后者通过相似度分数对检索器输出的文档设置阈值。 检索器可以轻松集成到更复杂的应用中,例如检索增强生成 (RAG) 应用,将给定问题与检索到的上下文结合形成 LLM 的提示。要了解更多关于构建此类应用的信息,请查看 RAG 教程

下一步

您现在已经了解了如何基于 PDF 文档构建语义搜索引擎。 关于文档加载器的更多信息: 关于嵌入模型的更多信息: 关于向量存储的更多信息: 关于 RAG 的更多信息,请参见: