Milvus 实战:当 RAG 遇上向量数据库,从"玩具 Demo"到"生产可用的"那一步

作者:Lee川日期:2026/5/25

Milvus 实战:当 RAG 遇上向量数据库,从"玩具 Demo"到"生产可用的"那一步

前面的文章讲过,RAG 的第四步是"向量存储"。在原型阶段,一个 MemoryVectorStore 就能跑通全链路。但问题是:程序一关,所有向量灰飞烟灭;数据一多,内存直接爆掉;更别提多用户隔离、权限控制、分布式检索这些生产环境的刚需。

MemoryVectorStore 是 Demo 的终点,却是向量数据库的起点。

本文通过一段与 Milvus(Zilliz Cloud)交互的真实代码,拆解向量数据库在 RAG 生产落地中的关键角色。

为什么是 Milvus?

Milvus 是目前全球最活跃的开源向量数据库之一,它的定位非常明确:专为向量检索而生。传统数据库的索引结构(B+Tree、Hash)是为精确匹配设计的,面对"在海量 1024 维向量中找出与查询向量最相似的前 10 个"这种需求时,性能直接崩塌。

Milvus 底层基于 Approximate Nearest Neighbor(ANN,近似最近邻)算法,能在毫秒级完成百万乃至亿级向量的相似度检索。它的云服务 Zilliz Cloud 更进一步——免运维、自动扩缩容、提供 Token 认证,一行连接串就能接入。

连接:从一行地址开始

1import { MilvusClient } from '@zilliz/milvus2-sdk-node';
2
3const client = new MilvusClient({
4    address: process.env.MILVUS_ADDRESS,  // Zilliz Cloud 集群地址
5    token: process.env.MILVUS_TOKEN,       // API Token 认证
6});
7

这里连接的不是本地 Milvus 实例,而是 Zilliz Cloud 的云端集群address 是集群的公网端点,token 是 API 密钥——就像连接一个远程数据库,不需要在本地跑任何 Milvus 进程。这是生产环境最典型的部署模式:向量库作为独立的基础设施,AI 应用通过网络协议与之交互。

连接后的第一件事永远是健康检查:

1const checkHealth = await client.checkHealth();
2if (!checkHealth.isHealthy) {
3    console.error('连接Milvus失败', checkHealth.reasons);
4    return;
5}
6

这不是多余的防御代码。在生产环境中,网络抖动、集群升级、Token 过期都可能导致连接失败。先确认连得上,再做后续操作——这是和外部服务交互的基本素养。

Schema 设计:向量数据库的灵魂

如果你用过 MySQL,一定知道建表时定义字段类型有多重要。Milvus 也一样——它不是一个"无脑扔向量"的黑盒,而是需要你精心设计 Collection(类比数据库中的 Table)的 Schema。

代码中注释掉的建库逻辑展示了一个完整的 Schema 设计:

1await client.createCollection({
2    collection_name: 'ai_diary',
3    fields: [
4        { name: 'id', data_type: DataType.VarChar, max_length: 50, is_primary_key: true },
5        { name: 'vector', data_type: DataType.FloatVector, dim: VECTOR_DIM },
6        { name: 'content', data_type: DataType.VarChar, max_length: 5000 },
7        { name: 'date', data_type: DataType.VarChar, max_length: 50 },
8        { name: 'mood', data_type: DataType.VarChar, max_length: 50 },
9        { name: 'tags', data_type: DataType.Array, element_type: DataType.VarChar,
10            max_length: 50, max_capacity: 10 },
11    ]
12});
13

每个字段都值得细说:

id(主键)VarChar(50),不是你熟悉的 auto-increment 数字。Milvus 中的主键可以是字符串,这在 AI 应用中非常有用——你可以用 diary_001doc_juejin_723332 这种有业务含义的 ID 做精确检索。

vector(向量字段)FloatVector,维度 VECTOR_DIM = 1024。这是整个 Collection 的核心——所有相似度搜索都基于这个字段。1024 维是由你的 Embedding 模型决定的(通义千问 text-embedding-v3 输出就是 1024 维)。这个数字必须和 Embedding 模型的输出维度严格一致,否则插入会直接报错。 一维不差,差一维都不行。

