向量数据库召回率暴跌 0.33 的排查复盘VexDB-Lite 并行磁盘构建的缓存键 Bug 是如何被定位的【免费下载链接】VexDB-LiteA cross-platform vector database, which can be integrated into existing databases as a plugin.项目地址: https://gitcode.com/gh_mirrors/ve/VexDB-LiteVexDB-Lite 是一款可嵌入 PostgreSQL、DuckDB 和 SQLite 的跨平台向量数据库插件三个后端共享同一套图索引算法与量化内核。2026 年 7 月我们在 Cohere-1M 数据集的并行磁盘构建复测中发现查询召回率Recall10从 0.99 区间暴跌到 0.33。本文完整复盘这次排查三个假说、两次否定、一个隐蔽的距离缓存键错误以及它是如何被一组0 worker 串行对照钉死的。事故现场一次完美的构建0.33 的召回率 先看事故数据Cohere-1M768 维15 个并行 worker直接磁盘构建指标plainRaBitQ compact构建是否完成✅ 成功✅ 成功构建期 CPU峰值约 1478%12~14.7 核并行同左崩溃 / OOM无无Recall100.33950.3393正常基线是什么完整内存建图的控制组 recall10 稳定在 0.996。0.33 意味着 top-10 结果里约 7 个是错的——对以图搜图、以文搜文这类应用来说这个索引基本不可用。值得注意的一个细节plain 和 RaBitQ 两种模式几乎同时跌到 0.339。两者量化编码方式完全不同却掉得一样低——这强烈暗示问题出在它们共同的图构建输入上而不是量化本身。这个线索后来被证实非常关键。排查阶段一确认 worker 真的在干活 第一反应是怀疑并行没生效。但锁等待和 CPU 数据直接否定了这个假说15 个 worker 全程几乎不排队构建期稳定占用十几个核。并行架构没问题问题在别处。排查阶段二cosine 归一化不一致——第一个真凶深挖向量读取路径后发现leader 进程在插入前对向量做了 detoast、对齐和 cosine 单位化而 PG 并行 worker 却把原始向量直接送进了图插入。Cohere 的原始向量并非单位长度于是图里混用了单位化和原始长度两种表示查询端按单位化向量遍历距离自然全乱。把向量预处理统一到 leader/worker 共用的回调后recall 拉回0.9686plain/ 0.9397RaBitQ——从 0.33 起死回生但仍低于 0.99 的质量闸门。排查没有结束。排查阶段三一个看起来有效的错误方向 ⚠️剩余的召回损失曾被归因于并行冷启动多个 worker 从空图同时插入早期骨架拓扑偏弱。据此团队加了一批串行种子先行建图数据确实好转串行种子数Recall10Cohere-100K8,1920.97451,2000.98876,8000.991 ✅ 过闸眼看就要收工一个对照实验推翻了整个方向0 worker 串行直接磁盘构建recall 只有 0.973而同一数据的完整内存建图是 0.996。这是整个排查中最有决定性的一组数字串行也不达标 → 并行冷启动不是必要条件DiskStore磁盘存储路径才是共同变量。种子只是掩盖了 DiskStore 的真实错误。真正的根因距离缓存键张冠李戴 顺藤摸瓜根因定位到反向边裁剪逻辑源码见 graph_index_algorithm.h。图索引插入新节点时除了为新节点选邻居还要更新旧节点的反向边旧邻居的邻居槽位满了就需要裁剪。裁剪要比较候选向量到各邻居的距离而 DiskStore 为了省算力会按(节点 A ID, 节点 B ID)这对 ID 缓存两两距离。Bug 就在这裁剪用的候选向量取自新节点缓存键却沿用了旧节点的 IDself.id。于是缓存中已经存在的旧节点 ↔ 旧邻居距离被直接当成新节点 ↔ 旧邻居的距离复用——向量和 ID 不属于同一个节点距离张冠李戴。基于错误距离做的裁剪决策让图长出了大量错误边、丢掉了关键边拓扑被悄悄削弱召回率随之下降。这也解释了所有此前的困惑为什么内存模式一直正常MemStore 根本没启用这组成对距离缓存缓存不生效错键无害为什么 plain 和 RaBitQ 同时中招两者共用同一个insert_on_disk()路径为什么加大种子能修复串行种子阶段恰好避开了并发写缓存的窗口召回上去了但它治标不治本。修复与效果召回率回到 0.99 区间 ✅修复很克制让 DiskStore 的缓存键与候选向量统一使用新节点 IDnew_point_id并删除了此前临时加的 7.6 万串行种子恢复从第一条数据直接磁盘并行的最终架构。场景Cohere修复前修复后100K / 3 workers / 无种子plain0.9730.9941M / 15 workersplain0.96860.9939100K / 3 workersRaBitQ compact0.9440.993完整内存控制组基准0.9960.996排查中顺手修掉了第二个独立问题memory_modecompact曾用量化后的近似距离建图造成额外拓扑损失。最终语义收窄为建图阶段一律用原始向量精确距离全部 worker 结束后再批量编码为 PQ/RaBitQ code让 compact 只改变存储格式不改变图质量。给使用者的三条实用建议 先建对照组再谈异常。任何 recall 波动先测一遍同数据的完整内存 / 串行基线本次是 0.996正常值有了退化幅度才谈得上可量化排查方向才不会跑偏。区分索引状态与索引质量。构建成功、indisvalidtrue只说明格式合法不代表拓扑正确。可用vexdb_index_info()查看索引实际生效的量化器与存储模式细节见 README.md。用回归闸门守住质量底线。本次新增的直接磁盘并行回归用例graph_index_plain_parallel_disk.yaml固定低内存预算、覆盖 1/3 worker、recall 与重启读取让同类 Bug 无法静默溜进主干。复盘总结四条值得记住的经验症状 ≠ 根因。召回率低是果中间隔着归一化、缓存键等多个因数据输入路径和图拓扑路径要分开验证。能提召回的补丁不等于根因修复。串行种子让 0.974 → 0.991差点让一个存储层 Bug 带着解决方案上线。对照组是排查中最强的工具。0 worker 串行只有 0.973一行数据直接否定了持续多天的并行冷启动方向。缓存会放大错误。距离缓存本身没有错错在缓存键必须和它代表的向量是同一个节点——任何按 ID 复用计算结果的优化都要保证 ID 语义与数据一致。相关代码与文档根因分析含完整排查时间线docs/analysis/2026-07-24-pg-parallel-build-root-cause.md并行磁盘构建设计与细粒度锁方案docs/design/2026-07-24-pg-parallel-disk-build-architecture.mdCohere-1M 远程复测原始报告docs/reports/2026-07-24-cohere-1m-parallel-retest.md反向边裁剪源码缓存键修复位置graph_index_algorithm.h功能与配置说明documentation/features.md【免费下载链接】VexDB-LiteA cross-platform vector database, which can be integrated into existing databases as a plugin.项目地址: https://gitcode.com/gh_mirrors/ve/VexDB-Lite创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考