向量数据库工程实践:从选型到索引调优
引言
做 RAG 的人大多经历过同一个落差:模型换了更强的,Prompt 也反复调了,答非所问的情况却依然存在。排查到最后,问题往往不在生成端,而在检索端——向量库召回的那几条上下文本身就不对。向量数据库看起来只是「存向量、查近邻」,但真正决定线上效果的,是分块策略、索引参数、过滤方式与更新机制这些工程细节。这篇文章不谈概念,只谈一套能落地的选型与调优路径。
一、先明确你到底需要哪种向量库
选型最容易犯的错,是先挑产品再想需求。建议先回答四个问题:数据量级是十万、千万还是上亿;写入是批量离线导入还是实时增量;查询是否带复杂元数据过滤;是否需要与关键词检索做混合。这四个答案基本就决定了技术路线。
- 十万级以内、已有 PostgreSQL:pgvector 足够,少一个组件就少一类故障。
- 千万级以上、写入以离线为主:考虑 Milvus、Qdrant 这类专用库,索引与分片能力更完整。
- 过滤条件复杂:把「向量检索与元数据过滤能否联合下推」作为第一考察项。有些实现是先粗召回再过滤,过滤选择性高时召回会被打穿。
- 强实时写入:关注写入放大与段合并策略,而不是只看查询 QPS。
一句话原则:能用已有数据库解决就不要引入新组件,规模真的顶不住时再换专用库。
二、索引选型:HNSW 与 IVF 的取舍
HNSW 是图索引,查询时在近邻图上贪心游走,延迟低、召回高,代价是向量和图的边都要常驻内存,写入时还要维护图结构。IVF 系列先把向量聚成若干簇,查询时只扫部分簇,配合 PQ 量化能把内存压到原来的几十分之一,但对分布变化敏感,且需要训练阶段。
- HNSW 关键参数:M 控制每个节点的连边数,越大召回越好、内存越高;efConstruction 影响建索引质量;efSearch 是查询期的召回与延迟旋钮,通常从 64 起步往上调。
- IVF 关键参数:nlist 决定簇数量,一般取数据量的平方根量级;nprobe 是查询扫描的簇数,直接决定召回与延迟。
- 实际做法:先用 HNSW 把效果跑通,作为效果基线;当内存水位超过 70% 时,再把冷数据切到 IVF-PQ,用一部分召回换容量。
调参不要凭感觉。准备一个 200~500 条的评测集,固定 embedding 模型,只改一个参数看召回与 P99 延迟的曲线,比任何经验值都可靠。
三、检索质量不止靠索引
很多团队把召回不准归因于索引,实际上分块与融合策略的影响更大。
- 分块:按语义边界切,单块控制在 300~600 token,相邻块保留 10%~20% 重叠,避免答案被切断。表格与代码块单独处理,不要混进正文。
- 混合检索:纯向量对专有名词、编号、错误码不敏感。BM25 与向量各取 top20,用 RRF 融合,通常能明显提升这类查询的命中率。
- 重排:召回阶段追求「不漏」,重排阶段追求「排得准」。用 cross-encoder 对 top30~50 重排后取前 5,成本可控、收益明显。
- 过滤前置:把租户、时间、权限这类高选择性条件放在向量检索之前,既保证隔离,也顺带降延迟。
四、上线后必须盯住的四件事
- 召回率回归:把评测集做成 CI 的一部分,每次换模型、换分块、换索引都跑一遍,防止「改一处、坏一片」。
- 内存与 P99:HNSW 的内存是隐性成本,监控要看到单集合的常驻内存与增长斜率。
- 删除与墓碑:频繁更新会产生大量失效段,需要定期 compaction,否则召回会悄悄退化。
- 版本化:embedding 模型换代后新旧向量不可混用,必须整库重建。设计之初就要预留 collection 版本号与双写切换路径。
小结
向量数据库不是「装上就完事」的中间件,它更像一个需要持续调优的检索系统。选型阶段看规模与过滤能力,索引阶段看内存与召回的平衡,效果阶段靠分块、混合检索与重排补齐,运维阶段则要盯住召回回归与版本切换。把这四层都做扎实,RAG 的「答非所问」大多会在检索端就被拦住,而不是留给模型去猜。
- 点赞
- 收藏
- 关注作者
评论(0)