content(原文内容)VarChar(5000),存储日记原文。检索时不仅要拿到向量距离,还要把原文还给用户。这是 RAG 的"R"和"G"之间的桥梁——向量负责"找",原文负责"答"。

datemood(业务元数据):这些不是 RAG 必需字段,但它们让检索结果更丰富。想象用户问"我上周心情好的时候做了什么"——如果只有向量,你做不到这种精确过滤。

tags(数组字段)DataType.Array,这是 Milvus 的高级功能。它支持将多个标签存储在同一字段中(如 ['户外', '朋友']),配合标量过滤可以实现"在标签包含'户外'的日记中做向量检索"这种混合查询。

Schema 设计的核心原则:向量字段负责相似度检索,标量字段(VarChar、Array 等)负责精确过滤和结果展示。两者缺一不可——只有向量叫"黑盒检索",只有标量叫"关键词搜索",合在一起才是真正实用的向量数据库。

索引:让检索从"走遍全库"变成"按图索骥"

没有索引的向量检索叫"暴力搜索"——把查询向量与库中每一条向量逐一计算距离,然后排序。数据量小的时候还能跑,百万级向量时一次查询可能要几十秒。

索引的作用,是在精度和速度之间找到平衡点:

1await client.createIndex({
2    collection_name: 'ai_diary',
3    field_name: 'vector',
4    index_type: IndexType.IVF_FLAT,
5    metric_type: MetricType.COSINE,
6    params: { nlist: VECTOR_DIM },
7});
8

IVF_FLAT:倒排文件索引(Inverted File),Milvus 最经典的索引类型。它的工作原理是:先把所有向量用 K-Means 聚成 nlist 个簇,查询时只搜索与查询向量最近的那几个簇,而不是全库扫描。用 1% 的精度损失,换 99% 的速度提升。

nlist: VECTOR_DIM(即 1024):簇的数量。这个值一般设为 4 × sqrt(n)(n 为数据总量),但这里直接用维度数 1024 作为初始值。簇越多,搜索越精确但越慢;簇越少,搜索越快但越粗糙。这是 ANN 领域的经典"精度-速度跷跷板"。

MetricType.COSINE:余弦相似度。两个向量的夹角越小,相似度越高。COSINE 对向量长度不敏感,只关注"方向",在文本语义检索中效果最好。另外两种常见选择是 IP(内积,对向量长度敏感)和 L2(欧氏距离,越小越相似)。

loadCollection 之后,索引才真正加载到内存中,Collection 进入可检索状态。这一步是阻塞的——数据量越大,加载越慢,这也是为什么它在建库阶段执行,而非每次查询时执行。

写入:从文本到向量的完整旅程

数据插入是向量数据库区别于传统数据库最显著的地方——你不能直接 INSERT 一段文本,你必须先把文本变成向量

1const diaryContents = [
2    { id: 'diary_001', content: '今天天气很好,去公园散步了...', date: '2026-01-10',
3      mood: 'happy', tags: ['生活', '散步'] },
4    { id: 'diary_002', content: '今天工作很忙,完成了一个重要的项目里程碑...', date: '2026-01-11',
5      mood: 'excited', tags: ['工作', '成就'] },
6    { id: 'diary_003', content: '周末和朋友去爬山,天气很好...', date: '2026-01-12',
7      mood: 'relaxed', tags: ['户外', '朋友'] },
8    { id: 'diary_004', content: '今天学习了 Milvus 向量数据库...', date: '2026-01-12',
9      mood: 'curious', tags: ['学习', '技术'] },
10    { id: 'diary_005', content: '晚上做了一顿丰盛的晚餐...', date: '2026-01-13',
11      mood: 'proud', tags: ['美食', '家庭'] },
12];
13
14const diaryData = await Promise.all(
15    diaryContents.map(async (diary) => ({
16        ...diary,
17        vector: await getEmbeddings(diary.content),  // 文本  向量
18    }))
19);
20
21await client.insert({ collection_name: 'ai_diary', data: diaryData });
22

