文章目录
-
- [Part 8: Vector Stores(向量存储)](#Part 8: Vector Stores(向量存储))
-
- [8.1 向量存储概念](#8.1 向量存储概念)
- [8.2 Chroma(本地开发首选)](#8.2 Chroma(本地开发首选))
- [8.3 FAISS(高性能)](#8.3 FAISS(高性能))
-
- 安装
- [所有方法 Demo](#所有方法 Demo)
- [8.4 其他向量存储](#8.4 其他向量存储)
- [8.5 Retriever 接口](#8.5 Retriever 接口)
-
- [as_retriever 方法](#as_retriever 方法)
- [search_type 详解](#search_type 详解)
- [search_kwargs 参数详解](#search_kwargs 参数详解)
- [8.6 高级检索技术](#8.6 高级检索技术)
- [8.7 向量存储最佳实践](#8.7 向量存储最佳实践)
- ==========================================
- [1. 嵌入模型选择](#1. 嵌入模型选择)
- =========================================="""
- ==========================================
- [2. 向量数据库选择指南](#2. 向量数据库选择指南)
- =========================================="""
- ==========================================
- [3. 检索优化建议](#3. 检索优化建议)
- =========================================="""
Part 8: Vector Stores(向量存储)
8.1 向量存储概念
什么是向量数据库
向量数据库(Vector Database)是一种专门用于存储和检索向量嵌入 (Vector Embeddings)的数据库。与传统数据库按精确值匹配不同,向量数据库通过语义相似度来查找数据。
通俗理解:想象你有一个巨大的图书馆,传统数据库只能按书名精确查找,而向量数据库能理解"这本书和那本书讲的内容差不多",即使它们的标题完全不同。
工作原理
渲染错误: Mermaid 渲染失败: Parse error on line 2: ... LR A原始文本 "机器学习是AI的子领域" --> B[ ----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'STR'
常见向量数据库对比表格
| 数据库 | 类型 | 安装难度 | 中文支持 | 持久化 | 适用场景 | 推荐指数 |
|---|---|---|---|---|---|---|
| Chroma | 本地/服务端 | 极简 | 好 | 内置 | 本地开发、原型验证 | ⭐⭐⭐⭐⭐ |
| FAISS | 本地库 | 简单 | 好 | 手动 | 高性能本地检索 | ⭐⭐⭐⭐⭐ |
| Pinecone | 云服务 | 需注册 | 好 | 云端 | 生产环境、大规模 | ⭐⭐⭐⭐ |
| Qdrant | 本地/服务端 | 中等 | 好 | 内置 | 生产环境、混合检索 | ⭐⭐⭐⭐ |
| Weaviate | 服务端 | 中等 | 好 | 内置 | 生产环境、语义搜索 | ⭐⭐⭐⭐ |
| Milvus | 分布式 | 复杂 | 好 | 内置 | 企业级、超大规模 | ⭐⭐⭐ |
8.2 Chroma(本地开发首选)
安装
bash
pip install langchain-chroma chromadb
所有方法详解
python
"""
Chroma 向量存储完整方法 Demo
安装: pip install langchain-chroma chromadb
"""
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
# ==========================================
# 0. 准备嵌入模型
# ==========================================
# 使用 OpenAI 嵌入模型
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small", # 嵌入模型名称
# openai_api_key="your-api-key", # 也可通过环境变量设置
)
# 也可以使用免费的嵌入模型(不需要 API Key)
# from langchain_huggingface import HuggingFaceEmbeddings
# embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
# ==========================================
# 1. from_documents ------ 从文档列表创建
# ==========================================
documents = [
Document(page_content="LangChain 是一个 LLM 应用开发框架", metadata={"source": "doc1"}),
Document(page_content="向量数据库用于存储和检索文本嵌入", metadata={"source": "doc2"}),
Document(page_content="RAG 技术结合了检索和生成", metadata={"source": "doc3"}),
Document(page_content="Python 是最流行的 AI 开发语言", metadata={"source": "doc4"}),
Document(page_content="深度学习使用神经网络处理数据", metadata={"source": "doc5"}),
]
vectorstore = Chroma.from_documents(
documents=documents, # Document 对象列表(必需)
embedding=embeddings, # 嵌入模型(必需)
persist_directory=None, # 持久化目录(None 表示内存模式)
collection_name="langchain_demo", # 集合名称(默认 "langchain")
collection_metadata=None, # 集合元数据
ids=None, # 自定义文档 ID 列表
)
print("Chroma 向量存储创建成功!")
# ==========================================
# 2. from_texts ------ 从文本列表创建
# ==========================================
texts = [
"机器学习是人工智能的核心技术",
"自然语言处理让计算机理解人类语言",
"计算机视觉使机器能够理解图像",
"强化学习通过奖励信号训练智能体",
]
vectorstore2 = Chroma.from_texts(
texts=texts, # 文本字符串列表(必需)
embedding=embeddings, # 嵌入模型(必需)
metadatas=[ # 每个文本对应的元数据(可选)
{"topic": "ML"},
{"topic": "NLP"},
{"topic": "CV"},
{"topic": "RL"},
],
ids=["ml", "nlp", "cv", "rl"], # 自定义 ID(可选)
persist_directory=None,
collection_name="ai_topics",
)
# ==========================================
# 3. add_documents ------ 添加文档
# ==========================================
new_docs = [
Document(page_content="Transformer 是现代 NLP 的基础架构", metadata={"source": "new1"}),
Document(page_content="GPT 系列模型展示了强大的语言能力", metadata={"source": "new2"}),
]
# 添加文档并获取生成的 ID
added_ids = vectorstore.add_documents(
documents=new_docs, # Document 对象列表(必需)
ids=["transformer", "gpt"], # 自定义 ID(可选,不指定则自动生成)
)
print(f"添加了 {len(added_ids)} 个文档,ID: {added_ids}")
# ==========================================
# 4. add_texts ------ 添加文本
# ==========================================
new_ids = vectorstore.add_texts(
texts=["BERT 模型用于文本分类", "扩散模型用于图像生成"],
metadatas=[{"topic": "NLP"}, {"topic": "CV"}],
ids=["bert", "diffusion"],
)
print(f"添加了 {len(new_ids)} 个文本")
# ==========================================
# 5. similarity_search ------ 相似度搜索
# ==========================================
results = vectorstore.similarity_search(
query="什么是人工智能?", # 查询文本(必需)
k=3, # 返回最相似的 k 个结果(默认 4)
filter=None, # 元数据过滤条件(可选)
# filter={"source": "doc1"} → 精确匹配
# filter={"topic": {"$in": ["ML", "NLP"]}} → 高级过滤
)
print(f"\n相似度搜索结果(k=3):")
for i, doc in enumerate(results):
print(f" {i+1}. [{doc.metadata.get('source', 'N/A')}] {doc.page_content}")
# ==========================================
# 6. similarity_search_with_score ------ 带分数的搜索
# ==========================================
results_with_scores = vectorstore.similarity_search_with_score(
query="深度学习和神经网络的关系",
k=5,
)
print(f"\n带分数的搜索结果:")
for doc, score in results_with_scores:
# Chroma 使用 L2 距离(越小越相似)
# 0 表示完全相同,值越大差异越大
print(f" [距离: {score:.4f}] {doc.page_content}")
# ==========================================
# 7. similarity_search_by_vector ------ 按向量搜索
# ==========================================
# 先将查询文本转为向量
query_vector = embeddings.embed_query("AI 技术")
results = vectorstore.similarity_search_by_vector(
embedding=query_vector, # 查询向量(必需)
k=3,
)
print(f"\n按向量搜索结果:")
for doc in results:
print(f" {doc.page_content}")
# ==========================================
# 8. delete ------ 删除文档
# ==========================================
vectorstore.delete(
ids=["transformer", "gpt"], # 要删除的文档 ID 列表
)
print("\n已删除指定文档")
# ==========================================
# 9. get ------ 获取文档
# ==========================================
# 通过 ID 获取文档
docs = vectorstore.get(
ids=["ml", "nlp"], # 文档 ID 列表
# where={"topic": "ML"}, # 按元数据过滤
# include=["documents", "metadatas", "embeddings"], # 返回字段
)
print(f"\n获取到的文档: {docs}")
# ==========================================
# 10. update ------ 更新文档
# ==========================================
vectorstore.update_document(
document_id="ml", # 要更新的文档 ID
document=Document( # 新的文档内容
page_content="机器学习是人工智能最重要的分支之一",
metadata={"source": "updated", "topic": "ML"}
),
)
# 批量更新
vectorstore.update_documents(
ids=["nlp", "cv"],
documents=[
Document(page_content="NLP 是自然语言处理的缩写", metadata={"topic": "NLP"}),
Document(page_content="CV 是计算机视觉的缩写", metadata={"topic": "CV"}),
],
)
持久化 Demo
python
"""
Chroma 持久化 Demo
"""
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# ==========================================
# 方式一:创建时指定持久化目录
# ==========================================
PERSIST_DIR = "/data/user/work/chroma_db"
# 第一次运行:创建并持久化
vectorstore = Chroma.from_documents(
documents=[
Document(page_content="持久化测试文档一", metadata={"id": 1}),
Document(page_content="持久化测试文档二", metadata={"id": 2}),
],
embedding=embeddings,
persist_directory=PERSIST_DIR, # 指定持久化目录
collection_name="my_collection",
)
print("向量存储已保存到磁盘")
# ==========================================
# 方式二:从持久化目录加载
# ==========================================
# 后续运行:直接从磁盘加载(无需重新嵌入)
vectorstore = Chroma(
persist_directory=PERSIST_DIR, # 持久化目录
embedding_function=embeddings, # 仍需提供嵌入模型
collection_name="my_collection", # 集合名称
)
# 直接进行搜索
results = vectorstore.similarity_search("测试", k=2)
for doc in results:
print(f" {doc.page_content}")
# ==========================================
# 方式三:使用 Chroma 客户端管理
# ==========================================
import chromadb
# 创建持久化客户端
client = chromadb.PersistentClient(path=PERSIST_DIR)
# 获取或创建集合
collection = client.get_or_create_collection(
name="my_collection",
metadata={"description": "测试集合"},
)
# 查看所有集合
collections = client.list_collections()
print(f"所有集合: {[c.name for c in collections]}")
# 删除集合(慎用!)
# client.delete_collection("my_collection")
8.3 FAISS(高性能)
安装
bash
pip install langchain-community faiss-cpu
# 如需 GPU 加速: pip install faiss-gpu
所有方法 Demo
python
"""
FAISS 向量存储完整方法 Demo
安装: pip install langchain-community faiss-cpu
"""
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# ==========================================
# 1. from_documents ------ 从文档创建
# ==========================================
documents = [
Document(page_content="FAISS 是 Facebook 开发的高效向量搜索库", metadata={"source": "doc1"}),
Document(page_content="它支持多种索引类型和距离度量", metadata={"source": "doc2"}),
Document(page_content="FAISS 适合大规模向量检索场景", metadata={"source": "doc3"}),
Document(page_content="它可以在 CPU 和 GPU 上运行", metadata={"source": "doc4"}),
]
vectorstore = FAISS.from_documents(
documents=documents, # Document 对象列表(必需)
embedding=embeddings, # 嵌入模型(必需)
# FAISS 特有参数:
# normalize_L2=False, # 是否对向量进行 L2 归一化
# index=None, # 自定义 FAISS 索引(高级用法)
)
print("FAISS 向量存储创建成功!")
# ==========================================
# 2. from_texts ------ 从文本创建
# ==========================================
texts = ["文本一", "文本二", "文本三"]
vectorstore = FAISS.from_texts(
texts=texts,
embedding=embeddings,
metadatas=[{"id": 1}, {"id": 2}, {"id": 3}],
)
# ==========================================
# 3. similarity_search ------ 相似度搜索
# ==========================================
results = vectorstore.similarity_search(
query="向量搜索", # 查询文本
k=2, # 返回数量
# filter=None, # FAISS 不直接支持元数据过滤
)
for doc in results:
print(f" {doc.page_content}")
# ==========================================
# 4. similarity_search_with_score ------ 带分数搜索
# ==========================================
# FAISS 默认使用 L2 距离(越小越相似)
results_scores = vectorstore.similarity_search_with_score(
query="高效搜索",
k=3,
)
for doc, score in results_scores:
print(f" [L2距离: {score:.4f}] {doc.page_content}")
# ==========================================
# 5. similarity_search_by_vector ------ 按向量搜索
# ==========================================
query_vector = embeddings.embed_query("搜索算法")
results = vectorstore.similarity_search_by_vector(
embedding=query_vector,
k=2,
)
# ==========================================
# 6. add_documents / add_texts ------ 添加数据
# ==========================================
vectorstore.add_documents([
Document(page_content="新增文档内容", metadata={"source": "new"}),
])
vectorstore.add_texts(
texts=["新增文本一", "新增文本二"],
metadatas=[{"source": "t1"}, {"source": "t2"}],
)
# ==========================================
# 7. save_local / load_local ------ 保存和加载
# ==========================================
SAVE_DIR = "/data/user/work/faiss_index"
# 保存到磁盘
vectorstore.save_local(
folder_path=SAVE_DIR, # 保存目录(必需)
index_name="index", # 索引文件名前缀(默认 "index")
)
print(f"FAISS 索引已保存到 {SAVE_DIR}")
# 从磁盘加载
loaded_store = FAISS.load_local(
folder_path=SAVE_DIR, # 保存目录(必需)
embeddings=embeddings, # 嵌入模型(必需)
index_name="index", # 索引文件名前缀
allow_dangerous_deserialization=True, # 允许反序列化(安全考虑)
)
# 加载后直接搜索
results = loaded_store.similarity_search("测试", k=2)
for doc in results:
print(f" {doc.page_content}")
# ==========================================
# 8. merge_from ------ 合并向量存储
# ==========================================
# 创建第二个向量存储
store2 = FAISS.from_texts(
texts=["合并文档一", "合并文档二"],
embedding=embeddings,
)
# 将 store2 合并到 vectorstore
vectorstore.merge_from(store2)
print(f"合并后文档总数: {vectorstore.index.ntotal}")
# ==========================================
# 9. FAISS 高级索引配置
# ==========================================
import faiss
# 创建自定义 FAISS 索引
dimension = 1536 # text-embedding-3-small 的维度
# IndexFlatIP: 内积索引(适合归一化后的向量)
index = faiss.IndexFlatIP(dimension)
# IndexFlatL2: L2 距离索引(默认)
# index = faiss.IndexFlatL2(dimension)
# IndexIVFFlat: 倒排索引(适合大规模数据)
# nlist = 100 # 聚类中心数
# quantizer = faiss.IndexFlatL2(dimension)
# index = faiss.IndexIVFFlat(quantizer, dimension, nlist)
# 使用自定义索引创建向量存储
custom_store = FAISS(
embedding_function=embeddings,
index=index,
docstore=vectorstore.docstore, # 复用文档存储
index_to_docstore_id=vectorstore.index_to_docstore_id,
)
8.4 其他向量存储
Pinecone(云端)
python
"""
Pinecone 向量存储 Demo
安装: pip install langchain-pinecone
"""
# Pinecone 是全托管的云端向量数据库,无需自己管理基础设施
# from langchain_pinecone import PineconeVectorStore
# from langchain_openai import OpenAIEmbeddings
# from pinecone import Pinecone
# # 初始化 Pinecone 客户端
# pc = Pinecone(api_key="your-api-key")
# embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# # 创建索引(在 Pinecone 控制台或通过 API)
# # pc.create_index(
# # name="my-index",
# # dimension=1536,
# # metric="cosine",
# # spec={"serverless": {"cloud": "aws", "region": "us-east-1"}}
# # )
# # 连接到已有索引
# vectorstore = PineconeVectorStore(
# index=pc.Index("my-index"),
# embedding=embeddings,
# )
# # 添加文档
# vectorstore.add_documents(documents)
# # 搜索
# results = vectorstore.similarity_search("查询文本", k=5)
# # 带过滤的搜索
# results = vectorstore.similarity_search(
# "查询文本",
# k=5,
# filter={"category": "tech"},
# )
Qdrant
python
"""
Qdrant 向量存储 Demo
安装: pip install langchain-qdrant qdrant-client
"""
# Qdrant 是高性能的向量搜索引擎,支持本地和服务器模式
# from langchain_qdrant import QdrantVectorStore
# from qdrant_client import QdrantClient
# from langchain_openai import OpenAIEmbeddings
# embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# # 方式一:内存模式(适合开发测试)
# client = QdrantClient(":memory:")
# # 方式二:本地持久化
# client = QdrantClient(path="/data/user/work/qdrant_data")
# # 方式三:连接远程服务器
# # client = QdrantClient(url="http://localhost:6333")
# # 创建向量存储
# vectorstore = QdrantVectorStore(
# client=client,
# collection_name="my_collection",
# embedding=embeddings,
# )
# # 添加文档
# vectorstore.add_documents(documents)
# # 搜索(支持丰富的过滤条件)
# results = vectorstore.similarity_search(
# "查询文本",
# k=5,
# filter={"must": [{"key": "metadata.field", "match": {"value": "xxx"}}]},
# )
Weaviate
python
"""
Weaviate 向量存储 Demo
安装: pip install langchain-weaviate weaviate-client
"""
# Weaviate 是支持多模态的向量数据库
# import weaviate
# from langchain_weaviate import WeaviateVectorStore
# from langchain_openai import OpenAIEmbeddings
# embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# # 连接本地 Weaviate 实例
# client = weaviate.connect_to_local()
# # 或连接 Weaviate 云服务
# # client = weaviate.connect_to_weaviate_cloud(
# # cluster_url="your-cluster-url",
# # auth_credentials=weaviate.auth.AuthApiKey("your-api-key"),
# # )
# vectorstore = WeaviateVectorStore.from_documents(
# documents=documents,
# embedding=embeddings,
# client=client,
# index_name="MyDocument",
# )
# results = vectorstore.similarity_search("查询", k=5)
8.5 Retriever 接口
Retriever(检索器)是 LangChain 中统一的检索接口。所有向量存储都可以通过 as_retriever() 方法转换为 Retriever 对象。
as_retriever 方法
python
"""
Retriever 接口 Demo
"""
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
documents = [
Document(page_content="Python 是一种通用编程语言", metadata={"topic": "编程"}),
Document(page_content="JavaScript 用于 Web 前端开发", metadata={"topic": "编程"}),
Document(page_content="机器学习是 AI 的核心领域", metadata={"topic": "AI"}),
Document(page_content="深度学习使用多层神经网络", metadata={"topic": "AI"}),
Document(page_content="自然语言处理处理人类语言", metadata={"topic": "AI"}),
Document(page_content="Docker 是一种容器化技术", metadata={"topic": "DevOps"}),
]
vectorstore = Chroma.from_documents(
documents=documents,
embedding=embeddings,
collection_name="retriever_demo",
)
# ==========================================
# as_retriever ------ 转换为 Retriever
# ==========================================
retriever = vectorstore.as_retriever(
search_type="similarity", # 搜索类型(默认)
search_kwargs={
"k": 3, # 返回结果数量
},
)
# Retriever 的核心方法是 invoke()
results = retriever.invoke("什么是人工智能")
print(f"检索到 {len(results)} 个结果:")
for doc in results:
print(f" [{doc.metadata.get('topic')}] {doc.page_content}")
search_type 详解
python
"""
三种搜索类型详解
"""
# ==========================================
# 1. similarity ------ 标准相似度搜索(默认)
# ==========================================
retriever_sim = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 3}, # 返回最相似的 k 个结果
)
results = retriever_sim.invoke("编程语言")
print("similarity 搜索结果:")
for doc in results:
print(f" {doc.page_content}")
# ==========================================
# 2. similarity_score_threshold ------ 带分数阈值的搜索
# ==========================================
retriever_threshold = vectorstore.as_retriever(
search_type="similarity_score_threshold",
search_kwargs={
"k": 5, # 最多返回 k 个
"score_threshold": 0.5, # 最低相似度阈值
# Chroma 使用 L2 距离,阈值越小越严格
# 注意: 不同向量数据库的分数含义不同
},
)
results = retriever_threshold.invoke("量子计算")
print(f"\nsimilarity_score_threshold 搜索结果: {len(results)} 个")
# ==========================================
# 3. mmr ------ 最大边际相关性搜索
# ==========================================
"""
MMR (Maximal Marginal Relevance) 在保证相关性的同时,
尽可能增加结果之间的多样性,避免返回内容高度重复的结果。
参数:
k: 最终返回的结果数量
fetch_k: 候选结果数量(先从数据库取 fetch_k 个,再从中选 k 个)
lambda_mult: 多样性权重
- 1.0: 只考虑相关性(等同于 similarity)
- 0.0: 只考虑多样性
- 0.5: 平衡相关性和多样性(推荐)
"""
retriever_mmr = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={
"k": 3, # 最终返回 3 个
"fetch_k": 10, # 先获取 10 个候选
"lambda_mult": 0.5, # 平衡相关性和多样性
},
)
results = retriever_mmr.invoke("人工智能技术")
print("\nmmr 搜索结果:")
for doc in results:
print(f" {doc.page_content}")
search_kwargs 参数详解
python
"""
search_kwargs 参数完整说明
"""
# 不同 search_type 支持的参数:
# --- similarity ---
search_kwargs_similarity = {
"k": 5, # 返回结果数量(默认 4)
"filter": {"topic": "AI"}, # 元数据过滤(仅部分数据库支持)
}
# --- similarity_score_threshold ---
search_kwargs_threshold = {
"k": 10, # 最大返回数量
"score_threshold": 0.7, # 最低相似度分数
"filter": {}, # 元数据过滤
}
# --- mmr ---
search_kwargs_mmr = {
"k": 3, # 最终返回数量
"fetch_k": 20, # 候选结果数量
"lambda_mult": 0.7, # 多样性权重 (0.0~1.0)
"filter": {}, # 元数据过滤
}
# 使用示例
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs=search_kwargs_mmr,
)
8.6 高级检索技术
MultiQueryRetriever(多查询检索)
通过让 LLM 生成多个查询变体,从不同角度检索相关文档,提高召回率。
python
"""
MultiQueryRetriever Demo
安装: pip install langchain-chroma
"""
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# 准备向量存储
documents = [
Document(page_content="LangChain 支持多种 LLM 提供商"),
Document(page_content="向量嵌入将文本转换为数值向量"),
Document(page_content="RAG 通过检索增强模型回答"),
Document(page_content="提示工程是优化 LLM 输出的关键技术"),
Document(page_content="Agent 能够自主决策和执行任务"),
]
vectorstore = Chroma.from_documents(documents, embeddings)
# 创建多查询检索器
retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(k=3), # 基础检索器
llm=llm, # 用于生成查询变体的 LLM
# prompt=custom_prompt, # 自定义提示(可选)
# include_original=True, # 是否包含原始查询(默认 True)
)
# 查询
query = "什么是 RAG?"
results = retriever.invoke(query)
print(f"多查询检索结果(共 {len(results)} 个):")
for doc in results:
print(f" {doc.page_content}")
# 查看生成的查询变体
# retriever.llm_chain 是内部使用的链
# 可以通过回调查看生成的查询
ContextualCompressionRetriever(上下文压缩)
对检索到的文档进行二次过滤和压缩,只保留与查询最相关的内容。
python
"""
ContextualCompressionRetriever Demo
"""
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank # 需要安装: pip install langchain-cohere
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# 准备包含冗余信息的文档
documents = [
Document(page_content="LangChain 是一个开源框架,由 Harrison Chase 创建。它提供了丰富的工具和组件。"),
Document(page_content="LangChain 支持多种编程语言,包括 Python 和 JavaScript。社区非常活跃。"),
Document(page_content="苹果是一种水果,富含维生素C。它有红色和绿色等品种。"),
Document(page_content="LangChain 的核心组件包括 Models、Prompts、Chains 和 Agents。"),
]
vectorstore = Chroma.from_documents(documents, embeddings)
# ==========================================
# 方式一:使用 LLM 作为压缩器
# ==========================================
from langchain_community.document_compressors import LLMChainExtractor
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor, # 压缩器
base_retriever=vectorstore.as_retriever(k=5), # 基础检索器
)
results = compression_retriever.invoke("LangChain 的核心组件是什么?")
print("LLM 压缩检索结果:")
for doc in results:
print(f" {doc.page_content}")
# ==========================================
# 方式二:使用 LLMChainFilter 过滤器
# ==========================================
from langchain_community.document_compressors import LLMChainFilter
# LLMChainFilter 只做过滤,不做压缩
# 返回原始文档或丢弃
filter_compressor = LLMChainFilter.from_llm(llm)
filter_retriever = ContextualCompressionRetriever(
base_compressor=filter_compressor,
base_retriever=vectorstore.as_retriever(k=5),
)
results = filter_retriever.invoke("LangChain 框架")
print("\n过滤检索结果:")
for doc in results:
print(f" {doc.page_content}")
# ==========================================
# 方式三:使用 EmbeddingsFilter 嵌入过滤
# ==========================================
from langchain_community.document_compressors import EmbeddingsFilter
embeddings_filter = EmbeddingsFilter(
embeddings=embeddings,
similarity_threshold=0.5, # 相似度阈值
)
embedding_retriever = ContextualCompressionRetriever(
base_compressor=embeddings_filter,
base_retriever=vectorstore.as_retriever(k=10),
)
EnsembleRetriever(集成检索)
结合多个检索器的结果,提高检索质量。
python
"""
EnsembleRetriever Demo
安装: pip install langchain rank_bm25
"""
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
documents = [
Document(page_content="Python 是一种高级编程语言"),
Document(page_content="Java 广泛用于企业级开发"),
Document(page_content="JavaScript 是 Web 开发的核心语言"),
Document(page_content="C++ 用于系统级编程和游戏开发"),
Document(page_content="Rust 是一种安全的系统编程语言"),
Document(page_content="Go 语言适合构建微服务"),
]
# ==========================================
# 检索器 1:BM25(关键词检索)
# ==========================================
bm25_retriever = BM25Retriever.from_documents(
documents=documents,
k=3, # 返回数量
)
# ==========================================
# 检索器 2:向量检索(语义检索)
# ==========================================
vectorstore = Chroma.from_documents(documents, embeddings)
vector_retriever = vectorstore.as_retriever(k=3)
# ==========================================
# 创建集成检索器
# ==========================================
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever], # 检索器列表
weights=[0.4, 0.6], # 各检索器的权重(总和为 1)
# BM25 权重 0.4 + 向量检索权重 0.6
# 如果更看重语义相似,可以提高向量检索权重
)
results = ensemble_retriever.invoke("Web 开发用什么语言?")
print(f"集成检索结果(共 {len(results)} 个):")
for doc in results:
print(f" {doc.page_content}")
ParentDocumentRetriever(父子文档)
使用小块进行精确检索,返回对应的大块以提供完整上下文。
python
"""
ParentDocumentRetriever Demo
"""
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# 准备长文档
long_text = """
第一章:人工智能概述
人工智能(AI)是计算机科学的一个分支,旨在创建能够模拟人类智能的系统。
AI 的发展经历了多次浪潮,从早期的专家系统到如今的深度学习。
第二章:机器学习基础
机器学习是 AI 的核心技术之一。它通过数据驱动的方式让计算机自动学习。
监督学习、无监督学习和强化学习是机器学习的三大范式。
第三章:深度学习
深度学习使用多层神经网络来学习数据的层次化表示。
卷积神经网络(CNN)在图像识别中表现优异。
循环神经网络(RNN)适合处理序列数据。
Transformer 架构是当前最重要的深度学习模型。
第四章:自然语言处理
自然语言处理(NLP)让计算机能够理解和生成人类语言。
BERT、GPT 等预训练模型极大地推动了 NLP 的发展。
大语言模型(LLM)展现了强大的语言理解和生成能力。
第五章:计算机视觉
计算机视觉使机器能够理解图像和视频内容。
目标检测、图像分割、人脸识别是 CV 的核心任务。
Vision Transformer 将 Transformer 引入了视觉领域。
"""
documents = [Document(page_content=long_text, metadata={"source": "ai_book"})]
# ==========================================
# 配置父子分割器
# ==========================================
# 子分割器:小块(用于检索)
child_splitter = RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=20,
separators=["\n\n", "\n", "。", " ", ""],
)
# 父分割器:大块(用于返回上下文)
# 这里不设置 parent_splitter,直接使用原始文档作为父文档
# 如果需要也可以设置:
# parent_splitter = RecursiveCharacterTextSplitter(chunk_size=1000)
# 文档存储(存储父文档)
docstore = InMemoryStore()
# 向量存储(存储子文档的向量)
vectorstore = Chroma(
embedding_function=embeddings,
collection_name="parent_child_demo",
)
# ==========================================
# 创建父子文档检索器
# ==========================================
retriever = ParentDocumentRetriever(
vectorstore=vectorstore, # 子文档的向量存储
docstore=docstore, # 父文档的存储
child_splitter=child_splitter, # 子文档分割器
# parent_splitter=None, # 父文档分割器(可选)
id_key=None, # ID 键名
)
# 添加文档
retriever.add_documents(documents)
# 检索 ------ 返回的是父文档(完整上下文)
results = retriever.invoke("Transformer 架构")
print(f"父子文档检索结果:")
for doc in results:
print(f" 长度: {len(doc.page_content)} 字符")
print(f" 内容: {doc.page_content[:150]}...")
print()
SelfQueryRetriever(自查询)
让 LLM 自动将用户的自然语言查询转换为结构化查询(包含语义搜索和元数据过滤)。
python
"""
SelfQueryRetriever Demo
"""
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
from langchain_core.documents import Document
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# 准备带丰富元数据的文档
documents = [
Document(
page_content="LangChain 是一个强大的 LLM 应用框架",
metadata={"type": "框架", "language": "Python", "difficulty": "中级"}
),
Document(
page_content="PyTorch 是一个深度学习框架",
metadata={"type": "框架", "language": "Python", "difficulty": "高级"}
),
Document(
page_content="React 是一个前端 UI 框架",
metadata={"type": "框架", "language": "JavaScript", "difficulty": "中级"}
),
Document(
page_content="Django 是一个 Python Web 框架",
metadata={"type": "框架", "language": "Python", "difficulty": "初级"}
),
Document(
page_content="TensorFlow 是 Google 的机器学习框架",
metadata={"type": "框架", "language": "Python", "difficulty": "高级"}
),
]
vectorstore = Chroma.from_documents(documents, embeddings)
# 定义元数据字段信息
metadata_field_info = [
AttributeInfo(
name="type",
description="技术类型,如:框架、库、工具",
type="string",
),
AttributeInfo(
name="language",
description="编程语言,如:Python、JavaScript",
type="string",
),
AttributeInfo(
name="difficulty",
description="学习难度,如:初级、中级、高级",
type="string",
),
]
# 创建自查询检索器
retriever = SelfQueryRetriever.from_llm(
llm=llm,
vectorstore=vectorstore,
document_contents="各种技术框架的介绍", # 文档内容的简要描述
metadata_field_info=metadata_field_info, # 元数据字段信息
enable_limit=True, # 是否允许 LLM 限制结果数量
verbose=True, # 打印查询转换过程
)
# 查询示例
# LLM 会自动解析出语义查询和元数据过滤条件
query1 = "推荐一些 Python 的框架"
results = retriever.invoke(query1)
print(f"\n查询: '{query1}'")
for doc in results:
print(f" [{doc.metadata}] {doc.page_content}")
query2 = "哪些框架适合初学者?"
results = retriever.invoke(query2)
print(f"\n查询: '{query2}'")
for doc in results:
print(f" [{doc.metadata}] {doc.page_content}")
每种技术的适用场景
| 技术 | 核心优势 | 适用场景 | 额外成本 |
|---|---|---|---|
| MultiQueryRetriever | 多角度检索,提高召回率 | 查询表述模糊、需要高召回 | 多次 LLM 调用 |
| ContextualCompressionRetriever | 过滤无关内容,提高精度 | 文档冗余多、需要精确答案 | 额外 LLM 调用 |
| EnsembleRetriever | 结合关键词+语义检索 | 需要同时匹配关键词和语义 | 多个检索器维护 |
| ParentDocumentRetriever | 精确检索+完整上下文 | 长文档、需要保持上下文完整性 | 额外存储空间 |
| SelfQueryRetriever | 自然语言转结构化查询 | 元数据丰富、用户查询包含过滤条件 | LLM 调用解析查询 |
8.7 向量存储最佳实践
向量存储最佳实践总结
==========================================
1. 嵌入模型选择
=========================================="""
| 场景 | 推荐嵌入模型 | 维度 | 成本 |
|---|---|---|---|
| 通用(英文) | text-embedding-3-small | 1536 | 低 |
| 通用(英文高质量) | text-embedding-3-large | 3072 | 中 |
| 中文 | text-embedding-3-small | 1536 | 低 |
| 多语言 | text-embedding-3-large | 3072 | 中 |
| 本地免费 | all-MiniLM-L6-v2 | 384 | 免费 |
| 本地中文 | bge-large-zh-v1.5 | 1024 | 免费 |
==========================================
2. 向量数据库选择指南
=========================================="""
| 阶段 | 推荐数据库 | 理由 |
|---|---|---|
| 原型开发 | Chroma | 安装简单,API 友好 |
| 本地高性能 | FAISS | 速度极快,Facebook 出品 |
| 小规模生产 | Chroma / Qdrant | 支持持久化和过滤 |
| 中大规模生产 | Qdrant / Weaviate | 功能丰富,性能好 |
| 超大规模 | Pinecone / Milvus | 云端托管 / 分布式 |
| """ |
==========================================
3. 检索优化建议
=========================================="""
- Chunk 大小: 500-1000 字符是大多数场景的最佳起点
- Chunk 重叠: 设置为 chunk_size 的 10-20%
- 搜索类型: 默认用 similarity,需要多样性用 mmr
- 检索数量: k=4 是好的起点,RAG 场景通常 k=3-5
- 混合检索: BM25 + 向量检索的组合通常优于单一检索
- 重排序: 检索后使用 reranker 提高精度