ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenViking 的 cuVS GPU 向量检索后端:配置、显存准入与本地向量搜索实战

OpenViking 的 cuVS GPU 向量检索后端:配置、显存准入与本地向量搜索实战 OpenViking 的 cuVS GPU 向量检索后端配置、显存准入与本地向量搜索实战【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenVikingOpenViking 的cuvs向量后端把 dense vector search 交给 NVIDIA cuVS同时保留本地后端的记录持久化、标量索引、稀疏检索和故障恢复是验证 GPU 检索链路而不重写整个向量数据库的轻量集成方式。本文覆盖 cuVS 后端的环境要求与安装、brute_force/CAGRA 算法配置、显存感知自动模式auto admission、微批处理micro-batching、GPU 显存占用估算、数据类型与原生索引行为边界以及最小功能验证方法读完后你可以直接在自己的 GPU 机器上配置并跑通 OpenViking 的 cuVS 检索链路。架构定位cuVS 只是索引库不是完整向量数据库在动手配置之前先理解这个后端在 OpenViking 中的职责边界。cuVS 是 NVIDIA 的 GPU 向量索引库只负责 dense vector top-k 搜索OpenViking 的本地引擎仍然负责 durable records、标量/路径索引、稀疏检索和崩溃恢复。从源码结构看这一边界在 cuvs_index.py 的模块文档字符串中被明确写出cuVS is an index library rather than a complete vector database. This module therefore owns only the dense vectors and their label mapping. OpenVikings existing local engine remains responsible for durable records, scalar indexes, sparse retrieval, and crash recovery.首版实现刻意追求正确性和简单的生命周期语义upsert 与 delete 更新 host 侧 snapshot 并使 GPU 索引失效下一次搜索时一次性批量重建 cuVS 索引。这样即使 cuVS 对不同索引类型没有统一的 update/delete 契约brute-force 和 CAGRA 都能兼容 OpenViking 的全部 mutation 路径。在 backend 工厂中cuvs与local、http等并列注册为合法 backendfactory.py 的_ADAPTER_REGISTRY将cuvs映射到CuVSCollectionAdapter。该 adapter 继承自LocalCollectionAdapter在构造时把配置注入为dense_search: {backend: cuvs, ...}的 collection 配置见 local_adapter.py。所有配置字段的默认值、取值范围与约束则由 Pydantic 模型 CuVSConfig 统一定义且model_config {extra: forbid}意味着配置中出现未声明的字段会直接报错。环境要求与安装运行 cuVS 后端需要满足以下条件Linux x86_64 或 aarch64可见的 NVIDIA GPUcuVS 26.06 预编译包要求 Ampere 或更新架构CUDA 12.2安装与本机 CUDA 大版本匹配的 Python 包Python 3.11cuVS 26.06 的 Python wheel 要求CUDA 12 环境pip install -e . pip install cuvs-cu12 cupy-cuda12x[ctk] --extra-index-urlhttps://pypi.nvidia.comCUDA 13 环境pip install -e . pip install cuvs-cu13 cupy-cuda13x[ctk] --extra-index-urlhttps://pypi.nvidia.comCuPy 的[ctk]extra 会安装 cuVS Python 互操作路径所需的 CUDA toolkit headers即使宿主机已有 CUDA driver、但没有完整 toolkit也建议保留该 extra。配置从 brute_force 精确检索到 CAGRA 近似检索先用 brute_force 跑通精确检索最小可用的 cuVS 配置如下对应 CuVSConfig 中的默认值组合{ storage: { workspace: /data/openviking, vectordb: { backend: cuvs, distance_metric: cosine, cuvs: { algorithm: brute_force, dtype: float32, max_concurrent_gpu_searches: 1, micro_batching_enabled: false, fallback_to_native: true, filter_cache_size: 16 } } } }各参数的含义与默认值均来自CuVSConfig源码定义参数类型/取值默认值说明algorithmbrute_force/cagrabrute_force先用 brute_force 做功能验证大规模场景再用 cagra 做近似检索dtypefloat32/float16float32GPU dataset 和 query 的数据类型。float16 是显式 opt-in 的直通 cast需自行 benchmark recall不影响原生 CPU 量化build_paramsdict{}透传给 cuVS CAGRAIndexParams的额外关键字参数search_paramsdict{}透传给 cuVS CAGRASearchParams的额外关键字参数fallback_to_nativebooltruesparse/hybrid 检索及 cuVS dense top-k 之外的操作回落到 OpenViking 原生本地索引filter_cache_sizeint ≥ 016GPU 上保留的最近使用 scalar-filter bitset 缓存数量0 表示禁用缓存max_concurrent_gpu_searchesint ≥ 11每个索引的在途 cuVS GPU search 调用上限host 侧 filter 与 snapshot 工作仍并发micro_batching_enabledboolfalse把兼容的并发 cuVS dense 查询合并为一次 matrix-search 调用micro_batching_max_batch_sizeint 1–88一次 cuVS search 调用最多携带的兼容查询数micro_batching_max_wait_msfloat 0–1001.0scheduler 为收集兼容请求主动等待的窗口毫秒0 表示不主动等待auto_enableboolfalsebackend 为local时GPU 空闲显存充足则自动启用 cuVS dense 搜索auto_memory_reserve_mbint ≥ 01024auto 准入预算之外保留的 GPU 空闲显存MiBauto_memory_safety_factorfloat ≥ 1.02.0乘在估算的 vector/graph/build/filter 显存之上的保守系数auto_filter_native_thresholdint ≥ 02000过滤查询候选数不超过该值时路由到 native 索引0 关闭该路由auto_path_filter_native_thresholdint ≥ 0200路径过滤使用更低的 native 路由阈值0 让全部路径过滤留在 cuVSauto_background_rebuildboolfalse由合并后的后台 worker 构建 dirty 状态的 auto-cuVS snapshot期间查询走 native 索引auto_rebuild_debounce_msint ≥ 0500连续 mutation 后触发后台 rebuild 前的静默窗口配置模型还内置了 micro-batching 的一致性校验validate_micro_batching开启micro_batching_enabled时若algorithm不是brute_force或max_concurrent_gpu_searches不等于 1配置加载即抛错。数据量增大后切换到 CAGRACAGRA 构建与查询参数可以直接传入 cuVS 原生接口{ storage: { vectordb: { backend: cuvs, cuvs: { algorithm: cagra, build_params: { graph_degree: 64, intermediate_graph_degree: 128, build_algo: nn_descent }, search_params: { itopk_size: 64, search_width: 1 } } } } }build_params中的graph_degree、intermediate_graph_degree不只是透传项——它们直接进入 auto 模式的显存估算graph_degree决定常驻 graph 大小intermediate_graph_degree决定构建期 intermediate graph 大小。显存感知自动模式如果希望保留local为默认 backend、只在 GPU 有足够空闲显存时自动启用 cuVS可以打开以下开关{ storage: { vectordb: { backend: local, cuvs: { auto_enable: true, algorithm: brute_force, auto_memory_reserve_mb: 1024, auto_memory_safety_factor: 2.0, auto_filter_native_threshold: 2000, auto_path_filter_native_threshold: 200, auto_background_rebuild: true, auto_rebuild_debounce_ms: 500 } } } }注意一个实现细节从源码结构看auto_enable并不是把 backend 换成cuvs而是 LocalCollectionAdapter.from_config 检测到该开关后向 collection 注入dense_search: {backend: auto_cuvs, ...}的 collection 级配置使 dense 检索在每次查询时做 GPU 准入判断。每次 lazy build/rebuild 前auto 模式会读取当前空闲显存并根据配置的dtype估算 device vector payload、CAGRA graph/intermediate graph如适用和 filter-bitset cache再乘以auto_memory_safety_factor同时保留auto_memory_reserve_mb。这套估算逻辑实现于 estimate_cuvs_memory其公式与下文GPU 显存占用一节一致向量字节数按N * dimension * (4 or 2)计CAGRA 再加N * graph_degree * 4与N * intermediate_graph_degree * 4filter cache 按ceil(N/32) * 4 * filter_cache_size计。如果预算不足或者 cuVS/GPU 不可用本次查询继续使用未改变的 native indexcuVS index 保持 dirty后续查询会在显存释放后重新尝试。通过 admission 后若仍遇到 GPU allocation failure也会回退 native。显式配置backend: cuvs时仍保持 fail-fast不经过这层自动判断。同一进程内的 local collection 会按 GPU 协调 build 和 admission避免两个并发 build 都基于同一份过期 free-memory 观测通过准入。不同 GPU 彼此独立warmed search 也不会被这个协调器串行化。auto 模式还会使用 native scalar index 返回的候选数做 filtered query 延迟路由候选数不超过auto_filter_native_threshold时使用 native vector recall路径过滤采用更低的auto_path_filter_native_threshold因为宽 URI 子树的 Trie 遍历和 bitmap union 本身可能占主要开销。默认阈值分别为 2,000 和 200设为 0 可关闭对应路由。阈值与硬件、维度和工作负载有关。显式backend: cuvs对支持的 dense query 仍固定使用 cuVS。auto_background_rebuild默认关闭。开启后连续 mutation 会按auto_rebuild_debounce_ms合并worker 在不持有跨后端 mutation 锁的情况下构建新的 immutable GPU snapshot。默认 500 ms 用于避免普通 ingest 的中间 batch 反复触发构建。对于边界明确、由多次调用组成的 bulk load可把所有写入放在async with backend.bulk_ingest(ctxctx):scope 内native 可见性和持久化仍按每次调用推进但 derived GPU maintenance 会延迟到最外层 scope 退出后只调度一次。该 scope 只是 maintenance hint不提供事务或原子性退出 scope 只负责调度 rebuild本身不等待 GPU ready。vector backend benchmark 会额外在正式计时 search 前显式等待最终 snapshot无法识别 bulk 边界的调用方仍可按实际 batch 间隔调整 debounce。Auto 仍为显式启用未开启 Auto/background rebuild 时该 scope 对派生维护为 no-op不改变原生 CPU 检索、写入与 dtype 行为。snapshot dirty 期间查询直接使用当前 native index不会把 GPU build 时间转化成请求排队时间。worker 只在 record generation 仍匹配时原子提交 label layout 和 GPU snapshot过期 build 会被丢弃并只重建最新一代。GPU 显存占用使用默认的dtype: float32时brute-force 的主要常驻 device payload 为N * dimension * 4bytes。显式设置dtype: float16后device payload 降为N * dimension * 2bytes。CAGRA 还需要约N * graph_degree * 4bytes 保存 graph构建期间可能需要N * intermediate_graph_degree * 4bytes 的 intermediate graph。每个缓存 filter bitset 约占ceil(N / 32) * 4bytes。这些公式与 estimate_cuvs_memory 的逐项计算一一对应说明文档中的显存预算并非经验数字而是 auto admission 真实使用的估算器。之前的 index-only 测试使用cudaMemGetInfo记录 build 前后的显存增量下表每项均为 5 个干净进程的中位数数据集cuVS 算法实测 GPU 增量100K x 768Dbrute-force294 MiB1M x 768Dbrute-force2.9 GiB100K x 1024Dbrute-force392 MiB1M x 1024Dbrute-force3.9 GiB1,183,514 x 100Dbrute-force452 MiB1,183,514 x 100DCAGRA872 MiB这些数值是 build 完成后的常驻增量不是采样得到的 peak VRAM。allocator 状态、cuVS 版本、CAGRA 参数、query batch 和并行 GPU workload 都可能进一步提高峰值它们也不包含这些进程在 build 前观测到的约 327 MiB CUDA runtime/context 基线。因此 auto 模式会先初始化 runtime、读取剩余空闲显存再应用保守 safety factor 和独立 reserve而不会只按 vector payload 准入。距离语义与原本的 OpenViking 本地后端保持一致cosine 会先做 L2 归一化再执行 inner productL2 的返回分数仍为1 - squared_l2分数越大越相似。数据类型与原生索引行为启用 cuVS 不会改变 OpenViking 的默认后端也不会重写原生 CPU 索引。正常的 collection metadata 仍为VectorIndex.Quantint8因此 native fallback 继续使用现有的、带逐向量 scale 的 int8 量化。与此同时cuVS device dataset 和 query 使用配置的dtype默认是 float32也可以显式选择 float16。host record shadow 保存预处理后的 Python 浮点值仅在创建 device dataset 和 query 时将它们 cast 为配置的 dtype。cuVS Python brute-force API 支持这两种 device 表示但不能直接表示 OpenViking 的 scaled-int8 record 格式。所以两条 dense search 路径不是等内存、等数值语义的比较native 是在 CPU 量化表示上的精确检索cuVS brute-force 是在保留的 float32 或 float16 device 表示上的精确检索两者可能出现少量 score 或 neighbor ordering 差异。Benchmark 必须同时报告两边的数据类型和 RecallK不能将结果描述为 equal-dtype 或 equal-memory。这是首版 opt-in 集成的有意边界现有 CPU 行为保持不变。auto 模式会根据 filter 候选阈值在两种表示之间选择要求固定数值表示的应用应使用显式 backend或将 native 路由阈值设为 0。GPU 低精度存储是显式能力不做隐式 cast。设置dtype: float16会把 cuVS dataset 和每个 query 同时 cast 为 float16brute-force 与 CAGRA 都不使用混合 query/index dtype。这是存储 cast不是逐向量量化必须以默认 float32 为 ground truth 报告 RecallK。与 native 兼容的 int8 仍需单独设计因为 OpenViking 使用逐向量 scale而 cuVS brute-force 不能直接接收这种 scaled-int8 表示。CAGRA int8 或 PQ compression 也应作为近似模式单独报告 recall/latency/memory frontier。GPU 索引使用 immutable snapshot 和可复用的 cuVS resource/CUDA stream。host 侧 filter 与 snapshot 工作可以并行但max_concurrent_gpu_searches默认是 1单 query brute-force 通常受显存带宽限制并发 kernel 可能互相争抢带宽、反而降低吞吐。只有在目标 GPU 与真实 workload 上测得收益后才建议显式调大该值。可选的请求微批处理精确 brute-force 路径可以把兼容的并发请求合并为一次 cuVS matrix-query 调用{ storage: { vectordb: { backend: cuvs, cuvs: { algorithm: brute_force, max_concurrent_gpu_searches: 1, micro_batching_enabled: true, micro_batching_max_batch_size: 8, micro_batching_max_wait_ms: 1.0 } } } }scheduler 只会合并使用同一个 immutable GPU snapshot、同一个 prepared filter、同一个实际 top-k 的请求GPU 返回的每一行会映射回原请求因此标量/路径过滤和结果条数语义不变。当 immutable snapshot clean、属于当前 generation且请求没有 filter 或命中已准备好的 device filter cache 时可走 warm admission fast path。该路径会 pin snapshot/filter并在 caller 不获取 device-search gate 的情况下直接入队。dirty、cold 或 stale snapshotdevice filter cache miss/eviction、rebuild 和 device filter materialization 仍走 gated preparation。准备完成后caller 先入队并释放 gate再等待结果只有 micro-batch worker 会在持有 device-search gate 时执行 matrix search所以 caller 不会持 gate 等待 worker。collection window 是延迟与吞吐的权衡。它只限制 scheduler 为收集兼容请求而主动等待的时间从最早的 compatible request 起最多主动等待配置值它不是 enqueue-to-dispatch latency 上限。worker 调度、前一个 GPU call 或 gated device preparation 都可能使实际 dispatch 更晚。并发充足时最多由配置上限数量的 query 共用一次 GPU call。参数约束如下micro_batching_max_batch_size范围为 1 到 8micro_batching_max_wait_ms范围为 0 到 100 ms设为0表示不主动等待但仍可 opportunistically 合并已经同时在队列中的兼容请求micro-batching 仅支持algorithm: brute_force并要求max_concurrent_gpu_searches: 1。这些约束在配置层就有强制CuVSConfig.validate_micro_batching 会在algorithm ! brute_force或max_concurrent_gpu_searches ! 1时拒绝配置。该能力默认关闭是 OpenViking 自己的 micro-batcher不等同于 cuVS 官方名为 Dynamic Batching 的组件。首版只支持 exact brute-forceCAGRA 和并发 dispatch 多个 batch 会在独立验证后再开放。Auto 模式也可使用这些选项但被路由到原生 CPU 的请求不会进入 GPU batch queue。single-row 与 matrix-query 在近似并列分数处可能有顺序差异调参时应同时验证结果集合重合度和 score。最小功能验证仓库提供的 smoke test 不依赖 embedding 或 VLM 服务python examples/cuvs_smoke.py # 验证 CAGRA 图索引 python examples/cuvs_smoke.py --algorithm cagra # 验证显式 float16 路径 python examples/cuvs_smoke.py --dtype float16examples/cuvs_smoke.py 内部通过get_or_create_local_collection创建一个 4 维向量、带account_idstring与uripath字段的cuvs_smokecollection并在dense_search配置中启用backend: cuvs与fallback_to_native: True。核心调用方式如下from openviking.storage.vectordb.collection.local_collection import ( get_or_create_local_collection, ) collection get_or_create_local_collection( meta_data{ CollectionName: cuvs_smoke, Fields: [ {FieldName: id, FieldType: string, IsPrimaryKey: True}, {FieldName: vector, FieldType: vector, Dim: 4}, {FieldName: account_id, FieldType: string}, {FieldName: uri, FieldType: path}, ], }, config{ dense_search: { backend: cuvs, algorithm: brute_force, fallback_to_native: True, } }, ) collection.create_index( default, { IndexName: default, VectorIndex: {IndexType: flat, Distance: cosine}, ScalarIndex: [account_id, uri], }, ) collection.upsert_data( [ {id: a, vector: [1, 0, 0, 0], account_id: demo, uri: /docs/a}, {id: b, vector: [0, 1, 0, 0], account_id: demo, uri: /docs/b}, ] ) result collection.search_by_vector( default, dense_vector[1, 0, 0, 0], limit2, filters{op: must, field: account_id, conds: [demo]}, ) assert [item.id for item in result.data] [a, b] collection.close()这段代码演示了 cuVS 后端的完整闭环collection 创建传入dense_search配置→ 索引声明flat cosine附带标量索引→ upsert → 带标量过滤的 dense 检索 → 断言结果顺序 → 关闭。注意检索仍走 local collection 的统一 APIcuVS 只在 dense 分支上被透明调度。配置行为还有专门的单测覆盖tests/vectordb/test_cuvs_config.py大规模性能对比可参考 benchmark/cuvs/ 下的 collection、index 与服务并发 benchmark 脚本及汇总工具以及通用的 vector backend 计时框架 benchmark/vectordb_perf/。更深入的设计背景可阅读 cuVS 集成设计文档。当前阶段的限制cuVS 只接管 pure dense searchsparse/hybrid query 在fallback_to_nativetrue时走原生本地索引。local 集成通过 native scalar/path index 生成 prefilter因此继承原生 DSL、date_time、geo_point和 path depth 的过滤语义而不是在 Python 重复实现。每次 GPU rebuild 会向 native engine 注册一次 cuVS label 顺序。新过滤条件直接复用 native scalar/path index 的 bitmap再投影为 cuVS row bitset不再用 Python 扫描所有 host-side records。filter_cache_size会保留最近使用的 GPU bitset 或 native 路由决策并在数据更新时失效auto 模式在进入 cuVS search 前预判候选数不同的首次过滤条件可通过 native engine 的共享读路径并行计算命中已缓存的 native 路由时则直接进入 native index。generation 校验会阻止跨 mutation 计算出的旧结果写入路由缓存。GPU index 使用 immutable snapshot 和可复用的 cuVS resources/CUDA stream默认关闭的 micro-batching 可让 compatible warm request 绕过 caller 侧 gate 入队并由唯一持有 device-search gate 执行 matrix search 的 worker 合批。mutation 和 snapshot commit 使用跨后端写锁。默认情况下每次 upsert/delete 后仍由下一次查询同步重建开启auto_background_rebuild后dirty 期间查询走 native连续写被合并为后台重建。cuVS 索引不作为权威持久化数据进程重启时会从 OpenViking 本地 store 重建因此不受 cuVS 跨版本序列化格式变化影响。brute_force适合功能对齐和 ground truthCAGRA 的 graph/search 参数需要在后续结合召回率、QPS、延迟和显存进行调优。落地建议小结先验证、后近似用brute_forcedtype: float32跑通 smoke test 确认 GPU 链路再切 CAGRA 并调build_params/search_params。显存不确定时用 auto 模式保留backend: local并打开auto_enable让 OpenViking 按显存预算自动准入失败自动回落 native生产上要求固定数值行为时再用显式backend: cuvs。调吞吐再开 micro-batching仅在确认 GPU 显存带宽瓶颈、且 workload 并发充足时开启并同时验证 RecallK 与结果集合重合度。尊重配置约束CuVSConfig使用extra: forbid并内建 validator拼错字段名或违规组合如 micro-batching CAGRA会在配置加载阶段直接报错而不是静默降级。【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表