LangChain 向量数据库详解

本文介绍如何使用 FAISS 向量数据库存储文档向量,并实现语义检索功能。

1. 什么是向量数据库?

1.1 海马体的比喻

人类大脑中,海马体负责存储和检索记忆。向量数据库就像是 AI 的"海马体",专门用于存储和检索嵌入向量。

传统数据库: 存储结构化数据(表格、文本)
向量数据库: 存储嵌入向量,支持语义相似度搜索

1.2 核心功能

功能 说明
存储向量 将文本的嵌入向量持久化存储
相似度搜索 根据向量相似度返回最相关的文档
实时检索 将用户查询转换为向量,匹配最相似结果

2. 什么是 FAISS?

2.1 FAISS 简介

FAISS(Facebook AI Similarity Search)是 Facebook 开发的开源向量检索库:

特点 说明
高性能 亿级向量秒级检索
多种索引 支持 IVF、HNSW 等多种索引算法
易用 纯 Python 接口,与 LangChain 无缝集成
内存优化 支持量化压缩,减少内存占用

2.2 其他向量数据库对比

数据库 特点
FAISS Facebook 开源,适合本地小规模场景
Chroma 轻量级,适合快速原型开发
Milvus 企业级,支持分布式部署
Pinecone 云服务,无需自建
Weaviate 支持混合搜索(向量+关键词)

3. 代码解析

3.1 完整代码

from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import FAISS
from langchain_openai.embeddings import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 1. 加载文档
loader = TextLoader("./demo.txt", encoding="utf-8")
docs = loader.load()

# 2. 文本分块
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=40,
    separators=["\n\n", "\n", "。", "!", "?", ",", "、", ""]
)
texts = text_splitter.split_documents(docs)

# 3. 初始化嵌入模型
embeddings_model = OpenAIEmbeddings(
    model="text-embedding-3-large",
    openai_api_key="sk-xxxx",
    openai_api_base="https://api.xxx.com/v1"
)

# 4. 构建向量数据库
db = FAISS.from_documents(texts, embeddings_model)

# 5. 创建检索器
retriever = db.as_retriever()

3.2 向量数据库创建

db = FAISS.from_documents(documents, embedding_model)
参数 说明
documents Document 对象列表(分块后的文本)
embedding_model 嵌入模型(必须与检索时一致)

4. 检索功能

4.1 创建检索器

retriever = db.as_retriever()

4.2 执行检索

# 语义检索:用户提问,系统返回最相关的文档块
retrieved_docs = retriever.invoke("卢浮宫这个名字怎么来的?")

# 查看检索结果
print(retrieved_docs[0].page_content)

4.3 检索流程示意

用户问题: "卢浮宫这个名字怎么来的?"
    ↓
转换为向量 [0.123, -0.456, ...]
    ↓
在 FAISS 中搜索最相似的文档块
    ↓
返回 top-k 相关文档

5. 完整 RAG 流程

from langchain_openai import ChatOpenAI

# 1. 加载并分块文档
loader = TextLoader("./demo.txt", encoding="utf-8")
docs = loader.load()
texts = text_splitter.split_documents(docs)

# 2. 构建向量数据库
db = FAISS.from_documents(texts, embeddings_model)
retriever = db.as_retriever()

# 3. 用户提问
query = "卢浮宫这个名字怎么来的?"

# 4. 检索相关文档
retrieved_docs = retriever.invoke(query)

# 5. 构建提示词(将检索结果注入上下文)
context = "\n".join([doc.page_content for doc in retrieved_docs])
prompt = f"根据以下内容回答问题:\n\n{context}\n\n问题:{query}"

# 6. 调用 LLM 生成答案
llm = ChatOpenAI(model="gpt-4", api_key="sk-xxxx", base_url="https://api.xxx.com/v1")
answer = llm.invoke(prompt)
print(answer)

结果:
在这里插入图片描述


6. FAISS 高级用法

6.1 指定返回数量

retriever = db.as_retriever(search_kwargs={"k": 3})  # 返回3条
retrieved_docs = retriever.invoke("卢浮宫在哪里?")

6.2 相似度阈值过滤

# 只返回相似度 > 0.8 的结果
retriever = db.as_retriever(
    search_type="similarity_score_threshold",
    search_kwargs={"score_threshold": 0.8}
)

6.3 混合搜索(MMR)

# Maximum Marginal Relevance - 兼顾相关性和多样性
retriever = db.as_retriever(
    search_type="mmr",
    search_kwargs={"k": 3, "fetch_k": 10}
)

6.4 保存和加载

# 保存到本地
db.save_local("faiss_index")

# 加载
db = FAISS.load_local("faiss_index", embeddings_model)

7. 常见问题

Q1: FAISS 和 Chroma 哪个好?

场景 推荐
本地快速原型 Chroma
亿级大数据 FAISS
云服务 Pinecone/Milvus

Q2: 检索结果不准确怎么办?

  • 调整 chunk_size:尝试 300-1000 范围
  • 调整检索数量 k:更多候选但可能引入噪声
  • 检查嵌入模型是否匹配

Q3: 如何提升检索速度?

  • 使用 HNSW 索引(适合小规模数据)
  • 启用量化压缩(适合大规模数据)
  • 控制向量维度(用 dimensions 参数压缩)

Q4: 向量数据库需要持久化吗?

建议持久化,避免每次重启重新构建:

db.save_local("my_faiss_index")
db = FAISS.load_local("my_faiss_index", embeddings_model)
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