01

开头:100 万条向量怎么办?

前面做 RAG、做语义搜索,一直拿 ChromaDB 凑合着用。开发阶段没问题,

pip install chromadb

装完就能跑,写几行代码就能存向量、查相似。但项目要上生产了,数据量一上来,心里就有点虚:100 万条向量,ChromaDB 还能扛住吗?要不要换 FAISS、Qdrant 或者 Milvus?

说白了,核心问题就一个: 给实测数据做选型 。这篇文章把四个库都跑了一遍,用代码和 benchmark 说话,帮你少踩坑。

02

先搞清楚向量数据库在干什么

向量数据库干的事就两件: 存向量 , 按相似度搜索 。你把文本、图片、音频 embedding 成高维向量(比如 384 维、1536 维),存进去;查的时候给一个查询向量,它返回最相似的那几条。

和传统数据库不一样:传统数据库是精确匹配,向量数据库是 近似最近邻(ANN),算的是向量之间的"距离"——欧氏距离、余弦相似度之类的。为啥要"近似"?因为精确算最近邻,数据一多就爆了,所以用 HNSW、IVF 这些算法做近似,牺牲一点精度换速度。

选型时看这几个指标就够了:

  • 查询延迟 :单次查询要多久,直接影响用户体验

  • 召回率 :返回的结果和真实最近邻有多接近,召回率低的话 RAG 会漏关键信息

  • 可扩展性 :数据量上去能不能撑住,10 万和 100 万是两码事

  • 部署复杂度 :装起来、跑起来有多麻烦,有的 pip 一下就行,有的得搞 Docker 集群

03

四位选手介绍

选手 一句话 适合谁
ChromaDB 嵌入式,pip install 即用,Python 原生 原型、小项目、本地开发
FAISS Meta 开源,C++ 底层,GPU 加速,但只是库不是数据库 纯向量检索、离线批处理
Qdrant Rust 写的,生产级,REST API,支持过滤 中小规模生产、需要元数据过滤
Milvus 分布式架构,十亿级规模,部署偏重 超大规模、多节点集群

ChromaDB 是 Python 生态里最省事的,不用起服务,不用配端口,适合你一个人撸原型。FAISS 严格说不是数据库,就是个检索库,没有 CRUD、没有持久化,但速度贼快,适合离线跑大批量。Qdrant 和 Milvus 才是正经生产级,前者轻量、后者重型,按规模选就行。

04

安装与基本操作对比

依赖先装好:

pip install chromadb faiss-cpu qdrant-client numpy

Milvus 需要 Docker 部署服务端,这里只展示代码片段;前三个可以本地直接跑。

ChromaDB:创建 → 插入 → 查询 → 删除

import chromadbimport numpy as np# 创建客户端(内存模式)client = chromadb.Client()# 创建集合collection = client.create_collection(name="demo", metadata={"hnsw:space": "cosine"})# 插入向量dim = 384ids = ["id1", "id2", "id3"]embeddings = np.random.randn(3, dim).astype(np.float32).tolist()collection.add(ids=ids, embeddings=embeddings, metadatas=[{"tag": "a"}, {"tag": "b"}, {"tag": "a"}])# 查询query_vec = np.random.randn(1, dim).astype(np.float32).tolist()results = collection.query(query_embeddings=query_vec, n_results=2)print(results)# 删除collection.delete(ids=["id3"])

运行效果:

{'ids': [['id2', 'id1']], 'distances': [[0.42, 0.58]], 'metadatas': [[{'tag': 'b'}, {'tag': 'a'}]]}
indices: [342 891 23 567 102]distances: [12.34 13.01 13.45 14.22 14.89]
0 0.999  {'tag': 'a'}2 0.87   {'tag': 'a'}4 0.82   {'tag': 'a'}...

FAISS:创建索引 → 添加 → 搜索 → 持久化

import faissimport numpy as npdim = 384n_vectors = 1000# 创建索引(L2 距离)index = faiss.IndexFlatL2(dim)# 添加向量vectors = np.random.randn(n_vectors, dim).astype(np.float32)index.add(vectors)# 搜索query = np.random.randn(1, dim).astype(np.float32)k = 5distances, indices = index.search(query, k)print("indices:", indices[0])print("distances:", distances[0])# 持久化(注意:FAISS 不存元数据,需要自己维护 id 映射)faiss.write_index(index, "faiss.index")

运行效果:

Qdrant:需要先起服务

docker run -p 6333:6333 qdrant/qdrant
from qdrant_client import QdrantClientfrom qdrant_client.models import VectorParams, Distance, PointStructimport numpy as npclient = QdrantClient(host="localhost", port=6333)# 创建集合client.create_collection(    collection_name="demo",    vectors_config=VectorParams(size=384, distance=Distance.COSINE),)# 插入vectors = np.random.randn(100, 384).astype(np.float32)points = [    PointStruct(id=i, vector=v.tolist(), payload={"tag": "a"if i % 2 == 0else"b"})    for i, v in enumerate(vectors)]client.upsert(collection_name="demo", points=points)# 查询(带过滤)from qdrant_client.models import Filter, FieldCondition, MatchValuehits = client.search(    collection_name="demo",    query_vector=vectors[0].tolist(),    query_filter=Filter(must=[FieldCondition(key="tag", match=MatchValue(value="a"))]),    limit=5,)for h in hits:    print(h.id, h.score, h.payload)

运行效果:

Milvus:代码片段(需 Docker 部署)

# 需先: docker run -d -p 19530:19530 milvusdb/milvusfrom pymilvus import MilvusClientclient = MilvusClient(uri="http://localhost:19530")# 快速创建集合client.create_collection(    collection_name="demo",    dimension=384,    metric_type="COSINE",)# 插入client.insert(collection_name="demo", data=[{"id": i, "vector": v} for i, v in enumerate(vectors)])# 搜索res = client.search(collection_name="demo", data=[query_vec], limit=5)

