背景

最近在搞 RAG 相关的东西,向量数据库这块一直用的 FAISS。用着没啥大毛病,但有个痛点:内存占用太大。

1000万条 1536 维的向量,float32 存储直接干到 31GB。服务器内存吃不住,量化方案又得单独跑 train 阶段,数据量小了码本质量还拉胯。

然后在 arXiv 上刷到一篇 Google Research 的论文——TurboQuant(ICLR 2026),顺着论文找到了它的 Rust 实现:turbovec

试了一下,真香。

turbovec 是什么

一句话:基于 TurboQuant 算法的向量索引库,Rust 写的,有 Python 绑定。

核心卖点:

  • 1000万 1536 维向量,31GB → 4GB
  • 没有 train 阶段add() 直接索引
  • 比 FAISS IndexPQFastScan 快 12-20%(ARM)/ 持平或略快(x86)
  • 纯本地,数据不出机器

GitHub: RyanCodrai/turbovec(9K+ stars)

技术原理(简化版)

TurboQuant 的核心思路挺巧妙的:

  1. 归一化:把向量长度去掉,变成超球面上的单位方向
  2. 随机正交旋转:旋转之后,每个坐标独立服从已知的 Beta 分布。关键点——这个分布跟输入数据无关,是数学上能推导出来的
  3. Lloyd-Max 量化:既然分布已知,最优的桶边界可以直接算出来,不需要从数据里学
  4. Bit-pack:1536维向量从 6144 字节压到 384 字节,16 倍压缩

省掉了 train 阶段,意味着:

  • 数据量小也能用
  • 在线添加新向量不需要重建索引
  • 没有超参数调优的烦恼

实际用法

pip install turbovec

基础用法真的很简单:

from turbovec import TurboQuantIndex

index = TurboQuantIndex(dim=1536, bit_width=4)
index.add(vectors)          # 直接 add,不用 train
index.add(more_vectors)     # 随时加,不用重建

scores, indices = index.search(query, k=10)

# 持久化
index.write("my_index.tq")
loaded = TurboQuantIndex.load("my_index.tq")

需要稳定 ID 的场景(比如要删除某些向量),用 IdMapIndex

import numpy as np
from turbovec import IdMapIndex

idx = IdMapIndex(dim=1536, bit_width=4)
idx.add_with_ids(vectors, np.array([1001, 1002, 1003], dtype=np.uint64))

scores, ids = idx.search(query, k=10)   # 返回你自己的 uint64 id
idx.remove(1002)                         # O(1) 删除

最让我惊喜的是内核级过滤

# SQL 先粗筛出候选 id
allowed = np.array(db.execute(
    "SELECT id FROM docs WHERE tenant=?", (t,)
).fetchall(), dtype=np.uint64)

# 向量搜索时直接过滤,没有过取、没有召回损失
scores, ids = idx.search(query, k=10, allowlist=allowed)

过滤是在 SIMD 内核里做的,32 个向量一组,没有 allowed 的直接跳过,比"先搜再过滤"高效得多。

性能对比

官方 benchmark 数据(100K 向量, k=64, 中位数 5 次):

ARM (Apple M3 Max):

  • 2-bit 单线程:比 FAISS FastScan 快 ~15%
  • 4-bit 单线程:快 ~12-20%

x86 (Intel Xeon Sapphire Rapids):

  • 4-bit:快 1-6%
  • 2-bit:基本持平

召回率方面,OpenAI 1536/3072 维上比 FAISS IndexPQ 高 0.4-3.4 个百分点(@1)。

适配情况

  • Python 3.9-3.14
  • macOS + Linux(没有 Windows)
  • x86 要求 AVX2(Haswell 2013+),AVX-512 运行时自动检测
  • ARM 用 NEON

框架集成:LangChain / LlamaIndex / Haystack / Agno 都有 drop-in 替换。

坑和注意

  1. Alpha 阶段 — PyPI 标记的 Development Status 是 Alpha,生产环境慎用
  2. 低维数据 — GloVe d=200 这种,2-bit 下召回率比 FAISS 略低(Beta 假设在低维更松)
  3. x86 2-bit 多线程 — 唯一略微跑输 FAISS 的配置(2-4%)
  4. 没 Windows — 目前只支持 macOS 和 Linux

总结

如果你的场景是:

  • 内存紧张
  • 需要在线增删向量
  • 不想折腾 train 阶段
  • 纯本地部署

turbovec 值得试试。4GB 存原来 31GB 的数据,还不用 train,这个吸引力够大了。

我已经在自己的 RAG 项目里从 FAISS 切过去了,目前没踩坑。后续有坑再更新。


参考: