Milvus 引入 SVS Vamana,英特尔团队比较高召回检索与内存开销

英特尔团队在四组数据上对比 LeanVec 与两种 HNSW 存储方式。多数配置中查询和内存表现更优,文中也列出 FP16 更快的例外及构建限制。
编辑更正(2026年11月12日)性能比较采用文中的数据集和配置,存在 HNSW FP16 更快的例外。向量表示的内存还应按降维后的实际维度计算。Milvus 文档(在新窗口打开)
近日,Milvus 3.0 正式接入英特尔 SVS Vamana 内存图索引。
作为基于 Vamana 近邻图实现的检索索引,SVS Vamana 原生支持 LeanVec 向量降维与量化。启用 LeanVec 时,在文中多数测试配置下,它比所选 HNSW 存储方式取得更高吞吐和更低延迟,部分配置仍存在例外。

对于正在用 HNSW并且计划做切换的团队来说,这套方案同时兼顾高召回与低内存成本两大优势。
以下是关于 SVS Vamana 的介绍与测评结果。
01
在HNSW上提升召回,为什么会导致代价陡增
RAG、图像检索、推荐这类业务,往往对延迟上限以及Top K召回率都有着很高的要求,HNSW 也因此成为行业主流选择。
但相应的,我们为此需要付出的代价则是:向量本体 + 图邻接信息全部驻留内存,数据量扩容、副本加多,资源开销跟着线性上涨。
因此,在实际部署中,通常有两种方式来平衡精度和内存。
一种是 SQ8 标量量化,每维压缩到 8 bit。Milvus 里 FAISS 系列的 HNSW_SQ 就是这个路线,向量存储体积可以降到原始 float32 的 1/4。多数情况下,HNSW SQ8 可以用较低内存稳定跑出约 95% 召回。
另一种是 FP16,每维 16 bit,量化误差更小,更容易实现高召回,但向量存储开销是 SQ8 的两倍。
而要想基于SQ8实现更高召回,只能放大检索遍历范围。检索时扫描更多邻接节点,才有机会找回漏检向量,代价是大量额外距离计算和内存随机访问。因此,在召回率要求较高时,这些额外开销可能让吞吐量明显下降,尾延迟也随之上升。
有时候,召回率从 95% 提高到 99%,看似只增加了四个百分点,系统付出的成本却可能远不止这些。
基于以上问题,SVS LeanVec 的优化在于:它通过量化与降维结合,减少了搜索过程中反复读取和计算的向量数据,同时通过重排序补回压缩损失的精度。
02
LeanVec 如何兼顾压缩和精度
SVS Vamana 使用的 Vamana 图,和 DiskANN 采用的近邻图结构同源。不过,SVS Vamana 图经过剪枝,可以使得搜索能够通过几次长距离跳跃“跳”向查询目标,使查询能够较快地接近目标向量。
在此基础上,LeanVec 则负责降低沿图搜索的开销。它为每个向量保存主向量与辅助向量两种表示,分别用于搜索和重排序。
用于搜索的主向量先经过线性投影降维(二分之一、四分之一、六分之一,或者任何你配置的值),再进行LVQ量化。图的构建和遍历都基于这一表示,大部分距离计算不再需要处理完整维度的向量。
重排序用的辅助向量,则在量化后保留完整维度。检索环节拿到候选集之后,系统使用它对候选结果重新计算距离,减少降维对最终结果的影响。
检索时,以 OpenAI 1536 维向量数据集举例:主向量会降到 256 维、4bit 量化,图遍历全程在这个更小的空间里执行;只有最后一小批候选,才会调用 1536 维、8bit 的辅助向量重排。
相比之下,HNSW SQ8 虽然也压缩了每个维度,但每访问一个节点,仍要读取并计算完整维度的向量。LeanVec 进一步减少了遍历阶段的数据量,因此在高维数据上更容易体现收益。
03
召回从 95% 到 99%,查询性能差多少
我们在四组数据集与规模组合下,将 SVS LeanVec(采用 LeanVec4x8 存储:主向量 4 bit、辅助向量 8 bit,分别测试开启 / 关闭 OOD、多组检索窗口大小)与 Milvus 中基于 Faiss 的 HNSW_SQ 索引(包含 FP16 和 SQ8 标量量化两种存储模式)做对比:

针对每一份数据集,我们遍历各索引的检索参数,采集不同召回率下的指标,绘制完整召回率 - QPS 曲线,分别在 k=10、k=100 两种返回条数下测试。固定并发为 100 个客户端线程,观测索引加载耗时、每秒查询数(QPS)以及 P99 延迟。
注:投影的训练方式也会影响性能。LeanVec 默认采用 OOD(分布外)模式,为底库向量和查询向量分别学习投影;ID(分布内)模式则使用共享投影,索引构建更快。

先看 95% 召回率:

四组数据中,SVS LeanVec 在每个数据集上都胜过了 HNSW FP16之外,SVS LeanVec 的吞吐量达到 HNSW SQ8 的1.40~1.84 倍,P99 延迟降低24%~38%。在此基础上,更高维度和更大规模的数据集(Bioasq 1024D、OpenAI 5M)上收益最大。
继续提高召回率到99%,HNSW SQ8 需要明显增加搜索开销,SVS的优势也会越来越明显。在Cohere 100 万数据集中,这种对比差异非常典型:

达到 99% 召回率时,HNSW SQ8 的吞吐量只剩 95% 时的约五分之一,P99 延迟超过原来的四倍。SVS LeanVec 的性能也有下降,但仍保持了 7,252 QPS,约为 HNSW SQ8 的4.6 倍。
同样的结论也适用于参与本次测试的更多其他数据集,并且在数据总量越大、维度更高的数据集种,表现会更为明显。可以看到,在本文使用的搜索设置下,HNSW SQ8 的吞吐量在接近召回率范围上限时急剧下降,在 OpenAI-500K、OpenAI-5M 和 Bioasq 数据集上甚至低于最高目标值。

改用 FP16 后,HNSW 的高召回率表现有所改善,但多数测试结果仍落后于 SVS LeanVec。
总的来说,99% 召回率下,Cohere 100 万的 QPS 分别为 4,873 和 7,252,SVS 高出约 49%;OpenAI 50 万则分别为 3,868 和 4,523,SVS 的 P99 延迟也更低。只有OpenAI 500 万是一个例外。在 99% 召回率下,HNSW FP16 达到 1,186 QPS、114.28 ms P99,SVS LeanVec 为 1,011 QPS、131.44 ms P99。
此外,还值得一提的是Bioasq 数据集,本次配置下,包括 HNSW FP16 在内,没有索引达到 99% 召回率;在能够达到的范围内,而SVS LeanVec 的吞吐量仍然领先。
要注意,这里的性能优势,是 Vamana 图结构、LeanVec 两级压缩、后置重排以及底层实现共同作用的结果,不是单一优化点带来的收益。
04
查询更快之外,还能省多少内存
速度只是性能的一面,另一面是维持该性能所需付出的资源成本。正如前文所说,内存是向量检索里最主要的开销项。我们可以先简单理解单向量内存占用(向量维度为 d):HNSW FP16 约占用 2・d 字节,HNSW SQ8 约为 d 字节,LeanVec4x8 的向量表示约为 d + d_reduced/2 字节,其中 d_reduced 是主向量降维后的维度;取 d_reduced=d/2 时才约为 d+d/4 字节。
由此不难看出,SVS 的内存占用会远低于 FP16,和 SQ8 接近。
除此之外,所有图索引都要存储每个节点的邻接列表(大约为:出度 × 4 字节 / 节点,Vamana 的度数,或是 HNSW 的 2・M),这部分开销和向量维度无关,在低维场景下影响更明显,高维、M 取值不大时占比会下降。
下面是实测数据:索引加载完成、对外提供查询时的常驻内存(Milvus vector_index 指标,不含 QueryNode 进程整体内存):

测试环境说明:SVS 配置为LeanVec4x8;Cohere、OpenAI 降维至 256 维,Bioasq 降维至 512 维。
补充说明:索引载入 QueryNode 的过程中,瞬时内存会高于稳态常驻值。但三类索引的这部分额外开销比例相近,因此对比结论不变:SVS LeanVec 的加载峰值内存始终低于 HNSW FP16,延续了稳态下的内存优势。
最终,在全部数据集上,SVS LeanVec 的内存占用接近 SQ8,只有 FP16 的57%~68%。在多数所测配置下,吞吐量可持平或优于 FP16,文中也列出了 FP16 更快的情况,并且和内存最低的 HNSW SQ8 处于同一量级(差距仅 10%–20%)。这意味着,在多数测试场景中,它用更少内存获得了更高吞吐量。
用吞吐量除以索引内存,就能直观看到这份内存资源带来的价值:每 GiB 索引内存可承载的 QPS,数值越高代表资源越划算。下面是 99% 召回率下的结果,高召回场景里内存与性能的差距会被进一步放大:

计算方式:QPS/GiB =(并发 100、99% 召回下的 QPS)÷ 索引常驻内存(GiB)。本表不含 Bioasq,该数据集下所有索引都无法达到 99% 召回;两组 OpenAI 数据集上,SQ8 均无法抵达 99% 召回。
可以看到,99% 召回率下,SVS LeanVec 每 GiB 内存的吞吐量是 HNSW FP16 的 1.5–2.3 倍。即使在 FP16 查询更快的 OpenAI 500 万数据上,SVS 也只需要 9.0 GiB 索引内存,而 FP16 需要 15.6 GiB。
内存、性价比之外,建索引耗时也需要一并考虑。关闭 OOD、使用 ID 模式时,SVS LeanVec 在四组数据上的构建与加载总时间比 HNSW FP16 缩短了22%~39%。启用 OOD 后,Cohere 和两组 OpenAI 数据的耗时与 FP16 接近,Bioasq 则从 791 秒增加到 1,532 秒。

因此,召回率目标在 95% 左右、又比较重视构建速度时,可以先尝试 ID;更在意高召回率下的查询吞吐量时,再比较 OOD 带来的收益是否值得额外构建时间。
05
如何在 Milvus 中使用 SVS Vamana
要使用SVS Vamana ,可以通过 Milvus 的 FAISS 接口配置:index_type 设为 FAISS,再用 faiss_index_name 指定 Vamana 图和向量存储方式。目前需要 Milvus、PyMilvus 3.0.0 或更高版本,并在源码构建时启用 SVS;默认构建不包含这一支持。
make USE_SVS=ON
假设已经创建 collection,并定义了向量字段,可以这样配置索引:
from pymilvus import MilvusClient
client = MilvusClient(uri="http://localhost:19530")
collection_name = "your_collection_name"
index_params = client.prepare_index_params()
index_params.add_index(
field_name="your_vector_field_name",
index_type="FAISS",
index_name="vector_index",
metric_type="COSINE",
params={
# 图最大度数为 64;主向量 4 位,辅助向量 8 位
# 主向量降至 256 维
"faiss_index_name": "SVSVamana64,LeanVec4x8_256",
"construction_window_size": 200,
"ood_training": True,
},
)
client.create_index(
collection_name=collection_name,
index_params=index_params,
)
client.load_collection(collection_name=collection_name)
_256 代表降维后的维度;省略这一后缀时,默认降至原始维度的一半。将 ood_training 设为 False,即可使用构建更快的 ID 模式。
搜索阶段通过 search_window_size 调整搜索范围,作用类似于 HNSW 的 ef。search_buffer_capacity 需要大于或等于它:
search_params = {
"params": {
"search_window_size": 100,
"search_buffer_capacity": 100,
}
}
初次测试可以从 LeanVec4x8 开始。高召回率下查询开销较大时,尝试提高主向量维度;希望进一步减少内存时,则可以降低维度,或改用辅助向量为 4 位的 LeanVec4x4。
另外,LVQ、LeanVec 压缩依赖 Intel CPU,AVX-512 环境收益最优。非 Intel 平台依然可以跑 SVS Vamana,但建议选用 FP32/FP16 / 普通 SQ8 存储。
06
选型建议

感谢 Intel 的 Andreas Huber、Dmitry Razdoburdin、Ethan Glaser、Igor Konopko、Rafik Saliev、Yue Jiao,Zilliz 的 Li Liu、Alexandr Guzhva,以及参与 SVS 集成与验证的 Knowhere 和 Milvus 团队。
注:本文来自Intel团队投稿,内容仅代表作者个人观点,不代表Milvus团队立场。
文章来自于“Zilliz",作者 "英特尔团队"。
相关主题
读完之后
加入 AINRK 交流群
了解加入交流群的方式,与更多 AI 从业者交流。