注意 Promise.all——五条日记的 Embedding 是并发生成的。当数据量从 5 条变成 5000 条时,这个并发策略的价值就显现出来了。生产环境中通常会加上并发控制(如 p-limit)避免打爆 Embedding API 的速率限制。

每条数据在入库前都经过了"文本 → 向量"的转换:content 字段被送入 Embedding 模型,返回一个 1024 维的浮点数数组,写入 vector 字段。向量库本身不知道文本是什么意思,它只负责存向量和做向量运算——文本的"理解"是 Embedding 模型的工作。

检索:相似度搜索的核心 API

建库和写入是一次性的工作,检索才是每一笔用户请求都要走的路径:

1const query = '我想看看关于户外活动的日记';
2const queryVector = await getEmbeddings(query);
3
4const searchResult = await client.search({
5    collection_name: 'ai_diary',
6    vector: queryVector,
7    limit: 3,
8    metric_type: MetricType.COSINE,
9    output_fields: ['id', 'content', 'date', 'mood', 'tags'],
10});
11

整个检索流程只有三步,但每一步都不可省略:

  1. 查询向量化——用同一个 Embedding 模型把用户查询转成向量。如果查询用 A 模型、入库用 B 模型,向量空间不一致,检索结果会完全错乱。Embedding 模型的一致性比模型本身的好坏更重要。
  2. 向量检索——Milvus 在 1024 维空间中执行 ANN 搜索,返回距离查询向量最近的 3 个文档。metric_type: COSINE 必须与建索引时的度量方式一致,否则索引失效,退化为暴力搜索。
  3. 结果映射——output_fields 指定返回哪些标量字段。Milvus 默认只返回主键和距离分数,其他字段按需指定。在 RAG 场景中,至少需要 content 字段来拼装提示词。

结果遍历展示了向量数据库相比纯向量索引库(如 Faiss)的最大优势——它同时管理向量和结构化元数据:

1searchResult.results.forEach(result => {
2    console.log([`日记ID: ${result.id}`](https://xplanc.org/primers/document/zh/10.Bash/90.%E5%B8%AE%E5%8A%A9%E6%89%8B%E5%86%8C/EX.id.md));
3    console.log(`内容: ${result.content}`);
4    console.log([`日期: ${result.date}`](https://xplanc.org/primers/document/zh/10.Bash/90.%E5%B8%AE%E5%8A%A9%E6%89%8B%E5%86%8C/EX.date.md));
5    console.log(`心情: ${result.mood}`);
6    console.log(`标签: ${result.tags}`);
7});
8

查询"户外活动",返回了"周末和朋友去爬山"(mood: relaxed, tags: ['户外', '朋友']),因为"爬山"和"户外活动"在向量空间中距离最近。同时,日期、心情、标签这些标量字段一起返回,前端可以直接渲染出丰富的检索结果卡片。

从玩具到工具:一段注释代码的进化史

文件底部有一段被注释掉的早期测试代码,它的演进本身就是一篇微型技术故事:

1// 早期测试版:4维向量,AUTOINDEX索引
2const DIMENSION = 4;
3await client.createCollection({
4    collection_name: 'test',
5    dimension: DIMENSION,    // 直接用 dimension 而不是 fields
6    auto_id: true,           // 自动生成主键
7});
8await client.createIndex({
9    index_type: IndexType.AUTOINDEX,  // 自动选索引
10});
11
12const data = [
13    { vector: [0.1, 0.2, 0.3, 0.4], content: '这是第一条数据' },
14    { vector: [0.5, 0.6, 0.7, 0.8], content: '这是第二条数据' },
15];
16

对比正式版,四个关键变化一览无余:

维度早期测试版正式生产版
向量维度4(手工构造)1024(Embedding 模型生成)
Schema极简(dimension + auto_id)完整(自定义字段、数组类型、主键设计)
索引AUTOINDEX(托管)IVF_FLAT(手动指定 + 参数调优)
数据手写浮点数,无真实语义Embedding API 生成,承载真实语义

这个演进映射了学习任何新技术的经典路径:先用最简配置跑通 Hello World,再逐步替换为生产可用的配置。 4 维手写向量让你理解"向量相似度"的数学直觉,1024 维 Embedding 让你真正解决业务问题。

Milvus vs MemoryVectorStore:生产落地必答题

维度MemoryVectorStoreMilvus (Zilliz Cloud)
持久化进程内存,重启即丢失云端持久化存储
数据规模万级(受内存限制)亿级(分布式横向扩展)
检索速度小数据量下极快(无网络开销)大数据量下稳定(ANN 索引加速)
Schema无 Schema,文档+向量自由存储强 Schema,预定义字段类型
元数据过滤基础的 metadata 字段原生支持标量过滤 + 混合检索
多用户不支持通过 Partition Key 或 Collection 隔离
运维零运维Zilliz Cloud 托管 / 自建集群
适用场景原型、Demo、学习生产环境、多用户 SaaS、企业应用

一句话总结:MemoryVectorStore 让你相信 RAG 能 work,Milvus 让 RAG 能 scale。

后续:从检索到增强

searchResult.results 拿到最相关的三条日记后,下一步就是把它塞进提示词,交给 LLM 回答。这个流程在前面的 RAG 文章中已经详述,这里不再展开。但值得强调的是——向量数据库的使命止步于"精准检索",之后的"阅读理解"是 LLM 的领地。两者的边界清晰,各司其职,这正是 RAG 架构的优雅之处。


面试考点总结

1. 向量数据库和传统数据库的核心区别是什么?

传统数据库(MySQL、PostgreSQL)为精确匹配设计,索引结构(B+Tree、Hash)擅长等值查询和范围查询。向量数据库为相似度检索设计,底层使用 ANN(近似最近邻)算法,擅长在高维空间中找"最像"的数据。它们不是替代关系,而是互补关系——生产环境中通常是 MySQL 存业务数据 + Milvus 存向量数据,各管各的。

2. Milvus 中的 Collection Schema 设计需要注意什么?

核心原则:向量字段负责检索,标量字段负责过滤和展示。 向量维度必须与 Embedding 模型输出维度严格一致(差一维都插不进去)。主键支持字符串类型,可以用有业务含义的 ID。标量字段按需定义——在检索时通过 output_fields 返回,减少后续查 MySQL 的额外开销。数组字段(DataType.Array)适合存储标签等可变长度的元数据。

3. IVF_FLAT 索引的工作原理是什么?nlist 参数如何选择?

IVF_FLAT 先用 K-Means 将所有向量聚成 nlist 个簇,查询时只搜索最近几个簇而非全库扫描。这是一种"粗筛 + 精排"的策略。nlist 越大,搜索越精确但越慢;nlist 越小,搜索越快但精度越低。 经验公式是 nlist = 4 × sqrt(n)(n 为数据总量)。IVF_FLAT 是"精度-速度"权衡中最均衡的选择之一。

4. COSINE、IP、L2 三种度量方式分别适用于什么场景?

  • COSINE(余弦相似度):只看向量方向,忽略长度。文本语义检索的首选,因为文本向量的长度往往和文本长度相关而非语义相关。
  • IP(内积):对向量长度和方向都敏感。适合需要对热门内容加权的推荐系统。
  • L2(欧氏距离):越小越相似。适合图像检索等向量长度本身就包含信息的场景。

建索引和查询时的 metric_type 必须一致,否则索引不生效。

5. 为什么 Embedding 模型的一致性比模型本身的好坏更重要?

查询向量和存储向量必须来自同一个向量空间。如果查询用 A 模型、入库用 B 模型,即使两个模型单独评估都很优秀,它们的向量空间不同,距离计算就失去语义意义——你搜索"户外活动",可能返回"晚餐食谱",因为两个模型对相同文本的向量表达完全不同。换 Embedding 模型 = 需要重新生成所有向量 = 数据迁移。

6. 向量数据库在 RAG 链路中的职责边界是什么?

向量数据库只负责**"找出来"**——给定查询向量,返回最相似的 K 个文档及其元数据。它不理解文本,不参与生成。文档的向量化是 Embedding 模型的工作,基于文档生成回答是 LLM 的工作。理解这个边界有助于架构分层:Embedding 负责向量化,Milvus 负责检索,LLM 负责生成。 三层各司其职,任意一层可以独立替换升级。

7. MemoryVectorStore 和 Milvus 分别用在什么阶段?

MemoryVectorStore 用于原型验证——快速跑通 RAG 全链路,验证"按这个 chunkSize、这个 Embedding 模型、这个 prompt 模板,回答质量是否达标"。验证通过后,切换到 Milvus 解决生产问题——持久化存储、海量数据、多用户隔离、高并发检索。从 MemoryVectorStore 到 Milvus 的过程,就是从"Demo 能跑"到"线上能用"的过程。

8. Milvus Collection 加载(loadCollection)的作用是什么?

loadCollection 将 Collection 的数据和索引从磁盘加载到内存。在 Milvus 架构中,数据和索引存储在不属于计算节点的对象存储(如 MinIO、S3)中。未加载的 Collection 不可查询——查询请求会被拒绝。所以它在建库流程中排在最后一步:先建表 → 建索引 → 插入数据 → 加载 → 可查询。加载是阻塞且耗时的操作(取决于数据量),在生产中一般建库时执行一次,而非每次查询前执行。


Milvus 实战:当 RAG 遇上向量数据库,从"玩具 Demo"到"生产可用的"那一步》 是转载文章,点击查看原文


相关推荐


RAG 系列(五):Embedding 模型——语义理解的核心
冬奇Lab2026/5/3

为什么换个 Embedding 模型,检索效果天差地别? 前面四篇文章,我们搞定了 Pipeline 搭建、参数调优和分块策略。但有一个问题一直没细说: 你的文档被切成 Chunk 之后,是怎么变成向量的? 这个过程叫 Embedding(嵌入),它把人类可读的文本变成计算机可算的向量。Embedding 模型的选择,直接决定了: "苹果"和"iPhone"能不能被识别为相关 "数据库连接池耗尽"和"Too many connections"能不能被匹配到一起 中文成语、专业术语、缩写能不


Python全栈项目实战:自建高效多媒体处理工具
天天进步20152026/4/24

在数字化时代,视频剪辑、格式转换、音频提取等需求已成为日常。虽然市面上有很多成熟的工具,但作为开发者,**亲手构建一个属于自己的“全栈多媒体处理平台”**不仅能深度掌握 Python 生态,还能解决隐私安全和批量化定制的痛点。 本博文将带你梳理一个 Python 全栈多媒体处理工具的核心设计与实现方案。 一、 项目核心功能 一个实用的多媒体工具至少应具备以下“硬核”功能: 视频处理:格式转换(MP4/WebM/AVI)、视频抽帧、添加水印、调整分辨率。 音频处理:音频提取、格式压


Frida 源码编译全流程:自己动手编译 frida-server
CYRUS_STUDIO2026/4/15

版权归作者所有,如有转发,请注明文章出处:cyrus-studio.github.io/blog/ 下载 Frida 源码 Frida 源码:github.com/frida/frida 官方文档:frida.re/docs/buildi… 下载源码 git clone https://github.com/frida/frida.git 安装相关依赖: sudo apt-get install build-essential git lib32stdc++-9-dev \ libc


用 3100 个数字造一台计算机
jump_jump2026/4/7

你有没有想过,一台计算机最少需要什么? 不是说你桌上那台——那个有几十亿个晶体管、跑着操作系统和浏览器的庞然大物。我说的是最本质的那个东西:能算数、能画画、能放音乐、能响应你的键盘和鼠标。 答案可能会让你意外:一个数组就够了。 Little Virtual Computer 是一台用 TypeScript 写的虚拟计算机,原作者是 jsdf。我在他的基础上做了不少重构和优化——把代码拆分成了清晰的模块结构,加了音频系统、断点调试、内存追踪、中英文切换等功能。3100 个内存槽位,23 条指令,你


别再被误导!try...catch性能大揭秘
小码哥_常2026/3/30

别再被误导!try...catch性能大揭秘 开头:抛出问题,引发好奇 家人们,最近我在代码审查的时候,被狠狠质疑了一把。我在代码里用了好些try...catch,结果就收到了这样的意见:“try...catch用太多会影响性能,得优化一下”。当时我就在想,try...catch真有这么大罪过吗?平常开发的时候,我们为了处理各种可能出现的异常,try...catch可没少用,它真的会严重影响性能吗 ?今天咱就来好好唠唠这个话题,一起把这层迷雾给拨开! 历史担忧:曾经的性能痛点 (一)早期 Jav


Claude Skills 新手笔记
言萧凡_CookieBoty2026/3/22

开篇:这份笔记能帮你解决什么问题 如果你正在用 Claude(或任何大模型)做写作、总结、审阅、编码、整理资料等重复性工作,你很快会遇到两个痛点: 同一类任务,每次都要把背景、规则、格式重新讲一遍; 输出质量容易波动:有时很稳,有时跑偏,难以复用。 Claude Skills 可以把“可重复任务的知识 + 流程 +资源”打包成可复用的能力单元,让模型在需要时按需加载,从而更稳定地完成特定工作。这篇文章会用最小规范、加载机制、以及一个完整的中文示例,带你快速建立可落地的理解。 1. Clau


破解企业安全软件网络拦截实战记录
来点vc2026/3/14

一、背景与现象 问题描述 个人电脑访问某技术网站时,被企业安全软件(零信任安全架构)拦截,提示: "您访问的站点或应用因不合规,企业安全软件 已自动拦截此次访问" 关键特征: 这是个人电脑,未连接公司 VPN,未访问公司内网 浏览器和系统设置中看不到任何代理配置 重启电脑后问题依然存在 二、排查与分析过程 第一阶段:DNS 层面排查 初始假设:DNS 被劫持到企业服务器 $ scutil --dns | grep nameserver nameserver[0] : 10.x.x.x


AI大模型小白手册|Embedding 与向量数据库
树獭非懒2026/3/5

前言 在人工智能快速发展的今天,大模型虽能理解并生成人类语言,却高度依赖外部工具来高效处理和检索海量信息。其中,Embedding(嵌入)  技术将文本、图像等复杂数据转化为计算机可计算的向量,而向量数据库则专门用于存储和快速检索这些高维向量,从而实现语义级别的相似性匹配。这两项技术共同构成了现代AI应用如智能问答、推荐系统和知识库检索的基石。 本手册专为AI初学者设计,旨在用通俗易懂的方式讲解Embedding的基本原理、主流模型特点、向量数据库的核心功能及典型使用场景,并通过简单示例帮助你快


【深度学习基础篇04】从回归到分类:图像分类与卷积神经网络入门
ppppppatrick2026/2/25

【深度学习基础篇】从回归到分类:图像分类与卷积神经网络入门 文章目录 【深度学习基础篇】从回归到分类:图像分类与卷积神经网络入门一、前情提要:从回归实战到分类任务的核心转变回归与分类的核心区别:输出逻辑的本质不同分类任务的输出解码:从“置信度”到“类别标签” 二、图像分类的前提:理解图像的张量表示1. 图像的核心维度:通道×高度×宽度(C×H×W)2. 批量图像的张量格式:N×C×H×W3. 全连接层处理图像的痛点:维度爆炸 三、卷积的核心概念:从“局部感知”到特征提取1


丰田正在使用 Flutter 开发游戏引擎 Fluorite
恋猫de小郭2026/2/17

近日,丰田汽车旗下子公司丰田互联北美公司宣布,即将开源基于 Flutter 的自主研发的游戏引擎 Flourite ,而实际上在此之前,Flutter 已经是丰田车机的开发 SDK 之一。 Toyota Connected North America,TCNA,是丰田的北美子公司,专注于车载软件、AI 等。 Fluorite 是首款完全集成 Flutter 的主机级(console-grade)游戏引擎,主要针对车载数字座舱(digital cockpit)和嵌入式低端硬件设计,已在 202

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读