RAG 系列(六):向量数据库——存储与检索的基础设施

为什么需要专门的向量数据库?

前面五篇文章,我们搞清楚了怎么切分文档、怎么生成 Embedding。现在这些向量存在哪里?怎么被高效地检索出来?

你可能会想:"用 Redis 或者 PostgreSQL 存向量不行吗?"

不行 ------传统数据库是为精确查询设计的(比如 WHERE id = 123),而向量检索是近似最近邻搜索(ANN):给定一个查询向量,在几亿个文档向量中快速找出最相似的 Top-K 个。传统数据库的索引(B+树、哈希表)对这种"相似性查询"无能为力。

举个例子:

  • 传统查询:查找 id=42 的用户 → O(1) 或 O(log n)
  • 向量查询:查找和用户 A 兴趣最相似的 10 个人 → 需要比较全库向量,O(n) 暴力搜索太慢了

向量数据库通过专门的 ANN 索引(HNSW、IVF 等),把 O(n) 降到 O(log n),在毫秒级完成亿级向量的相似性检索。


向量数据库的三大核心能力

1. 向量存储

存储海量向量(百万到十亿级别),每个向量附带原始文本和元数据。支持增量写入和删除。

2. ANN 近似最近邻检索

核心算法:

算法 原理 优点 缺点
HNSW 分层导航小世界图,构建多层图结构,从粗到细搜索 速度快、精度高、支持动态增删 内存占用较大
IVF Inverted File,把向量空间分成多个聚类,先找最近聚类再搜索 内存友好、适合静态数据 增删向量需要重建索引
Flat 暴力全量比较 100% 精确 极慢,仅适合小数据量

选型建议:开发阶段用 Flat(简单),生产环境用 HNSW(性能最好)。

3. 元数据过滤(Metadata Filter)

这是向量数据库区别于纯向量检索库(如 FAISS)的关键能力。你可以同时做两件事:

  • 用向量相似度找语义相关的内容
  • 用元数据条件做精确过滤(如 时间 > 2024-01-01 AND 类别 = "技术文档"
python 复制代码
# 示例:只检索 2024 年之后的技术文档
results = vectorstore.similarity_search(
    query="微服务监控",
    k=5,
    filter={
        "category": "技术文档",
        "year": {"$gte": 2024}
    }
)

主流向量数据库选型对比

五大数据库速览

数据库 定位 部署方式 索引算法 元数据过滤 适用场景
Chroma 开发/原型 本地/嵌入式 HNSW 本地快速验证、小项目
Qdrant 生产自部署 Docker/K8s HNSW 企业首选,性能强、过滤强
Weaviate 混合检索 Docker/托管 HNSW 需要 BM25 + 向量混合检索
pgvector PG 扩展 PostgreSQL 插件 HNSW/IVF 已有 PG 环境,不想引入新数据库
Pinecone 托管云服务 全托管 自动选择 不想运维,快速上线

详细分析

Chroma ------ 开发者的最佳选择

python 复制代码
from langchain_chroma import Chroma

# 嵌入式运行,零配置
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)
  • ✅ 零配置,pip install 即用
  • ✅ 支持持久化到本地磁盘
  • ❌ 单机性能有限,不适合高并发
  • ❌ 分布式能力弱

Qdrant ------ 生产环境的企业首选

python 复制代码
from langchain_qdrant import Qdrant
from qdrant_client import QdrantClient

client = QdrantClient(url="http://localhost:6333")
vectorstore = Qdrant(
    client=client,
    collection_name="docs",
    embeddings=embeddings,
)
  • ✅ Rust 编写,性能极高
  • ✅ 元数据过滤表达式非常强大
  • ✅ 支持分布式集群
  • ✅ 云端托管版本可用
  • ❌ 需要额外部署服务

Weaviate ------ 混合检索专家

python 复制代码
from langchain_weaviate import WeaviateVectorStore
import weaviate

client = weaviate.connect_to_local()
vectorstore = WeaviateVectorStore(
    client=client,
    index_name="Docs",
    text_key="text",
    embedding=embeddings,
)
  • ✅ 原生支持 BM25 + 向量混合检索
  • ✅ 内置向量化模块(可选)
  • ❌ 资源占用较高
  • ❌ 学习曲线陡峭

pgvector ------ PostgreSQL 用户的福音

sql 复制代码
-- 在 PostgreSQL 中安装扩展
CREATE EXTENSION vector;

-- 创建带向量列的表
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    content TEXT,
    embedding vector(1024),
    category VARCHAR(50)
);

-- 创建 HNSW 索引
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);
python 复制代码
from langchain_community.vectorstores import PGVector

