1. 前言:数据接入层在RAG管线中的位置
最近在补某个知识库项目的数据接入层,同事丢过来一个需求:线上已经把文档向量灌进了 Milvus,现在要在 LlamaIndex 这边把数据读回来,做检索、重排和问答。这个需求听起来很简单,无非是连一下数据库、建个索引、跑个 query,但真正落地的时候发现坑比想象中多很多:字段名对不上、metadata 丢了一半、重复入库、chunk 粒度不一致,每一件都能让检索效果大打折扣。
我这次做的就是一个典型的 Data-Processor 数据接入模块,代号可以叫 data_connectors20,核心工作就是从 Milvus 向量数据库中把已存在的向量数据读取出来,交给 LlamaIndex 构建索引,再通过 RAG 链路完成检索问答。这篇文章把我处理"从 Milvus 读数据到 LlamaIndex"这条链路的完整过程记录下来,包括环境搭建、代码实现、元数据处理、增量去重、性能排障几个部分,希望能给正在做类似数据接入模块的朋友省点时间。
先说一下适用范围。如果你遇到下面任何一种情况,这篇文章就是冲着你写的:
- 你有一个已经跑起来的 Milvus 实例,里面已经写入了文档向量,现在想在不重复 embedding 的前提下接入 LlamaIndex。
- 你的数据处理管线和检索框架是两拨人在维护,你需要一个薄薄的读取层把两边的数据模型粘起来。
- 你在评估 Milvus 和 LlamaIndex 组合的可行性,想提前知道这里面有哪些坑。
如果你本来就是从零搭建 RAG,文档还没切分、向量还没入库,那这篇文章的内容更适合作为你的"第二步参考",我建议先把前半部分读完,把 Milvus 侧的数据模型理顺了再动手。
2. 环境准备:Milvus 部署与 LlamaIndex 依赖安装
2.1 开发环境的两种搭建方式
动手之前,先把环境准备好。Milvus 的部署方式直接决定你在 LlamaIndex 侧怎么写连接参数,所以这一步不能跳过。
我这次用的是 Milvus Standalone 模式,因为早期联调阶段数据量不到一百万条,单机部署完全够用。如果你手头只有一台开发机,建议直接用 Docker Compose 一把梭,命令如下:
# 下载 standalone 编排文件 wget https://github.com/milvus-io/milvus/releases/download/v2.4.1/milvus-standalone-docker-compose.yml # 启动 docker compose -f milvus-standalone-docker-compose.yml up -d # 检查三个组件是否正常 docker compose -f milvus-standalone-docker-compose.yml ps这里要稍微解释一下。Milvus 2.x 的 Standalone 模式实际上由三个组件组成:Milvus 主服务、etcd(元数据存储)和 MinIO(对象存储)。你用 docker compose 一键启动的其实是这三个服务的组合。刚开始我犯过一个错误,只启动了 milvus 主容器,结果连接时一直报错,后来才发现 etcd 和 MinIO 没起来,Milvus 根本没法正常工作。所以启动完一定要执行docker compose ps确认三个容器都是 Up 状态。
如果你只是想在本地快速验证代码逻辑,不想折腾 Docker,也可以试试 Milvus Lite。它是个嵌入式版本,直接 pip 安装就能用:
pip install milvus-lite但 Milvus Lite 不适合作为正式的联调环境,因为它的文件存储格式和完整版不完全一致,数据迁移时可能出问题。我的建议是:日常小实验用 Milvus Lite,正式开发调试还是老老实实起 Docker。
2.2 LlamaIndex 相关依赖安装
LlamaIndex 这一侧的依赖安装同样有讲究,你不能直接pip install llama-index一把梭完事。LlamaIndex 从 0.10.x 开始就把集成模块拆得很细,Milvus 的集成被单独放在一个包里,必须显式声明安装:
pip install llama-index-core pip install llama-index-vector-stores-milvus pip install pymilvus这里补充一个容易踩坑的版本问题。llama-index-vector-stores-milvus这个包会依赖pymilvus,但它依赖的 pymilvus 版本可能和你本地已有的版本冲突。我在安装时就遇到了 pymilvus 2.3 被强制升级到 2.4 的情况,导致其他脚本里的一些 API 报 DeprecationWarning。建议在 requirements 里把pymilvus>=2.4.0写死,避免被动升级。
embedding 模型这一侧也有讲究。如果你读取的向量是之前用某一种 embedding 模型生成的,那么后续查询时也必须用同一个模型生成查询向量,否则向量空间不一致,检索结果就是乱的。我在代码里用一个配置文件统一维护 embedding 模型名称和维度,就