原文标题: RyanCodrai turbovec
原文内容:
一个包含 1000 万文档的语料库以 float32 格式存储需要 31 GB 内存。turbovec 将其压缩至 4 GB,并且搜索速度比 FAISS 更快。turbovec 是一个带有 Python 绑定的 Rust 向量索引,基于 Google Research 的 TurboQuant 算法构建——这是一种数据无关的量化器,能够达到 Shannon 失真下界,无需码本训练,也无需单独的训练阶段。支持在线数据摄入。添加向量后即可索引——无需训练步骤、无需参数调优、也无需随语料增长而重建。速度比 FAISS 更快。手写的 NEON(ARM)和 AVX-512BW(x86)内核在 ARM 上比 FAISS IndexPQFastScan 快 12–20%,在 x86 上与之持平或更优。支持搜索时过滤。向 search() 传递一个 ID 允许列表(或一个槽位位掩码),内核会直接处理该过滤条件。你始终能从允许集合中获得最多 k 个结果——无需过度获取,选择性过滤时也不会影响召回率。纯本地运行。无需托管服务,数据不会离开你的机器或 VPC。可与任何开源嵌入模型搭配,构建完全隔离的 RAG 堆栈。正在构建注重隐私、内存或延迟的 RAG 应用?你来对地方了。
Python pip install turbovec
from turbovec import TurboQuantIndex
index = TurboQuantIndex(dim=1536, bit_width=4)
index.add(vectors)
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
index = IdMapIndex(dim=1536, bit_width=4)
index.add_with_ids(vectors, np.array([1001, 1002, 1003], dtype=np.uint64))
scores, ids = index.search(query, k=10) # ids 是你的 uint64 外部 ID
index.remove(1002) # 按 ID 进行 O(1) 删除
index.write("my_index.tvim")
loaded = IdMapIndex.load("my_index.tvim")
混合检索(过滤搜索)
将结果限制为另一个系统(SQL、BM25、ACL、时间窗口等)生成的候选集:
import numpy as np
from turbovec import IdMapIndex
idx = IdMapIndex(dim=1536, bit_width=4)
idx.add_with_ids(vectors, ids)
# 阶段 1:外部系统将范围缩小到候选 ID。
allowed = np.array(db.execute("SELECT id FROM docs WHERE tenant=?", (t,)).fetchall(), dtype=np.uint64)
# 阶段 2:在候选集内进行密集重排序。
scores, ids = idx.search(query, k=10, allowlist=allowed)
过滤操作在 SIMD 内核内部以 32 向量块为粒度进行:没有允许槽位的块会在任何 LUT 查找或评分工作之前被短路跳过,而已评分块中单个不允许的槽位会在堆插入时被丢弃。因此,选择性允许列表(仅允许索引中一小部分)可以避免大部分 SIMD 开销,而不是先计算再丢弃结果。输出长度是 min(k, len(allowed))——当允许列表小于 k 时,你会得到恰好 len(allowed) 个结果,而不是填充的降级结果。完整参考请参见 docs/api.md。
框架集成
可直接替换各框架中原有的参考向量/文档存储。相同的公共接口、相同的持久化语义、相同的检索器和流水线连接——只需替换导入语句,即可保留你的流水线。
- LangChain —
pip install turbovec[langchain]· 替换langchain_core.vectorstores.InMemoryVectorStore - LlamaIndex —
pip install turbovec[llama-index]· 替换llama_index.core.vector_stores.SimpleVectorStore - Haystack —
pip install turbovec[haystack]· 替换haystack.document_stores.in_memory.InMemoryDocumentStore - Agno —
pip install turbovec[agno]· 替换agno.vectordb.lancedb.LanceDb
Rust
cargo add turbovec
use turbovec::TurboQuantIndex;
let mut index = TurboQuantIndex::new(1536, 4);
index.add(&vectors);
let results = index.search(&queries, 10);
index.write("index.tv").unwrap();
let loaded = TurboQuantIndex::load("index.tv").unwrap();
对于需要删除后仍保持稳定的外部 ID:
use turbovec::IdMapIndex;
let mut index = IdMapIndex::new(1536, 4);
index.add_with_ids(&vectors, &[1001, 1002, 1003]);
let (scores, ids) = index.search(&queries, 10);
index.remove(1002);
index.write("index.tvim").unwrap();
let loaded = IdMapIndex::load("index.tvim").unwrap();
召回率
TurboQuant 与 FAISS IndexPQ(LUT256, nbits=8)对比——论文第 4.4 节的基线。100K 向量,k=64。FAISS PQ 子量化器数量与 TurboQuant 的比特率相匹配(2-bit 时 m=d/4,4-bit 时 m=d/2)。在 OpenAI d=1536 和 d=3072 上,TurboQuant 在 2-bit 和 4-bit 下的 R@1 比 FAISS 高出 0.4–3.4 个点,并且两者在 k=4 时都收敛到 1.0。GloVe d=200 是更困难的场景——在低维度下,渐近 Beta 假设的约束性较弱。TurboQuant 在 4-bit 下的 R@1 比 FAISS 高出 0.3 个点,在 2-bit 下落后 1.2 个点,两者在 k≈16 时都接近 FAISS。
关于基线的说明。我们与 FAISS IndexPQ(LUT256, nbits=8, float32 LUT)进行比较,因为它是大多数用户会使用的生产级 PQ 标准。这比 TurboQuant 论文中自定义的 u8-LUT PQ 基线更强——FAISS 在评分时使用更高精度的 LUT,并使用 k-means++ 进行码本训练。我们在 OpenAI d=1536 / d=3072 上复现了论文中的 TurboQuant 数值,并在低维嵌入(参见 d=384 上的 turboquant-py)上达到了与其他社区参考实现相似的数值。GloVe 上可见的差距反映了 FAISS 是一个很强的基线,而非 TurboQuant 实现的问题。
完整结果:
- [d=1536 2-bit](https://github.com/RyanCodrai/turbovec)
- [d=1536 4-bit](https://github.com/RyanCodrai/turbovec)
- [d=3072 2-bit](https://github.com/RyanCodrai/turbovec)
- [d=3072 4-bit](https://github.com/RyanCodrai/turbovec)
- [GloVe 2-bit](https://github.com/RyanCodrai/turbovec)
- [GloVe 4-bit](https://github.com/RyanCodrai/turbovec)
压缩搜索速度
所有基准测试:100K 向量,1K 查询,k=64,5 次运行的中位数。
ARM(Apple M3 Max) 在 ARM 上,TurboQuant 在所有配置下都比 FAISS FastScan 快 12–20%。
x86(Intel Xeon Platinum 8481C / Sapphire Rapids,8 vCPU) 在 x86 上,TurboQuant 在所有 4-bit 配置下比 FAISS 快 1–6%,在 2-bit 单线程上运行速度与 FAISS 相差约 1%。2-bit 多线程行(d=1536 和 d=3072)是唯一略微落后于 FAISS 的配置(慢 2–4%)。