vectorstore = PGVector(
    connection_string="postgresql://user:pass@localhost/db",
    embedding_function=embeddings,
    collection_name="docs",
)
  • ✅ 和现有 PG 数据库无缝集成
  • ✅ 支持 SQL 的完整表达能力
  • ✅ 事务支持(ACID)
  • ❌ 向量检索性能不如专用数据库
  • ❌ 大规模数据下 PG 本身成为瓶颈

Pinecone ------ 完全不想运维的选择

python 复制代码
from langchain_pinecone import PineconeVectorStore
from pinecone import Pinecone

pc = Pinecone(api_key="your-key")
index = pc.Index("docs")
vectorstore = PineconeVectorStore(index=index, embedding=embeddings)
  • ✅ 全托管,零运维
  • ✅ 自动扩缩容
  • ✅ 元数据过滤支持良好
  • ❌ 价格较高
  • ❌ 数据锁定(迁移成本高)

实战:Chroma(开发)vs Qdrant(生产)

场景设定

假设我们要为一个技术博客系统构建 RAG:

  • 开发阶段:用 Chroma 快速验证,本地运行
  • 生产阶段:迁移到 Qdrant,支持多租户和元数据过滤

开发阶段 ------ Chroma

python 复制代码
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(
    model="BAAI/bge-large-zh-v1.5",
    api_key=os.getenv("SILICONFLOW_API_KEY"),
    base_url="https://api.siliconflow.cn/v1",
    chunk_size=32,
)

# 创建本地向量库
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db",
    collection_metadata={"hnsw:space": "cosine"}
)

# 检索
results = vectorstore.similarity_search("微服务拆分原则", k=3)
for doc in results:
    print(f"来源: {doc.metadata['source']}")
    print(f"内容: {doc.page_content[:100]}...")
    print()

# 持久化(Chroma 自动保存)
# 下次加载:
# vectorstore = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)

生产阶段 ------ Qdrant

python 复制代码
from langchain_qdrant import Qdrant
from qdrant_client import QdrantClient, models

# 连接 Qdrant 服务
client = QdrantClient(url="http://localhost:6333")

# 创建 Collection(相当于数据库的表)
client.create_collection(
    collection_name="blog_docs",
    vectors_config=models.VectorParams(
        size=1024,  # BGE-large-zh 的维度
        distance=models.Distance.COSINE,
    ),
)

# 写入数据
vectorstore = Qdrant(
    client=client,
    collection_name="blog_docs",
    embeddings=embeddings,
)

vectorstore.add_documents(documents=chunks)

# 带元数据过滤的检索
results = vectorstore.similarity_search(
    query="微服务监控",
    k=5,
    filter=models.Filter(
        must=[
            models.FieldCondition(
                key="category",
                match=models.MatchValue(value="微服务")
            ),
            models.FieldCondition(
                key="year",
                range=models.Range(gte=2024)
            ),
        ]
    )
)

从 Chroma 迁移到 Qdrant

python 复制代码
# 1. 从 Chroma 导出
croma_store = Chroma(
    persist_directory="./chroma_db",
    embedding_function=embeddings
)
all_docs = chroma_store.get()

# 2. 导入 Qdrant
qdrant_store = Qdrant(
    client=qdrant_client,
    collection_name="blog_docs",
    embeddings=embeddings,
)

# 3. 批量写入(Qdrant 支持高效批量导入)
from langchain_core.documents import Document

docs = [
    Document(page_content=text, metadata=meta)
    for text, meta in zip(all_docs["documents"], all_docs["metadatas"])
]
qdrant_store.add_documents(docs)

相似度算法怎么选?

向量数据库在比较两个向量时,需要一种"距离度量"。常用的有三种:

余弦相似度(Cosine Similarity)

css 复制代码
cosine(A, B) = (A · B) / (||A|| × ||B||)
  • 测量:两个向量夹角的余弦值
  • 特点:只关心方向,不关心长度
  • 适用:文本语义相似度(最常用的选择)
  • 取值:-1(完全相反)到 1(完全相同),通常 > 0.7 算相似

点积(Dot Product)

css 复制代码
dot(A, B) = A · B = Σ(Ai × Bi)
  • 测量:向量对应维度相乘再求和
  • 特点:同时考虑方向和长度
  • 适用:推荐系统(用户偏好强度重要)
  • 注意:如果向量未归一化,点积会被向量长度影响

欧氏距离(Euclidean Distance)

scss 复制代码
euclidean(A, B) = √Σ(Ai - Bi)²
  • 测量:两点之间的直线距离
  • 特点:绝对距离,对数值差异敏感
  • 适用:图像检索、数值特征场景
  • 取值:0(完全相同)到 ∞,越小越相似

选型建议

场景 推荐算法 理由
文本语义检索 余弦相似度 主流选择,对向量长度不敏感
推荐系统 点积 考虑用户兴趣强度
图像检索 欧氏距离 像素级差异更直观
不确定 余弦相似度 最安全的选择