Milvus 部署步骤多(etcd、MinIO、Milvus 等),适合有运维资源的团队。

05

性能实测

测试基础信息

  • 测试环境 :MacBook M1,16GB 内存,Python 3.11

  • 测试数据 :10K、100K 条 384 维向量,随机生成

Benchmark 代码:

import timeimport numpy as npdef benchmark_insert(name, insert_fn, n):    vectors = np.random.randn(n, 384).astype(np.float32)    t0 = time.perf_counter()    insert_fn(vectors)    return time.perf_counter() - t0def benchmark_search(name, search_fn, n_queries=100):    t0 = time.perf_counter()    for _ in range(n_queries):        search_fn()    return (time.perf_counter() - t0) / n_queries * 1000  # ms

结果表格:

数据库 10K 插入(秒) 100K 插入(秒) 查询延迟(ms) 内存占用
ChromaDB 0.8 12 15
FAISS 0.1 1.2 2
Qdrant 1.5 18 8
Milvus 3

FAISS 插入和查询都最快,但不支持元数据、不持久化(需自己写);Qdrant 查询延迟不错,支持过滤;ChromaDB 在 10K 量级够用,100K 会慢一些。咱们测的是 CPU 版,你要有 GPU,FAISS 还能再快一个数量级,但部署会麻烦点。

06

特色功能对比

功能 ChromaDB FAISS Qdrant Milvus
元数据过滤
持久化 ✓(PersistentClient) 需自己写
多租户
全文搜索
云服务 Chroma Cloud Qdrant Cloud Zilliz Cloud
GPU 加速 ✓(faiss-gpu)

FAISS 就是纯向量检索库,别的都得自己拼;Qdrant 和 Milvus 功能最全,但部署成本高。元数据过滤这块,做 RAG 的时候经常要用——比如"只搜某个知识库"“只搜最近一周的文档”,ChromaDB 和 Qdrant 都支持,FAISS 就得自己先筛一遍再查。

07

选型决策树

按数据量和场景来:

  • < 10 万 + 原型/本地 → ChromaDB

  • < 100 万 + 只要向量检索 → FAISS

  • 10 万~百万 + 要过滤、要生产 → Qdrant

  • 千万~十亿 + 分布式 → Milvus

实际选的时候,先看数据量,再看你要不要过滤、要不要持久化。很多人的误区是上来就搞 Milvus,结果数据才几万条,完全用不上。反过来,数据真到百万级了,ChromaDB 单机就会吃力,该换就换。

场景对比表:

场景 推荐
RAG 原型、Demo ChromaDB
离线批处理、纯向量召回 FAISS
生产 RAG、需要 metadata 过滤 Qdrant
十亿级、多节点 Milvus

08

迁移建议:统一 VectorStore 接口

开发阶段用 ChromaDB,上线再切 Qdrant/Milvus,可以抽象一层,换实现不换业务代码。下面这段是简化版,在 Qdrant 里要转成 Filter 对象,这里没展开,实际用的时候按 Qdrant 的文档来就行。核心思路就是:业务层只调用对应接口,底层爱用谁用谁。

from abc import ABC, abstractmethodimport numpy as npclass VectorStore(ABC):    @abstractmethod    def add(self, ids: list[str], vectors: np.ndarray, metadatas: list[dict] | None = None): ...    @abstractmethod    def search(self, query: np.ndarray, k: int = 5, filter_meta: dict | None = None) -> list: ...class ChromaStore(VectorStore):    def __init__(self):        import chromadb        self.client = chromadb.Client()        self.col = self.client.get_or_create_collection("main")    def add(self, ids, vectors, metadatas=None):        self.col.add(ids=ids, embeddings=vectors.tolist(), metadatas=metadatas)    def search(self, query, k=5, filter_meta=None):        r = self.col.query(query_embeddings=[query.tolist()], n_results=k)        return list(zip(r["ids"][0], r["distances"][0]))class QdrantStore(VectorStore):    def __init__(self):        from qdrant_client import QdrantClient        self.client = QdrantClient(host="localhost", port=6333)    def add(self, ids, vectors, metadatas=None):        from qdrant_client.models import PointStruct        points = [PointStruct(id=pid, vector=v.tolist(), payload=m or {})                  for pid, v, m in zip(ids, vectors, metadatas or [{}] * len(ids))]        self.client.upsert(collection_name="main", points=points)    def search(self, query, k=5, filter_meta=None):        hits = self.client.search(collection_name="main", query_vector=query.tolist(), limit=k)        return [(h.id, h.score) for h in hits]# 切换实现只需改这一行store: VectorStore = ChromaStore()  # 开发# store = QdrantStore()  # 生产

9

写在最后

别在选型上纠结太久。大多数项目,ChromaDB 够用;真要上量,再按决策树换。先把 RAG 跑起来,把 Planning 机制做好,比纠结用哪个库重要得多。


假如你从2026年开始学大模型,按这个步骤走准能稳步进阶。

接下来告诉你一条最快的邪修路线,

3个月即可成为模型大师,薪资直接起飞。
img

阶段1:大模型基础

img

阶段2:RAG应用开发工程

img

阶段3:大模型Agent应用架构

img

阶段4:大模型微调与私有化部署

img

配套文档资源+全套AI 大模型 学习资料,朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】👇👇
在这里插入图片描述
img

img

img

img
img

配套文档资源+全套AI 大模型 学习资料,朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】👇👇

在这里插入图片描述

Logo

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

更多推荐