Milvus、索引算法选择、度量类型、逻辑/物理 Collection 分层、BM25 稀疏向量、推荐引擎、统计与日志。我想解决的不是“把向量塞进库里”,而是“怎么把向量资产组织成真正可检索、可管理、可演进的基础设施”。
上一篇我写了向量化模块,核心观点是:
Embedding 不是一次 API 调用,而是在生产后续检索系统依赖的向量资产。
那有了向量资产以后,接下来的问题就是:
这些向量应该怎么存,怎么组织,怎么建索引,怎么被后续模块稳定消费。
很多教程到这里会一句话带过:
- 连接向量库
- 创建 collection
- 插入向量
- 完成
这个流程对 demo 当然够了。
但一旦你真的想把系统做成工程项目,很快就会发现,索引层其实远远不只是“写进库里”:
- Collection 应该怎么划分
- Index 和 Collection 是不是一个概念
- 算法应该怎么选
- 度量类型应该怎么定
- 维度不同的模型能不能混放
- 稀疏向量怎么和稠密向量共存
- 索引怎么恢复、怎么统计、怎么记录操作历史
所以在 RAG Pipeline Hub 里,我把向量索引单独做成了一个模块。
这篇文章,我就专门聊聊这部分设计。
项目地址:
- GitHub:
https://github.com/qingni/rag-pipeline-hub
为什么索引层不是简单的向量入库
很多人刚接触 RAG 时,会把索引层理解成一个纯存储问题:
拿到向量 -> 写进数据库 -> 搜索
但从工程角度看,这个理解太简化了。
因为索引层真正负责的,其实是下面这些事:
- 管理向量的物理存储结构
- 决定搜索性能和近似精度的平衡
- 组织不同知识库、不同模型、不同维度的数据
- 为后续混合检索预留稀疏表示能力
- 记录索引状态、统计、历史和操作行为
也就是说,它是整个 RAG 系统的检索基础设施层。
如果这层设计混乱,后面检索模块再聪明,也会被基础设施限制住。
我为什么把索引模块从“搜索模块”里拆出来
这个项目里,向量索引模块和搜索查询模块是拆开的。
这是一个我比较坚持的设计。
原因很简单:
- 索引模块关心的是“怎么建、怎么存、怎么管”
- 搜索模块关心的是“怎么查、怎么排、怎么提质量”
这两者强相关,但职责并不一样。
我更愿意把它们理解成:
- 向量索引模块:
Write / Manage - 搜索查询模块:
Read / Retrieve
这种拆法的好处是很明显的:
- 索引逻辑不会和搜索逻辑搅在一起
- 方便单独管理 Collection、Index、统计和推荐
- 后面要替换检索策略时,不需要连索引管理一起改
- 整个系统的职责边界更清晰
这也是为什么我不想把“建索引”和“做搜索”全堆在一个 service 里。
这个模块在整条链路里负责什么
向量索引模块位于向量化之后、搜索查询之前。
它负责的事情可以概括成一句话:
把向量化结果转换成真正可搜索的检索基础设施。
从流程上看,大致是这样:
选择向量化结果
-> 推荐索引配置
-> 选择算法和度量类型
-> 创建 / 复用 Collection
-> 写入稠密向量和稀疏向量
-> 建立索引
-> 保存元数据、统计和操作日志
所以这个模块的输出,不只是“Milvus 里多了一批数据”,而是:
- 可管理的 Index 记录
- 可复用的 Collection
- 可追踪的统计与日志
- 可供搜索模块读取的检索结构
为什么 Collection 和 Index 不应该混为一谈
这是很多项目最容易写得比较糊的地方。
在不少 demo 里,Collection 和 Index 几乎是一个意思。
但当数据规模、模型数量、知识库数量上来之后,你会发现这两个概念分不开。
我理解中的区别大概是:
Collection
更偏“数据容器”和组织边界。
它回答的问题是:
- 这些向量属于哪个知识库
- 它们以什么维度存
- 共享哪些字段结构
- 会不会和别的向量资产混放
Index
更偏“搜索结构”和性能策略。
它回答的问题是:
- 用什么算法查
- 用什么度量方式算相似度
- 追求精度还是速度
- 当前状态是不是已经可用
换句话说:
Collection 更像容器,Index 更像搜索配置。
只有把这两个概念拆开,你后面做管理、推荐、统计和搜索联动时,系统才不会越来越乱。
为什么我做了逻辑 Collection / 物理 Collection 分层
这部分是索引模块里我比较看重的一个设计点。
因为在真实场景里,你很容易遇到一个问题:
- 不同文档可能来自同一个逻辑知识库
- 但它们的 Embedding 模型不一定相同
- 向量维度也不一定相同
如果把这些向量硬塞进同一个物理 Collection,问题就会非常多:
- 维度不一致无法共存
- 管理边界混乱
- 后面多模型扩展很难做
所以这个项目参考了更工程化的做法,把 Collection 分成两层:
逻辑 Collection
面向业务概念,比如某个知识库、某类文档集合。
物理 Collection
面向真正的存储结构,通常按维度等底层条件拆分。
这件事看起来有点“多做了一层抽象”,但它的价值很实在:
- 支持多模型共存
- 让不同维度的向量有清晰归属
- 为跨 Collection 联合检索打基础
- 让后续迁移和扩展更容易
我越来越觉得,很多工程设计在小规模时看起来像“过度设计”,但等你真的进入多模型、多知识库场景时,它们会变成必须项。
为什么要在索引层就预留 BM25 稀疏向量能力
这个项目后面的搜索模块支持混合检索,也就是:
- 稠密向量召回
- 稀疏向量召回
- 融合
- 精排
如果只看搜索层,好像稀疏向量是搜索时才需要考虑的。
但实际上,稀疏能力应该从索引层就开始准备。
因为搜索层要做混合检索,前提是索引层已经准备好了:
- 稠密向量字段
- 稀疏向量字段
- 对应的统计信息
- 能支撑 BM25 查询的基础结构
在这个项目里,我用 jieba 做 BM25 稀疏向量生成,并把这部分能力放进索引模块中一起落地。
这么做的意义是:
混合检索不是搜索阶段临时拼出来的,而是从索引基础设施阶段就已经开始布局。
这会让后面的搜索模块更干净,也更容易解释。
为什么算法选择和度量类型不该靠用户盲猜
索引层另一个很常见的问题是:
系统虽然支持很多算法,但用户其实并不知道怎么选。
比如常见的索引算法就包括:
FLATHNSWIVF_FLATIVF_SQ8IVF_PQ
如果只把这些选项暴露出来,却不给任何建议,用户往往只能凭感觉点一个。
但这些算法背后对应的是非常不同的取舍:
- 小数据量更适合精确搜索
- 中等规模更适合平衡精度和速度
- 大规模更需要近似搜索和更强压缩
同样,度量类型也不是随便填:
COSINEL2IP
这些选择会和 Embedding 模型的特性强相关。
所以在这个项目里,我专门做了推荐引擎。
推荐逻辑会结合:
- 数据量
- 向量维度
- 模型类型
- 常见经验规则
来推荐:
- 索引算法
- 度量类型
- 相关参数
这件事的核心价值不是“系统更自动化”,而是:
让用户在合理默认值上开始,而不是在完全未知的配置空间里乱试。
为什么统计、日志和审计记录非常重要
索引层看起来不像用户直接操作最多的页面,但它其实很需要可观测性。
因为一旦这里出问题,影响会非常大:
- 写入失败
- 状态不一致
- 搜索结果异常
- Collection 匹配错误
- 重复创建索引
所以在这个模块里,我专门保留了:
- 索引元数据
- 操作日志
- 统计信息
- 推荐采纳记录
这些能力平时看起来不显眼,但在工程实践里非常关键。
比如你需要回答这些问题时,就会发现它们的重要性:
- 某个索引是什么时候建的
- 用了什么模型和什么参数
- 为什么这次推荐用户没采纳
- 当前状态是不是
READY - 某次恢复和持久化有没有成功
我一直觉得,工程化系统不是“功能多”,而是:
关键节点出现问题时,你能不能知道它为什么出问题。
这一层和“把向量写进 Milvus”到底差在哪
如果只从代码量看,最小版本的向量索引其实很短:
连接 Milvus
-> 创建 collection
-> 插入向量
-> 建 index
但在这个项目里,我更关心的是下面这些更工程化的能力:
- 逻辑 / 物理 Collection 分层
- 稠密 + 稀疏双路向量准备
- 索引配置推荐
- Collection / Index 独立管理
- 状态记录
- 统计与审计日志
- 恢复和持久化能力
所以它和普通 demo 的差别,不在“能不能建索引”,而在:
能不能把索引层做成一个长期可维护的检索基础设施。
我对这个模块的一个核心判断
如果只让我总结一句话,我会说:
向量写进库里只是开始,真正困难的是把这些向量组织成一套支持多模型、多知识库、混合检索和长期演进的基础设施。
这一步做得好,搜索模块才有稳定地基。
这一步做不好,后面所有检索优化都会不断撞上基础设施的边界。
所以在 RAG Pipeline Hub 里,我才会把索引模块单独拆出来,而不是把它当成搜索前的一段临时代码。
下一篇写什么
索引模块解决的是“怎么存、怎么建、怎么管”。
接下来真正面向结果质量的问题就是:
怎么把 Dense Recall、Sparse Recall、RRF、Reranker 和 Query Enhancement 串成一条真正可用的检索链路。
所以下一篇我会继续写:
《RAG 检索不能只靠向量 TopK:Dense + Sparse + RRF + Reranker 的完整链路》
项目地址:
- GitHub:
https://github.com/qingni/rag-pipeline-hub
如果这篇文章对你有帮助,欢迎:
- 点个
star - 提个
issue - 留言说说你在索引层最常踩的坑
如果你也做过 Milvus、Collection 管理、索引算法调优或者混合检索底座设计,欢迎交流你的经验。
我越来越觉得,很多 RAG 系统看起来差在“搜索效果”,其实根因往往早在索引层就埋下了。