⚠️ 重要:Embedding 模型和相似度算法要匹配!BGE 模型推荐使用余弦相似度,OpenAI text-embedding-3 系列也推荐余弦相似度。


元数据过滤:从"大海捞针"到"精准定位"

为什么需要元数据过滤?

假设你的知识库有 10 万篇文档,涵盖技术、产品、运营、销售多个部门。用户问:"今年的销售目标是什么?"

纯向量检索可能召回:

  • ✅ 销售部门 2024 年的目标文档
  • ❌ 运营部门提到的"销售"相关流程
  • ❌ 技术文档里的"销售系统架构"

加上元数据过滤 {"department": "销售", "year": 2024},就能精准锁定范围。

LangChain 中的元数据过滤

python 复制代码
from langchain_chroma import Chroma

# 写入时带上元数据
docs = [
    Document(
        page_content="2024 年销售目标:营收增长 30%...",
        metadata={"department": "销售", "year": 2024, "type": "目标"}
    ),
    Document(
        page_content="销售系统使用 Redis 缓存...",
        metadata={"department": "技术", "year": 2024, "type": "架构"}
    ),
]

vectorstore = Chroma.from_documents(docs, embeddings)

# 检索时过滤
results = vectorstore.similarity_search(
    "销售目标",
    k=3,
    filter={"department": "销售", "year": 2024}
)

Qdrant 的高级过滤表达式

python 复制代码
from qdrant_client import models

filter = models.Filter(
    must=[  # AND 条件
        models.FieldCondition(key="department", match=models.MatchValue(value="销售")),
        models.FieldCondition(key="year", range=models.Range(gte=2024)),
    ],
    should=[  # OR 条件
        models.FieldCondition(key="type", match=models.MatchValue(value="目标")),
        models.FieldCondition(key="type", match=models.MatchValue(value="总结")),
    ],
    must_not=[  # NOT 条件
        models.FieldCondition(key="status", match=models.MatchValue(value="草稿")),
    ]
)

选型决策总结

按场景推荐

场景 推荐数据库 理由
本地开发/快速原型 Chroma 零配置,pip install 即用
生产环境自部署 Qdrant 性能最强,过滤最灵活,Rust 稳定
需要混合检索(BM25 + 向量) Weaviate 原生支持两种检索融合
已有 PostgreSQL pgvector 不引入新组件,SQL 表达能力完整
完全不想运维 Pinecone 全托管,自动扩缩
超大规模(十亿级向量) Milvus 专为海量向量设计(本文未展开)

从开发到生产的迁移路径

markdown 复制代码
阶段 1:开发验证
    └── Chroma(本地嵌入式,零配置)
            ↓
阶段 2:测试环境
    └── Qdrant Docker(单节点,验证功能)
            ↓
阶段 3:生产上线
    └── Qdrant 集群 / Pinecone 托管(高可用)

小结

本文覆盖了向量数据库的核心知识:

  1. 为什么需要向量数据库 ------ ANN 检索传统数据库做不了
  2. 三大核心能力 ------ 存储、ANN 检索、元数据过滤
  3. 五大数据库对比 ------ Chroma、Qdrant、Weaviate、pgvector、Pinecone
  4. 实战代码 ------ Chroma 开发和 Qdrant 生产的完整示例
  5. 相似度算法 ------ 余弦、点积、欧氏距离的选择
  6. 元数据过滤 ------ 从"大海捞针"到"精准定位"

关键认知:向量数据库不是越贵越好,而是越适合你的场景越好。开发用 Chroma,生产用 Qdrant,有 PG 用 pgvector,不想运维用 Pinecone------没有银弹,只有最合适。


参考资料

相关推荐
vooy pktc1 小时前
macOS安装Redis
数据库·redis·macos
Agent手记1 小时前
首件检验流程繁琐,耗时久还容易出现合规漏洞怎么办?——基于实在Agent的AI+超自动化全流程闭环实战
网络·人工智能·ai·自动化
eqwaak01 小时前
PyTorch张量操作全攻略:从入门到精通
开发语言·人工智能·pytorch·python
程序员学习Chat1 小时前
计算机视觉-异常检测
人工智能·计算机视觉·异常检测
辞旧 lekkk1 小时前
【Qt】初识(上)
开发语言·数据库·qt·学习·萌新
格林威1 小时前
线阵工业相机:如何计算线阵相机的行频(Line Rate)?公式+实例
开发语言·人工智能·数码相机·算法·计算机视觉·工业相机·线阵相机
爱学习的张大1 小时前
具身智能数据Pipeline
人工智能
流年似水~1 小时前
素材管理:剪辑前整理素材的底层逻辑
人工智能·程序人生·语言模型·ai编程
geneculture2 小时前
当前主流人工智能(大语言模型、世界模型)与融智学双重形式化路径之间的根本差异
人工智能·融智学的重要应用·哲学与科学统一性·融智时代(杂志)·人际间性·人机间性