docs/design/openviking-cuvs-benchmark-plan.md
本 benchmark 不追求单个“最高 QPS”数字,而是回答四个对集成决策更有用的问题:
cuVS 官方建议从 build time、search quality 和 search performance 三个维度比较向量索引; 本方案沿用这个原则,并增加 OpenViking 集成层与 mutation lifecycle 的测量。
参考:
| 名称 | OpenViking 配置 | 作用 |
|---|---|---|
| Native exact | backend=local, IndexType=flat | CPU flat 基线;精确性相对于其实际存储表示定义 |
| cuVS exact | backend=cuvs, algorithm=brute_force | GPU 在其 float32 表示上的精确检索 |
| cuVS ANN | backend=cuvs, algorithm=cagra | 在固定 Recall@K 下比较 ANN 性能 |
可以使用 cuvs-bench 的 HNSWlib 或其他算法作为算法级参考,但不能把它们当作
OpenViking 端到端基线,因为它们没有经过相同的过滤、label mapping 和记录回表路径。
cuVS 是 opt-in dense-search sidecar,不修改默认 backend,也不改变 native CPU
索引的默认 int8 量化。当前 cuVS GPU shadow 使用 float32。因此:
低精度 GPU 路线分开评估:先增加 cuVS float16 dataset/query,与 float32 ground truth 比较 Recall@K、延迟和显存;随后再评估 CAGRA int8 或 VPQ。native 的逐向量 scale int8 不能直接映射到 cuVS brute-force,若要求数值兼容,需要自定义 int8 distance/top-k 或候选召回后按 scale rerank,不能用简单 cast 代替。
OpenViking 仓库已经包含多类 benchmark,它们可以作为 cuVS 集成的质量与端到端 guardrail:
| 仓库目录 | 主要问题 | 在 cuVS 评测中的用途 |
|---|---|---|
benchmark/locomo/ | 长期对话记忆、跨 session QA | memory quality 回归;比较 local exact、cuVS exact、CAGRA |
benchmark/longmemeval/openviking/ | 信息提取、多 session/时间推理、更新与拒答 | 首选的长期记忆质量 benchmark |
benchmark/RAG/ | LoCoMo、Qasper、FinanceBench、SyllabusQA | 检查通用 RAG 质量和领域差异 |
benchmark/tau2/llm/ | memory 对 agent tool-task success 的贡献 | 端到端任务收益,不用于隔离 vector-search 性能 |
benchmark/custom/session_contention_benchmark.py | Server 混合负载的 QPS、延迟、错误率和积压 | 扩展为 local/cuvs backend matrix,测真实服务退化 |
这些质量 benchmark 不能替代 ANN benchmark。LoCoMo 只有少量长对话,LongMemEval-S 也以 500 个问题和每题有限 session 为主;单个 user 的向量规模通常不足以让 GPU 展现优势。它们最适合 验证“替换后端后答案质量不下降”,而不是证明最大 QPS。
领域内建议优先考虑以下公开 benchmark:
推荐最终报告采用三张相互独立的 scoreboard:
为了让公开 memory benchmark 达到能够体现 GPU 的规模,不应简单复制相同 memory。建议使用 LongMemEval 的可扩展 filler sessions、LongMemEval-V2 trajectory haystack,或者独立的真实噪声 corpus,把总索引扩展到 100K/1M/5M/10M,同时保留原题 evidence 作为 retrieval ground truth。
只测 native flat、cuVS brute-force 和 CAGRA 的 build/search,不包含 embedding、HTTP、 持久化写入和结果回表。这一层最容易解释 GPU kernel 与算法本身的收益。
测量:
通过 search_by_vector() 发起查询,包含 Python adapter、filter translation、label mapping
和记录回表,但使用预先生成的 query vectors,避免 embedding 服务掩盖检索差异。
这一层应作为当前 feature integration 的主要结果,因为它测量了用户实际经过的代码路径。
通过 OpenViking server 发起请求,分别报告:
full retrieval 只用于判断向量检索在总延迟中的占比,不用于证明 cuVS kernel 的加速比。
先跑能够代表 OpenViking 的 synthetic workload,再用公开 ANN 数据集交叉验证。
| 维度 | 建议取值 | 说明 |
|---|---|---|
| Vector count | 10K、100K、1M、5M、10M | 用来找到 GPU break-even point |
| Dimension | 128、768、1024 | 128 对齐 SIFT;768/1024 接近常见 embedding |
| Metric | cosine/IP,补充 L2 | cosine 在两端使用相同的 L2 normalization |
| K | 10、100 | 同时覆盖常见 retrieval 与较大候选集 |
| Query batch | 1、8、32、128、512 | 区分低延迟与吞吐场景 |
公开数据集优先使用 cuVS Bench 已支持且带 ground truth 的数据:
graph_degree={32,64}、
intermediate_graph_degree={64,96}、itopk_size={32,64,128}。过滤会影响 CAGRA 的搜索路径,也是本集成区别于裸 cuVS benchmark 的关键部分。
每个规模测试以下 selectivity:100%、10%、1%、0.1%,并包含两种分布:
每个过滤场景重新生成 filtered ground truth,同时报告 Recall@K、p95 和 QPS。不能用未过滤 ground truth 计算 recall。
当前实现保留 host shadow,并在 upsert/delete 后把 GPU index 标脏;下一次查询执行批量重建。 因此必须独立测量:
这个结果决定延迟重建适合的 workload 边界。steady-state search 图不能把 rebuild 时间平均掉, 否则会对写密集 workload 产生误导。
当前 Python integration 一次只提交一个 query,并在一次 GPU search 期间持有 index lock;同时 每次调用都会创建 query device array 并把结果同步回 host。因此:
先用较小但足以观察趋势的矩阵建立可重复 harness:
第一阶段结束后再决定是否下载 10M/100M 公开数据集,避免在 harness 尚未稳定时消耗大量 存储和 GPU 时间。
benchmark/cuvs/
├── README.md
├── generate_dataset.py
├── run_index_benchmark.py
├── run_collection_benchmark.py
├── configs/
│ ├── smoke.yaml
│ └── scale.yaml
└── plot_results.py
每次运行输出一个自描述 JSON/JSONL 文件,至少包含 git revision、backend、algorithm、全部参数、 dataset hash、hardware metadata、软件版本、raw latency samples 和 summary。图表必须能够只依赖 这些结果文件离线重建。