Documentation Index Fetch the complete documentation index at: https://nvd-54.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
本教程将帮助您熟悉 LangChain 的文档加载器 、向量嵌入 和向量存储 抽象。这些抽象旨在支持从(向量)数据库和其他来源检索数据,以便与大语言模型(LLM)工作流集成。它们对于在模型推理过程中获取数据进行推理的应用非常重要,例如检索增强生成(RAG )。
在这里,我们将在 PDF 文档上构建一个搜索引擎。这将允许我们检索 PDF 中与输入查询相似的段落。本指南还包含基于搜索引擎的最小 RAG 实现。
本指南重点介绍文本数据的检索。我们将涵盖以下概念:
本指南需要 @langchain/community 和 pdf-parse:
npm i @langchain/community pdf-parse
有关更多详情,请参阅我们的安装指南 。
LangSmith
使用 LangChain 构建的许多应用将包含多个步骤和多次大语言模型(LLM)调用。随着这些应用变得越来越复杂,能够检查链或智能体内部到底发生了什么变得至关重要。最好的方法是使用 LangSmith 。
在上面的链接注册后,确保设置环境变量以开始记录追踪:
export LANGSMITH_TRACING = "true"
export LANGSMITH_API_KEY = "..."
1. 文档和文档加载器
LangChain 实现了 Document 抽象,用于表示一个文本单元及其关联的元数据。它有三个属性:
pageContent:表示内容的字符串;
metadata:包含任意元数据的字典;
id:(可选)文档的字符串标识符。
metadata 属性可以捕获关于文档来源、与其他文档关系以及其他信息。请注意,单个 Document 对象通常代表较大文档的一个片段。
我们可以根据需要生成示例文档:
import { Document } from "@langchain/core/documents" ;
const documents = [
new Document ( {
pageContent :
"Dogs are great companions, known for their loyalty and friendliness." ,
metadata : { source : "mammal-pets-doc" },
} ) ,
new Document ( {
pageContent : "Cats are independent pets that often enjoy their own space." ,
metadata : { source : "mammal-pets-doc" },
} ) ,
] ;
然而,LangChain 生态系统实现了文档加载器 ,可以与数百个常见数据源集成。这使得将这些来源的数据整合到您的 AI 应用中变得容易。
加载文档
让我们将 PDF 加载为一系列 Document 对象。这是一个示例 PDF —— Nike 2023 年的 10-K 年报文件。我们可以查阅 LangChain 文档了解可用的 PDF 文档加载器 。
import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf" ;
const loader = new PDFLoader ( "../../data/nke-10k-2023.pdf" ) ;
const docs = await loader . load () ;
console . log (docs . length) ;
PDFLoader 为每个 PDF 页面加载一个 Document 对象。对于每个文档,我们可以轻松访问:
console . log (docs[ 0 ] . pageContent . slice ( 0 , 200 )) ;
Table of Contents
UNITED STATES
SECURITIES AND EXCHANGE COMMISSION
Washington, D.C. 20549
FORM 10-K
(Mark One)
☑ ANNUAL REPORT PURSUANT TO SECTION 13 OR 15(D) OF THE SECURITIES EXCHANGE ACT OF 1934
FO
console . log (docs[ 0 ] . metadata) ;
{
source : '../../data/nke-10k-2023.pdf' ,
pdf : {
version : '1.10.100' ,
info : {
PDFFormatVersion : '1.4' ,
IsAcroFormPresent : false ,
IsXFAPresent : false ,
Title : '0000320187-23-000039' ,
Author : 'EDGAR Online, a division of Donnelley Financial Solutions' ,
Subject : 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31' ,
Keywords : '0000320187-23-000039; ; 10-K' ,
Creator : 'EDGAR Filing HTML Converter' ,
Producer : 'EDGRpdf Service w/ EO.Pdf 22.0.40.0' ,
CreationDate : "D:20230720162200-04'00'" ,
ModDate : "D:20230720162208-04'00'"
},
metadata : null ,
totalPages : 107
},
loc : { pageNumber : 1 }
}
无论是出于信息检索还是下游问答目的,页面可能是一个过于粗粒度的表示。我们最终的目标是检索能够回答输入查询的 Document 对象,进一步分割 PDF 将有助于确保文档相关部分的含义不会被周围文本”冲淡”。
我们可以使用文本分割器 来实现此目的。这里我们将使用一个基于字符进行分区的简单文本分割器。我们将文档分割成 1000 个字符的块,块之间有 200 个字符的重叠。重叠有助于减少将一个语句与相关重要上下文分开的可能性。我们使用 RecursiveCharacterTextSplitter,它会使用常见分隔符(如换行符)递归地分割文档,直到每个块达到适当大小。这是通用文本用例推荐的文本分割器。
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters" ;
const textSplitter = new RecursiveCharacterTextSplitter ( {
chunkSize : 1000 ,
chunkOverlap : 200 ,
} ) ;
const allSplits = await textSplitter . splitDocuments (docs) ;
console . log (allSplits . length) ;
2. 向量嵌入
向量搜索是存储和搜索非结构化数据(如非结构化文本)的常用方法。其思想是存储与文本关联的数值向量。给定一个查询,我们可以将其嵌入 为相同维度的向量,并使用向量相似性度量(如余弦相似度)来识别相关文本。
LangChain 支持来自数十个提供商 的向量嵌入。这些模型指定了如何将文本转换为数值向量。让我们选择一个模型:
OpenAI
Azure
AWS
VertexAI
MistralAI
Cohere
import { OpenAIEmbeddings } from "@langchain/openai" ;
const embeddings = new OpenAIEmbeddings ( {
model : "text-embedding-3-large"
} ) ;
AZURE_OPENAI_API_INSTANCE_NAME =< YOUR_INSTANCE_NAME >
AZURE_OPENAI_API_KEY =< YOUR_KEY >
AZURE_OPENAI_API_VERSION = "2024-02-01"
import { AzureOpenAIEmbeddings } from "@langchain/openai" ;
const embeddings = new AzureOpenAIEmbeddings ( {
azureOpenAIApiEmbeddingsDeploymentName : "text-embedding-ada-002"
} ) ;
BEDROCK_AWS_REGION = your-region
import { BedrockEmbeddings } from "@langchain/aws" ;
const embeddings = new BedrockEmbeddings ( {
model : "amazon.titan-embed-text-v1"
} ) ;
npm i @langchain/google-vertexai
GOOGLE_APPLICATION_CREDENTIALS = credentials.json
import { VertexAIEmbeddings } from "@langchain/google-vertexai" ;
const embeddings = new VertexAIEmbeddings ( {
model : "gemini-embedding-001"
} ) ;
npm i @langchain/mistralai
MISTRAL_API_KEY = your-api-key
import { MistralAIEmbeddings } from "@langchain/mistralai" ;
const embeddings = new MistralAIEmbeddings ( {
model : "mistral-embed"
} ) ;
COHERE_API_KEY = your-api-key
import { CohereEmbeddings } from "@langchain/cohere" ;
const embeddings = new CohereEmbeddings ( {
model : "embed-english-v3.0"
} ) ;
const vector1 = await embeddings . embedQuery (allSplits[ 0 ] . pageContent) ;
const vector2 = await embeddings . embedQuery (allSplits[ 1 ] . pageContent) ;
assert vector1 . length === vector2 . length ;
console . log ( `Generated vectors of length ${ vector1 . length } \n ` ) ;
console . log (vector1 . slice ( 0 , 10 )) ;
Generated vectors of length 1536
[-0.008586574345827103, -0.03341241180896759, -0.008936782367527485, -0.0036674530711025, 0.010564599186182022, 0.009598285891115665, -0.028587326407432556, -0.015824200585484505, 0.0030416189692914486, -0.012899317778646946]
有了生成文本向量嵌入的模型,我们接下来可以将它们存储在支持高效相似性搜索的特殊数据结构中。
3. 向量存储
LangChain VectorStore 对象包含向存储中添加文本和 Document 对象的方法,以及使用各种相似性度量进行查询的方法。它们通常使用向量嵌入 模型初始化,该模型决定了如何将文本数据转换为数值向量。
LangChain 包含一套与不同向量存储技术的集成 。一些向量存储由提供商托管(例如各种云提供商),需要特定的凭据才能使用;一些(如 Postgres )在可以本地运行或通过第三方运行的单独基础设施中运行;其他的可以在内存中运行以处理轻量级工作负载。让我们选择一个向量存储:
Memory
Chroma
FAISS
MongoDB
PGVector
Pinecone
Qdrant
Redis
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory" ;
const vectorStore = new MemoryVectorStore (embeddings) ;
npm i @langchain/community
import { Chroma } from "@langchain/community/vectorstores/chroma" ;
const vectorStore = new Chroma (embeddings , {
collectionName : "a-test-collection" ,
} ) ;
npm i @langchain/community
import { FaissStore } from "@langchain/community/vectorstores/faiss" ;
const vectorStore = new FaissStore (embeddings , {} ) ;
import { MongoDBAtlasVectorSearch } from "@langchain/mongodb"
import { MongoClient } from "mongodb" ;
const client = new MongoClient (process . env . MONGODB_ATLAS_URI || "" ) ;
const collection = client
. db (process . env . MONGODB_ATLAS_DB_NAME )
. collection (process . env . MONGODB_ATLAS_COLLECTION_NAME ) ;
const vectorStore = new MongoDBAtlasVectorSearch (embeddings , {
collection : collection ,
indexName : "vector_index" ,
textKey : "text" ,
embeddingKey : "embedding" ,
} ) ;
npm i @langchain/community
import { PGVectorStore } from "@langchain/community/vectorstores/pgvector" ;
const vectorStore = await PGVectorStore . initialize (embeddings , {} )
npm i @langchain/pinecone
import { PineconeStore } from "@langchain/pinecone" ;
import { Pinecone as PineconeClient } from "@pinecone-database/pinecone" ;
const pinecone = new PineconeClient ( {
apiKey : process . env . PINECONE_API_KEY ,
} ) ;
const pineconeIndex = pinecone . Index ( "your-index-name" ) ;
const vectorStore = new PineconeStore (embeddings , {
pineconeIndex ,
maxConcurrency : 5 ,
} ) ;
import { QdrantVectorStore } from "@langchain/qdrant" ;
const vectorStore = await QdrantVectorStore . fromExistingCollection (embeddings , {
url : process . env . QDRANT_URL ,
collectionName : "langchainjs-testing" ,
} ) ;
import { RedisVectorStore } from "@langchain/redis" ;
const vectorStore = new RedisVectorStore (embeddings , {
redisClient : client ,
indexName : "langchainjs-testing" ,
} ) ;
实例化向量存储后,我们现在可以索引文档。
await vectorStore . addDocuments (allSplits) ;
请注意,大多数向量存储实现都允许您连接到现有的向量存储——例如通过提供客户端、索引名称或其他信息。有关特定集成 的更多详情,请参阅文档。
一旦我们实例化了包含文档的 VectorStore ,我们就可以查询它。VectorStore 包含以下查询方法:
同步和异步查询;
通过字符串查询和通过向量查询;
带和不带返回相似性分数;
通过相似性和最大边际相关性 (平衡查询相似性和检索结果多样性)。
这些方法通常在输出中包含 Document 对象列表。
用法
向量嵌入通常将文本表示为”密集”向量,使得含义相似的文本在几何上接近。这让我们只需传入问题就能检索相关信息,无需了解文档中使用的任何特定关键词。
根据与字符串查询的相似性返回文档:
const results1 = await vectorStore . similaritySearch (
"When was Nike incorporated?"
) ;
console . log (results1[ 0 ]) ;
Document {
pageContent : 'direct to consumer operations sell products...' ,
metadata : { 'page' : 4 , 'source' : '../example_data/nke-10k-2023.pdf' , 'start_index' : 3125 }
}
返回分数:
const results2 = await vectorStore . similaritySearchWithScore (
"What was Nike's revenue in 2023?"
) ;
console . log (results2[ 0 ]) ;
Score : 0.23699893057346344
Document {
pageContent : 'Table of Contents...' ,
metadata : { 'page' : 35 , 'source' : '../example_data/nke-10k-2023.pdf' , 'start_index' : 0 }
}
根据与嵌入查询的相似性返回文档:
const embedding = await embeddings . embedQuery (
"How were Nike's margins impacted in 2023?"
) ;
const results3 = await vectorStore . similaritySearchVectorWithScore (
embedding ,
1
) ;
console . log (results3[ 0 ]) ;
Document {
pageContent : 'FISCAL 2023 COMPARED TO FISCAL 2022...' ,
metadata : {
'page' : 36 ,
'source' : '../example_data/nke-10k-2023.pdf' ,
'start_index' : 0
}
}
了解更多:
4. 检索器
LangChain VectorStore 对象不是 Runnable 的子类。LangChain 检索器 是 Runnable,因此它们实现了一组标准方法(例如同步和异步 invoke 和 batch 操作)。虽然我们可以从向量存储构造检索器,但检索器也可以与非向量存储数据源(如外部 API)接口。
向量存储实现了 as_retriever 方法,用于生成检索器,具体来说是 VectorStoreRetriever 。这些检索器包含特定的 search_type 和 search_kwargs 属性,用于标识要调用底层向量存储的哪些方法以及如何参数化它们。例如,我们可以用以下方式复现上述操作:
const retriever = vectorStore . asRetriever ( {
searchType : "mmr" ,
searchKwargs : {
fetchK : 1 ,
},
} ) ;
await retriever . batch ([
"When was Nike incorporated?" ,
"What was Nike's revenue in 2023?" ,
]) ;
[
[Document {
metadata : { 'page' : 4 , 'source' : '../example_data/nke-10k-2023.pdf' , 'start_index' : 3125 },
pageContent : 'direct to consumer operations sell products...' ,
} ] ,
[Document {
metadata : { 'page' : 3 , 'source' : '../example_data/nke-10k-2023.pdf' , 'start_index' : 0 },
pageContent : 'Table of Contents...' ,
} ] ,
]
检索器可以轻松地整合到更复杂的应用中,例如检索增强生成(RAG) 应用,它将给定的问题与检索到的上下文组合成大语言模型(LLM)的提示词。要了解更多关于构建此类应用的信息,请查看 RAG 教程 。
下一步
您现在已经了解了如何在 PDF 文档上构建语义搜索引擎。
关于文档加载器的更多信息:
关于向量嵌入的更多信息:
关于向量存储的更多信息:
关于 RAG 的更多信息,请参阅:
将这些文档连接到 Claude、VSCode 等工具,通过 MCP 获取实时答案。