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