LangChain 知识库教程
一句话
LangChain 提供了 embedding 和 vector store 抽象,用于构建基于语义搜索的检索增强生成(RAG)应用。
什么时候翻这页
当你需要构建一个能够从文档中检索相关信息的应用时,特别是当你需要实现检索增强生成(RAG)功能时。
核心概念
Documents
LangChain 实现了一个 Document 抽象,用于表示文本单元及其关联的元数据。它有三个属性:
page_content:表示内容的字符串metadata:包含任意元数据的字典id:(可选) 文档的字符串标识符
from langchain_core.documents import Document
documents = [
Document(
page_content="Dogs are great companions, known for their loyalty and friendliness.",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="Cats are independent pets that often enjoy their own space.",
metadata={"source": "mammal-pets-doc"},
),
]
Embeddings
向量搜索是存储和搜索非结构化数据(如非结构化文本)的常用方法。其思想是与文本关联的存储数字向量。给定查询,我们可以将其嵌入为相同维度的向量,并使用向量相似度度量(如余弦相似度)来识别相关文本。
LangChain 支持来自数十个提供商的 embeddings。这些模型指定了如何将文本转换为数字向量。以下是几种常用的 embedding 模型:
- OpenAI:
OpenAIEmbeddings(model="text-embedding-3-large") - Google Gemini:
GoogleGenerativeAIEmbeddings(model="models/gemini-embedding-001") - HuggingFace:
HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
Vector stores
LangChain VectorStore 对象包含将文本和 Document 对象添加到存储中的方法,以及使用各种相似度度量进行查询的方法。它们通常使用 embedding 模型初始化,这些模型确定文本数据如何转换为数字向量。
LangChain 包含与不同 vector store 技术的集成。一些 vector store 由提供商托管,需要特定凭据才能使用;一些可以在单独的基础设施中运行,可以在本地或通过第三方运行;其他可以在内存中运行以用于轻量级工作负载。
以下是几种常用的 vector store 实现:
- Chroma:
Chroma(collection_name="example_collection", embedding_function=embeddings) - InMemory:
InMemoryVectorStore(embeddings) - Pinecone:
PineconeVectorStore(embedding=embeddings, index=index)
Text splitters
文本分割器用于将大文档分割成较小的块,以便更好地检索和下游问答。RecursiveCharacterTextSplitter 是推荐用于通用文本用例的文本分割器。
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)
Retrievers
LangChain VectorStore 对象不继承 Runnable。LangChain Retrievers 是 Runnables,因此它们实现了一套标准方法(例如,同步和异步的 invoke 和 batch 操作)。虽然我们可以从 vector stores 构建检索器,但检索器也可以与非 vector store 数据源(如外部 API)接口。
retriever = vector_store.as_retriever(
search_type="similarity",
search_kwargs={"k": 1},
)
怎么做
1. 安装必要的包
pip install pypdf
2. 设置 LangSmith
export LANGSMITH_TRACING="true"
export LANGSMITH_API_KEY="..."
3. 加载和分割文档
import pypdf
from langchain_core.documents import Document
def load_pdf_pages(file_path: str) -> list[Document]:
reader = pypdf.PdfReader(file_path)
return [
Document(
page_content=page.extract_text() or "",
metadata={"source": file_path, "page": i},
)
for i, page in enumerate(reader.pages)
]
file_path = "../example_data/nke-10k-2023.pdf"
docs = load_pdf_pages(file_path)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)
4. 创建 embedding 模型
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
5. 创建 vector store
from langchain_chroma import Chroma
vector_store = Chroma(
collection_name="example_collection",
embedding_function=embeddings,
persist_directory="./chroma_langchain_db",
)
6. 添加文档到 vector store
ids = vector_store.add_documents(documents=all_splits)
7. 查询 vector store
# 基于字符串查询的相似性搜索
results = vector_store.similarity_search(
"How many distribution centers does Nike have in the US?"
)
# 带分数的相似性搜索
results = vector_store.similarity_search_with_score("What was Nike's revenue in 2023?")
doc, score = results[0]
# 基于向量的相似性搜索
embedding = embeddings.embed_query("How were Nike's margins impacted in 2023?")
results = vector_store.similarity_search_by_vector(embedding)
8. 创建检索器
retriever = vector_store.as_retriever(
search_type="similarity",
search_kwargs={"k": 1},
)
# 使用检索器
retriever.batch([
"How many distribution centers does Nike have in the US?",
"When was Nike incorporated?",
])
命令 / API 速查
Document 创建
from langchain_core.documents import Document
document = Document(
page_content="内容文本",
metadata={"source": "文档来源"},
id="文档ID"
)
Embeddings 初始化
# OpenAI
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
# Google Gemini
from langchain_google_genai import GoogleGenerativeAIEmbeddings
embeddings = GoogleGenerativeAIEmbeddings(model="models/gemini-embedding-001")
# HuggingFace
from langchain_huggingface import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-mpnet-base-v2",
encode_kwargs={"normalize_embeddings": True},
)
Vector Store 初始化
# Chroma
from langchain_chroma import Chroma
vector_store = Chroma(
collection_name="example_collection",
embedding_function=embeddings,
persist_directory="./chroma_langchain_db",
)
# InMemory
from langchain_core.vectorstores import InMemoryVectorStore
vector_store = InMemoryVectorStore(embeddings)
文本分割
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
add_start_index=True
)
splits = text_splitter.split_documents(docs)
Vector Store 查询
# 相似性搜索
results = vector_store.similarity_search("查询文本")
# 带分数的相似性搜索
results = vector_store.similarity_search_with_score("查询文本")
# 基于向量的相似性搜索
embedding = embeddings.embed_query("查询文本")
results = vector_store.similarity_search_by_vector(embedding)
检索器创建
retriever = vector_store.as_retriever(
search_type="similarity",
search_kwargs={"k": 1}
)
与 Hello-Agents / LangGraph / 本博客 handbook 索引的联系
本教程中的 Chroma vector store 实现与本博客 handbook 中使用的 Chroma 索引直接相关。在 handbook 中,我们使用相同的 Chroma 库来创建和管理向量存储,用于存储和检索文档嵌入。这种一致性使得我们可以轻松地将本教程中的概念应用到实际项目中。
在 LangGraph 中,检索器可以作为节点使用,从知识库中获取相关信息,然后传递给 LLM 进行处理。这与本教程中介绍的检索器概念一致,但增加了工作流管理的复杂性。
初学者易错点
-
chunk_size 和 chunk_overlap 设置不当:chunk_size 太小会导致上下文不足,太大则可能包含不相关信息。chunk_overlap 太小可能导致信息丢失,太大则增加计算负担。
-
忽略元数据:Document 对象中的 metadata 字段对于追踪文档来源和上下文非常重要,不应忽略。
-
embedding 模型选择不当:不同的 embedding 模型有不同的特点和适用场景,应根据具体需求选择合适的模型。
-
Vector Store 持久化:在使用 Chroma 等需要持久化的 vector store 时,需要正确配置 persist_directory 参数,否则数据可能会丢失。
-
检索器参数设置:search_kwargs 中的 k 值设置不当可能导致检索结果过多或过少,应根据应用场景调整。