五种嵌入式向量存储的基准测试:FAISS、Chroma、LanceDB、VectLite
五款用于本地RAG的嵌入式向量数据库性能测试:FAISS、Chroma、LanceDB、VectLite和NumPy在召回率、延迟、过滤功能及冷启动方面的对比。
来源: I Benchmarked 5 Vector Databases for a Local RAG. Only One Actually Surprised Me.
大多数关于“最佳向量数据库”的对比文章其实不过是各厂商宣传页的改头换面:Pinecone速度快,Qdrant性能稳定,Chroma使用简单,似乎各方都能取胜。而这篇文章则是从更具体的需求出发——无需集群、无需Docker、无需开放端口,也无需托管服务,只需要一个仅由一个本地文件构成的嵌入式向量存储,通过pip install安装后只需三行Python代码即可使用。因此,这里针对这一特定用途自行制作了五种引擎的基准测试。
测试数据
测试数据集包含5,000个384维的向量,使用余弦相似度进行了50次查询。所有测试均在macOS(x86_64)系统上,使用Python 3.12.8运行,并采用各引擎的默认设置。
| 引擎 | 数据插入速度(向量/秒) | 搜索p95值 | 10%召回率 | 过滤p95值 | 过滤10%召回率 |
|---|---|---|---|---|---|
| FAISS | 743,099 | 0.65毫秒 | 1.000 | 无 | 不进行过滤 |
| NumPy精确匹配 | 2,412,231 | 2.59 毫秒 | 1.000 | 9.25 毫秒 | 1.000 |
| Chroma | 2,011 | 3.14 毫秒 | 0.840 | 18.76 毫秒 | 1.000 |
| VectLite 0.10.0 | 154 | 5.71 毫秒 | 0.966 | 10.28 毫秒 | 0.966 |
| LanceDB | 20,120 | 12.20 毫秒 | 1.000 | 14.11 毫秒 | 1.000 |
十秒测试结果:FAISS速度最快,但它其实算不上真正的数据库。Chroma最容易上手,但其84%的默认召回率是个常被人们忽视的问题。令人意外的是,VectLite在无需任何调优的嵌入式模式下就能达到96.6%的召回率。LanceDB则追求完美的召回率,但为此付出了更高的延迟代价。NumPy只是用来对比的基准,而非参赛者。
为何“最快”并非正确的评估标准
向量数据库市场充斥着营销竞争。各供应商都会发布自己擅长的测试结果,相关评测文章也往往在缺乏背景说明的情况下重复这些数据,而且大家都只关注延迟。仅看延迟会带来误导——用错误的向量在半毫秒内给出答案,其实比用5毫秒时间找到正确的向量更糟糕。这正是召回率所要衡量的,也是为何像ANN-Benchmarks(https://ann-benchmarks.com/)这样的专业工具会将召回率与处理速度一起展示的原因。
因此,这次测试同时衡量了多项指标:一方面是p50、p95和p99延迟以及每秒查询次数,另一方面则是与纯NumPy实现的精确余弦搜索相比的10%召回率。
哪些内容被测试,哪些没有
该项目是一个名为 vectlite-benchmark-lab 的小型 Python 包。每个引擎都实现了一个通用的 VectorStore 接口,测试程序会依次调用它们。该测试涵盖以下内容:
- 批量数据导入
- 带有召回率测量的 k-NN 搜索
- 基于
tenant_id的精确匹配元数据过滤 - 冷启动时间
- 数据备份与可移植性
- 输出为 CSV、JSON 格式以及 Matplotlib 图表
需要提前说明的是,该测试不涉及分布式或多节点架构,本轮测试的向量数量不超过 5,000 个,也不进行任何索引优化,同时不使用 Qdrant 或 pgvector,因为这些工具需要运行中的服务器,而该测试的目标是纯本地运行。做出这一选择是有意为之。第一个有意义的问题并非经过两周优化后谁会胜出,而是直接安装引擎且不进行任何调整时它的表现如何。
方法
真实值是通过 NumPy 进行的暴力余弦搜索。引擎的召回率是指其在所有查询中平均返回的真实邻居所占的比例。运行配置如下:
vectlite : 0.10.0
vectors : 5,000 (synthetic, normalized)
dimensions : 384
queries : 50
top_k : 10
metric : cosine
filter : tenant_id (exact-match)
warmup : 5 queries discarded
hardware : macOS x86_64, Python 3.12.8
要在您的机器上重现该效果,请运行完整命令:
PYTHONPATH=src python -m vectlite_benchmark_lab run \
--stores vectlite,faiss,chroma,lancedb,numpy_exact \
--vectors 5000 --dimensions 384 --queries 50 \
--top-k 10 --batch-size 500 \
--output-dir results/vectlite-0.10.0 \
--data-dir data/vectlite-0.10.0
然后将你的结果与这些进行比较,观察其中的差异。
FAISS:速度的极限
FAISS在所有延迟指标上都表现最佳:p95值为0.65毫秒,且召回率完美,这正符合经过十年优化、专为该用途设计的C++库应有的表现。但它并非数据库,没有原生的元数据过滤功能,也没有内置的持久化机制和可移植的备份功能。虽然可以为其添加这些功能,实际上也确实有人这么做了,但就其初始状态而言,它更像是一个数学库,而非可直接交付给客户的工具。将其与Chroma相比,就好比将F1引擎与丰田汽车相提并论:前者在赛道上更快,后者则负责将购物物品送回家。此处仅将其作为参考列出。如果只需要基础的向量搜索功能,那它显然是最佳选择。
Chroma:易于上手,需注意召回率
Chroma 是 RAG 原型的默认选择,其出色的开发者体验使其备受青睐。只需安装 chromadb,编写五行代码,文档即可开始被索引。
但问题在于召回率。在未应用任何过滤条件的情况下,Chroma 仅能找到真实相关结果的 84%,这意味着大约每六次查询中就有一次无法找到预期结果。对于原型来说这还算可以接受,但在生产环境中的 RAG 系统中,检索质量直接影响模型的回答质量,这种相关性缺失的问题会悄然存在且 API 无法暴露。只要知道需要调整,通过修改 HNSW 设置即可弥补大部分差距。若应用过滤功能,召回率可达到 100%,但 p95 延迟会升至 18.76 毫秒,明显慢于执行相同任务的其它方法。结论:在初期表现极佳,即便经过三十天的使用,只要在投入生产前进行适当调优,依然能保持良好性能。
VectLite:意外的惊喜
在默认设置下,版本0.10.0的召回率可达96.6%,是此处所有嵌入式引擎中最高的。普通搜索的p95值为5.71毫秒,处于中等水平(Chroma为3.14毫秒,LanceDB为12.20毫秒)。在过滤后的任务中,其p95值为10.28毫秒,而Chroma则为18.76毫秒,因此速度几乎是Chroma的一半。
从最早版本开始就可见到进步。与v0.1.x相比,数据摄取速度从47向量/秒提升到154向量/秒(约快3.3倍),召回率从0.948上升至0.966,过滤操作的p95值则从18.6毫秒降至10.3毫秒,下降了45%。
数据摄取是该引擎的薄弱环节。154向量/秒的速度在Chroma的2000向量/秒甚至更高以及LanceDB面前显得十分缓慢。对于仅索引几千份文档的情况,这倒不是问题;但若要处理一百万个向量,那就得等待一整晚,因此这很可能是下一个需要改进的方面。不过,它是该组引擎中唯一一个性能无需找借口的。
LanceDB:完美召回率,搜索速度较慢
LanceDB的召回率可达100%,且每秒能处理20,120个向量,从理论上看表现相当出色。但其缺点是搜索延迟较高,p95值为12.20毫秒,在五种引擎中是最慢的。对于需要整夜处理数千个查询的批处理流程而言,这一延迟影响不大;但对于需要人实时操作、键盘旁等待响应的交互式工具来说,就会显得十分麻烦。它适合批处理和分析任务,但用于交互式应用则稍显缓慢。
NumPy:基准标准
通过对整个矩阵进行暴力余弦搜索,按定义即可实现完美召回率,且在处理数万向量之前延迟也在可接受范围内,之后则会出现急剧上升。它本身并非一种产品,而是用来衡量其他所有引擎性能的基准标准。
该如何选择
这项基准测试并未选出绝对的胜出者,而是揭示了不同方案之间的权衡关系。按应用场景大致对应如下:
- 快速RAG原型:Chroma,仅需两分钟即可搭建且拥有庞大的生态系统
- 嵌入式AI内存:VectLite,具备最佳的默认检索效果及便携式文件格式
- 本地批量处理管道:LanceDB,可实现完美检索并快速处理数据
- 无过滤功能的纯ANN模型:FAISS,拥有无与伦比的延迟表现
- 分布式生产环境:Qdrant或Milvus,属于此处未测试的另类方案
冷启动与备份
大多数测试都忽略的两个指标。启动时间,即重启后重新打开数据库所需的时间:FAISS为0.001毫秒,LanceDB为2毫秒,Chroma为5毫秒,而VectLite则高达3,059毫秒。VectLite在重新打开数据库时的性能损耗极为严重。对于长期运行的进程来说这无关紧要,但对于按需启动的无服务器函数或CLI工具而言,三秒的冷启动时间实在难以接受,很可能是首先需要解决的问题。
备份:VectLite在54毫秒内即可生成一个19 MB的便携式文件。复制、版本控制及部署操作都只是常规的文件处理工作。正是这一“嵌入式”特性让它得以实用,也是SQLite能存活二十年的关键所在。
本次测试的局限性
每个基准测试都需要标注注意事项,此处有五点:
- 5,000个向量数量偏少,当数量达到10万及以上时其行为会发生变化。
- 仅使用了默认设置,而Chroma和VectLite的性能几乎肯定可以通过优化进一步提升。
- 没有使用任何服务器引擎:Qdrant、Milvus、Weaviate和pgvector均未参与测试。
- 仅进行了一次测试,没有置信区间,也没有重复实验。
- 测试在单台机器上完成,其他硬件环境可能会得到不同的测试结果。
由于代码是开源的,测试结果可重复,因此一旦发现偏差或漏洞,就值得提出来处理。
后续步骤与总结
本次测试只是一个起点,而非最终结论。下一轮的候选方案包括:在所有引擎上进行的10万向量、768维度的测试;使用Markdown和PDF语料库、由人类编写的查询语句进行的RAG风格测试;调整后的召回率设置,使各引擎在相近的精确度下竞争;更短的VectLite冷启动时间;以及带有置信区间的重复测试。
对于“最佳向量数据库”的寻找并无统一答案,因为这取决于人们如何权衡召回率与延迟、数据导入速度以及启动时间。并没有某个绝对领先的数据库,而是每种引擎都有其独特特点。FAISS以数据库的姿态充当速度标杆;Chroma入门简单,但需在正式使用前进行调优;LanceDB是个完美主义者,即便速度较慢也毫不在意;NumPy则是公正的评判者,但却无法实现扩展;而VectLite则能毫不妥协地达成召回率目标。
对于本地代理、命令行工具或笔记本电脑上的离线优先RAG系统而言,VectLite具有很强的竞争力:SQLite让本地关系型数据变得乏味且难以移植,而VectLite则试图用人工智能内存实现同样的功能。这意味着它只需一个19 MB的文件,就能在大约6毫秒内给出响应。
参考链接:ANN-Benchmarks 网址为 https://ann-benchmarks.com/,Qdrant 的基准测试说明位于 https://qdrant.tech/benchmarks/,FAISS 的地址是 https://github.com/facebookresearch/faiss,Chroma 的文档可在 https://docs.trychroma.com/ 查看,LanceDB 的页面为 https://lancedb.github.io/lancedb/。