前言

当你的 RAG 系统需要处理百万级以上向量时,单机版的向量检索就不够用了。你需要一个真正的向量数据库。

目前主流的三个选择是:Milvus、Qdrant、Chroma。本文从架构、性能、功能、运维四个维度深度对比。

架构对比

Milvus(云原生)

┌──────────┐  ┌──────────┐  ┌──────────┐
│  Proxy   │  │  Proxy   │  │  Proxy   │  ← 无状态网关
└────┬─────┘  └────┬─────┘  └────┬─────┘
     │             │             │
┌────▼─────────────▼─────────────▼────┐
│           Root Coordinator           │  ← 元数据管理
└────▲─────────────▲─────────────▲────┘
     │             │             │
┌────┴─────┐  ┌────┴─────┐  ┌────┴─────┐
│  Query   │  │  Data    │  │  Index   │
│  Node    │  │  Node    │  │  Node    │  ← 计算存储分离
└──────────┘  └──────────┘  └──────────┘

依赖:etcd(元数据)+ MinIO/S3(数据)+ Kafka(日志)

特点:组件多、功能全、扩展性强。适合大规模生产环境。

Qdrant(Rust 实现)

┌──────────────┐
│   Qdrant     │
│  ┌────────┐  │
│  │ Segment│  │  ← 每个 collection 分为多个 segment
│  │        │  │
│  │ HNSW   │  │  ← 向量索引 + 负载索引
│  │ + Payload│ │
│  └────────┘  │
└──────────────┘

单二进制文件部署,无外部依赖。

特点:Rust 实现、性能卓越、部署极简。单二进制搞定一切。

Chroma(轻量级)

┌──────────────┐
│   Chroma     │
│  ┌────────┐  │
│  │SQLite  │  │  ← 数据持久化
│  │+ HNSW  │  │  ← 内存向量索引
│  └────────┘  │
└──────────────┘

pip install chromadb 即可使用。

特点:极简、开发友好、不适合生产大规模场景。

性能基准

测试条件:100 万 768 维向量,余弦距离,Top-10 检索,单机(32 核,128GB RAM,NVMe SSD)

指标 Milvus 2.4 Qdrant 1.9 Chroma 0.5
写入速度(向量/秒) 8,000 12,000 5,000
查询延迟(P50) 8ms 3ms 5ms
查询延迟(P99) 25ms 12ms 30ms
QPS(单机) 1,200 2,500 800
内存占用 2.8GB 1.5GB 3.2GB
索引构建时间 12min 8min 15min

注意:这是单机测试。Milvus 的强项在分布式,多节点下 QPS 可以线性扩展。

核心功能对比

标量过滤(Filter Search)

这是向量数据库最重要的实用功能——先按标签筛选,再搜向量。

# Milvus
milvus_client.search(
    collection_name="docs",
    data=[query_vector],
    limit=10,
    expr="category == 'technology' && view_count > 1000",
)

# Qdrant
qdrant_client.search(
    collection_name="docs",
    query_vector=query_vector,
    limit=10,
    query_filter=models.Filter(
        must=[
            models.FieldCondition(key="category", match=models.MatchValue(value="technology")),
            models.FieldCondition(key="view_count", range=models.Range(gte=1000)),
        ]
    ),
)

# Chroma
chroma_collection.query(
    query_embeddings=[query_vector],
    n_results=10,
    where={"category": "technology", "view_count": {"$gte": 1000}},
)

标量过滤性能
- Qdrant > Milvus > Chroma
- Qdrant 的 payload 索引用内存维护,过滤几乎无开销
- Milvus 在复杂过滤条件下延迟会明显上升
- Chroma 在 10 万级数据以上过滤性能急剧下降

混合检索(Hybrid Search)

# Qdrant —— 原生支持
from qdrant_client import QdrantClient
from qdrant_client.models import (
    HybridFusion, FusionQuery, Prefetch,
)

qdrant_client.search(
    collection_name="docs",
    query_vector=QueryVector(
        FusionQuery(
            prefetch=[
                Prefetch(
                    query=query_vector,
                    limit=50,
                ),
                Prefetch(
                    query="search keywords",
                    limit=50,
                ),
            ],
            fusion=HybridFusion.RRF,
        )
    ),
    limit=10,
)

# Milvus —— 需要自己实现混合
# 分别做向量检索和 BM25 检索,然后 RRF 合并在应用层

Qdrant 是三者中唯一原生支持混合检索的,Milvus 和 Chroma 需要在应用层手动实现 RRF 合并。

数据持久化与备份

功能 Milvus Qdrant Chroma
持久化 S3/MinIO 本地磁盘/S3 SQLite
快照备份 ✅ 原生 ✅ 原生 ❌ 手动
增量备份
从备份恢复

部署运维

部署复杂度

Milvus:  docker-compose 启动 7 个服务
Qdrant:  docker run qdrant/qdrant
Chroma:  pip install chromadb

资源占用

场景 Milvus Qdrant Chroma
最小部署 4GB RAM + 4 核 512MB RAM + 1 核 256MB RAM
生产推荐 32GB RAM + 16 核 8GB RAM + 4 核 不推荐生产
存储 MinIO 独立 直接在磁盘 SQLite 文件

实战部署(Docker Compose)

Qdrant(最轻量)

# docker-compose.yml
services:
  qdrant:
    image: qdrant/qdrant:latest
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - ./qdrant_storage:/qdrant/storage
    environment:
      - QDRANT__SERVICE__GRPC_PORT=6334

Milvus(生产级)

# docker-compose.yml
services:
  etcd:
    image: quay.io/coreos/etcd:v3.5.5
  minio:
    image: minio/minio:latest
  milvus:
    image: milvusdb/milvus:v2.4.0
    ports: ["19530:19530"]
    depends_on: [etcd, minio]

选型决策树

你的场景是?
├── 原型验证 / 学习 / 数据量  1000 万
│   └── Milvus(唯一成熟的分布式方案)
│
├── 需要标量过滤(Filter Search)
│   └── Qdrant > Milvus > Chroma
│
└── 边缘设备 / 嵌入式场景
    └── Qdrant(Rust 编译,二进制仅 30MB)

迁移方案

从 Chroma 迁移到 Qdrant:

# 导出 Chroma 数据
import chromadb
chroma_client = chromadb.PersistentClient(path="./chroma_data")
collection = chroma_client.get_collection("docs")
all_data = collection.get(include=["embeddings", "documents", "metadatas"])

# 导入到 Qdrant
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct

qdrant = QdrantClient("localhost:6333")
qdrant.create_collection(
    collection_name="docs",
    vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE),
)

points = [
    PointStruct(
        id=idx,
        vector=emb.tolist(),
        payload={"text": all_data["documents"][idx], **all_data["metadatas"][idx]},
    )
    for idx, emb in enumerate(all_data["embeddings"])
]
qdrant.upsert(collection_name="docs", points=points)

总结

  • 快速原型:Chroma(pip install 一秒上手)
  • 生产单机:Qdrant(高性能、极简运维、混合检索原生支持)
  • 生产分布式:Milvus(功能最全、扩展性最强)
  • 核心关注点:标量过滤性能 > 检索精度 > 写入速度 > 部署复杂度

我的个人建议:大部分团队从 Qdrant 开始。它用 Rust 实现,单机性能碾压,运维几乎零成本,需要扩展时也支持分布式。