首页 / 文章

优化HNSW索引并扩展向量搜索以用于生产环境中的RAG系统

了解 HNSW 的 M 和 ef 参数如何权衡召回率、延迟和内存使用,学习如何在 Chroma 中设置这些参数,以及何时通过垂直扩展或分片的方式来扩展向量数据库。

发布者:REACTAPP.TOP阅读约 4 分钟982 词

来源: **15.**HNSW & Vector Database Tuning for Production RAG

一个拥有数千个向量的检索增强生成(RAG)原型,在几乎任何配置下都能实现即时响应。当向量数量增长到数百万时,延迟和资源消耗开始成为主要问题,索引配置也变成了需要重点考虑的生产环节。本指南将介绍最重要的两个HNSW参数、如何在Chroma中设置它们,以及如何判断仅靠调整参数已不够用、系统需要进一步扩展的时机。

决定几乎所有功能的两个HNSW参数

调整 HNSW(分层可导航小世界)图结构时无需掌握其完整理论。该索引会将每个向量与多层结构中的邻近向量相连,查询时则沿着此图寻找最近的邻居。有两个参数决定了该图的结构以及查询的路径。如需更多背景信息,请参阅我们关于向量数据库的工作原理,从嵌入模型到混合搜索的解读文章。

M:每个节点的最大连接数

M决定了图中每个节点可保留的邻居连接的最大数量。

  • M 值较低:连接数减少,索引规模变小,内存占用降低且查询速度更快,但由于可搜索的有效候选路径较少,召回率也会下降。
  • 高 M 值:每个节点的链接更多,内存占用更大,索引规模也更大,构建速度更慢。查询速度会有所下降,但由于图结构提供了更多通往真正最近邻的路径,检索精度会提高。
  • 在构建索引时 M 值是固定的,因此之后若要更改该值则必须重新构建索引。

    ef:每次搜索的努力程度

    ef 控制索引在查找查询的最近邻时会考虑多少候选项。

    • 低 ef 值:检查的候选项较少,因此检索速度较快,但可能会遗漏相关文档,导致准确率下降。
    • 高 ef 值:检查的候选项更多,因此检索速度较慢,但得到的结果集会更接近真正的最近邻。

    许多引擎将此分为构建时的参数,用于控制图结构的构建精细程度,以及搜索时的参数,通常无需重新构建即可更改,因此这是最容易用来试验的参数。

    平衡精度、速度与内存

    HNSW的调优需要在精度、速度和内存之间进行三方权衡。对于常见的项目阶段,这些组合可作为合理的起点,其中ef表示搜索时的参数值:

    +----------------+----+-----+----------+
    | Use Case       | M  | ef  | Priority |
    +----------------+----+-----+----------+
    | Prototype      | 16 | 40  | Speed    |
    | Production     | 16 | 100 | Balanced |
    | High accuracy  | 32 | 200 | Accuracy |
    +----------------+----+-----+----------+
    

    可将它们视为基准用于对比:在每次更改前后,针对具有代表性的查询来测量召回率和延迟。

    在Chroma中设置HNSW参数

    不同的向量数据库对这些参数的设置方式各不相同。在Chroma中,可以在创建集合时将它们作为集合元数据传递。下面的示例将M设置为16,构建时的ef设置为100,搜索时的ef设置为50:

    #Chroma-HNSW Settings
    collection=client.create_collection(
    name='new_collection',
    metadata={
    'hnsw:M':16,
    'hnsw:construction_ef': 100,
    'hnsw:search_ef': 50
    }
    )
    

    在较新版本的Chroma中,这种元数据键的形式可能会发生变化,因为该版本还提供了专用的配置对象,因此请查阅对应版本的文档。由于这些参数会被嵌入到图中,因此应在导入数据之前设置M和构建时的ef值。

    当仅靠调优已不够时

    即便经过精心调优的索引最终也会达到性能上限。当数据检索时间经常超过100毫秒时,常见的原因就是索引已无法完全容纳在内存中,而进一步的参数调整也无法解决这一问题。一个粗略的估算方法是:原始向量存储的空间需求为向量数量乘以每个向量的维度,再乘以32位浮点数所需的4字节;而HNSW图还会带来随M值增长的额外开销。此时就需要考虑扩展方案,具体有两种形式。

    垂直扩展

    对于包含大约500万到1000万个向量的数据集,通常首先考虑在现有机器上增加RAM或CPU资源。有了足够的内存后,整个索引就能全部存储在RAM中,从而恢复快速的检索速度并提升整体效率。

    垂直扩展无需进行架构或代码上的修改,但单台机器存在内存上限,而且规模更大的实例成本会迅速上升。

    水平扩展

    当向量数量超过约1000万时,水平扩展成为更实际的选择。此时数据会被分片处理,即把数据分散到多台实例中,每片负责存储和查询自己的那部分数据。

    这种方式消除了单台机器的限制,但代价是复杂性:每个查询都需要分发到各个分片上,随后还需将各分片的部分结果合并为一份排序后的列表,这会增加延迟并带来更多的运维工作。

    关键要点

    • M值会影响模型性能:数值越高,召回率和内存使用量越大,且调整该值需要重新构建模型。
    • ef值会影响搜索效果:提高搜索时间参数是牺牲延迟以提升召回率的最低成本方式。
  • 从平衡的配置开始,例如 M 16 配合 100 的搜索 ef 值,然后针对自己的查询进行基准测试。
  • 大多数生产环境中的 RAG 系统只需通过索引调优和垂直扩展即可运行;分片虽然功能强大但很少需要,因此仅用于那些确实超出单台机器处理能力的集合。