LangChain 1.3 完全教程:从入门到精通-Part 8: Vector Stores(向量存储)

文章目录

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. 检索优化建议

=========================================="""

  1. Chunk 大小: 500-1000 字符是大多数场景的最佳起点
  2. Chunk 重叠: 设置为 chunk_size 的 10-20%
  3. 搜索类型: 默认用 similarity,需要多样性用 mmr
  4. 检索数量: k=4 是好的起点,RAG 场景通常 k=3-5
  5. 混合检索: BM25 + 向量检索的组合通常优于单一检索
  6. 重排序: 检索后使用 reranker 提高精度
相关推荐
坊钰2 小时前
【LangChain框架入门级】1
langchain
yumgpkpm3 小时前
华为HUAWEI昇腾910B下千问Qwen3.6-27B在的推理加速实践
sql·华为·langchain·json·ai编程·ai写作·gpu算力
lhxcc_fly4 小时前
5.LangChain--输出解析器
langchain·llm·输出解析器
SuniaWang5 小时前
《AgentX 专栏》07-全链路可观测:用OpenTelemetry+Jaeger让每次AI对话都可追踪可复盘
java·人工智能·spring·架构·langchain·opentelemetry·agenx
糖果店的幽灵5 小时前
LangChain 1.3 完全教程:从入门到精通-Part 9: RAG(检索增强生成)
人工智能·langchain
星浩AI19 小时前
项目实战:合同智能审批 · LangGraph + HITL 人机协同方案 [有源码]
后端·langchain·agent
兆。20 小时前
LangChain大模型服务集成指南:面向AI应用开发者
人工智能·langchain
wuhen_n1 天前
LangChain 核心:Chain 链式调用实现复杂 AI 任务
前端·langchain·ai编程