RAG-索引构建
向量嵌入
基础概念
什么是 Embedding
向量嵌入(Embedding)是一种将真实世界中复杂、高维的数据对象(如文本、图像、音频、视频等)转换为数学上易于处理的、低维、稠密的连续数值向量的技术。
想象一下,我们将每一个词、每一段话、每一张图片都放在一个巨大的多维空间里,并给它一个独一无二的坐标。这个坐标就是一个向量,它“嵌入”了原始数据的所有关键信息。这个过程,就是 Embedding。
- 数据对象:任何信息,如文本“你好世界”,或一张猫的图片。
- Embedding 模型:一个深度学习模型,负责接收数据对象并进行转换。
- 输出向量:一个固定长度的一维数组,例如
[0.16, 0.29, -0.88, ...]。这个向量的维度(长度)通常在几百到几千之间。

向量空间的语义表示
Embedding 的真正意义在于,它产生的向量不是随机数值的堆砌,而是对数据语义的数学编码。
- 核心原则:在 Embedding 构建的向量空间中,语义上相似的对象,其对应的向量在空间中的距离会更近;而语义上不相关的对象,它们的向量距离会更远。
- 关键度量:我们通常使用以下数学方法来衡量向量间的“距离”或“相似度”:
- 余弦相似度 (Cosine Similarity) :计算两个向量夹角的余弦值。值越接近 1,代表方向越一致,语义越相似。这是最常用的度量方式。
- 点积 (Dot Product) :计算两个向量的乘积和。在向量归一化后,点积等价于余弦相似度。
- 欧氏距离 (Euclidean Distance) :计算两个向量在空间中的直线距离。距离越小,语义越相似。
Embedding 在 RAG 中的作用
在RAG流程中,Embedding 扮演着无可替代的重要角色。
语义检索的基础
RAG 的“检索”环节通常以基于 Embedding 的语义搜索为核心。通用流程如下:
(1)离线索引构建:将知识库内文档切分后,使用 Embedding 模型将每个文档块(Chunk)转换为向量,存入专门的向量数据库中。
(2)在线查询检索:当用户提出问题时,使用同一个 Embedding 模型将用户的问题也转换为一个向量。
(3)相似度计算:在向量数据库中,计算“问题向量”与所有“文档块向量”的相似度。
(4)召回上下文:选取相似度最高的 Top-K 个文档块,作为补充的上下文信息,与原始问题一同送给大语言模型(LLM)生成最终答案。
决定检索质量的关键
Embedding 的质量直接决定了 RAG 检索召回内容的准确性与相关性。一个优秀的 Embedding 模型能够精准捕捉问题和文档之间的深层语义联系,即使用户的提问和原文的表述不完全一致。反之,一个劣质的 Embedding 模型可能会因为无法理解语义而召回不相关或错误的信息,从而“污染”提供给 LLM 的上下文,导致最终生成的答案质量低下。
Embedding 技术发展
Embedding 技术的发展与自然语言处理(NLP)的进步紧密相连,尤其是在 RAG 框架出现后,对嵌入技术提出了新的要求。其演进路径大致可分为以下几个关键阶段。
静态词嵌入:上下文无关的表示
- 代表模型:Word2Vec (2013), GloVe (2014)
- 主要原理:为词汇表中的每个单词生成一个固定的、与上下文无关的向量。例如,
Word2Vec通过 Skip-gram 和 CBOW 架构,利用局部上下文窗口学习词向量,并验证了向量运算的语义能力(如国王 - 男人 + 女人 ≈ 王后)。GloVe则融合了全局词-词共现矩阵的统计信息。 - 局限性:无法处理一词多义问题。在“苹果公司发布了新手机”和“我吃了一个苹果”中,“苹果”的词向量是完全相同的,这限制了其在复杂语境下的语义表达能力。
动态上下文嵌入
2017年,Transformer 架构的诞生带来了自注意力机制(Self-Attention),它允许模型在生成一个词的向量时,动态地考虑句子中所有其他词的影响。基于此,2018年 BERT 模型利用 Transformer 的编码器,通过掩码语言模型(MLM)等自监督任务进行预训练,生成了深度上下文相关的嵌入。同一个词在不同语境中会生成不同的向量,这有效解决了静态嵌入的一词多义难题。
RAG 对嵌入技术的新要求
在开篇我们就提到了 RAG 框架的提出,是为了解决大型语言模型 知识固化(内部知识难以更新)和 幻觉(生成的内容可能不符合事实且无法溯源)的问题。它通过“检索-生成”范式,动态地为 LLM 注入外部知识。这一过程的核心是 语义检索,很大程度上依赖于高质量的向量嵌入。
后续 RAG 的兴起对嵌入技术提出了更高、更具体的要求:
- 领域自适应能力:通用的嵌入模型在专业领域(如法律、医疗)往往表现不佳,这就要求嵌入模型具备领域自适应的能力,能够通过微调或使用指令(如 INSTRUCTOR 模型)来适应特定领域的术语和语义。
- 多粒度与多模态支持:RAG 系统需要处理的不仅仅是短句,还可能包括长文档、代码,甚至是图像和表格。这就要求嵌入模型能够处理不同长度和类型的输入数据。
- 检索效率与混合检索:嵌入向量的维度和模型大小直接影响存储成本和检索速度。同时,为了结合语义相似性(密集检索)和关键词匹配(稀疏检索)的优点,支持混合检索的嵌入模型(如 BGE-M3)应运而生,在某些任务中成为提升召回率的关键。
嵌入模型训练原理
了解了嵌入模型的发展,我们来简单探究一下当前主流的嵌入模型(通常是基于 BERT 的变体)是如何通过训练获得强大的语义理解能力的。
现代嵌入模型的核心通常是 Transformer 的编码器(Encoder)部分,BERT 就是其中的典型代表。它通过堆叠多个 Transformer Encoder 层来构建一个深度的双向表示学习网络。
主要训练任务
BERT 的成功很大程度上归功于 自监督学习 策略,它允许模型从海量的、无标注的文本数据中学习知识。
任务一:掩码语言模型 (Masked Language Model, MLM)
- 过程:
- 随机地将输入句子中 15% 的词元(Token)替换为一个特殊的
[MASK]标记。 - 让模型去预测这些被遮盖住的原始词元是什么。
- 随机地将输入句子中 15% 的词元(Token)替换为一个特殊的
- 目标:通过这个任务,模型被迫学习每个词元与其上下文之间的关系,从而掌握深层次的语境语义。
任务二:下一句预测 (Next Sentence Prediction, NSP)
- 过程:
- 构造训练样本,每个样本包含两个句子 A 和 B。
- 其中 50% 的样本,B 是 A 的真实下一句(IsNext);另外 50% 的样本,B 是从语料库中随机抽取的句子(NotNext)。
- 让模型判断 B 是否是 A 的下一句。
- 目标:这个任务让模型学习句子与句子之间的逻辑关系、连贯性和主题相关性。
- 重要说明:后续的研究(如 RoBERTa)发现2,NSP 任务可能过于简单,甚至会损害模型性能。因此,许多现代的预训练模型(如 RoBERTa、SBERT)在预训练阶段移除了 NSP。
更多细节可查看 BERT 架构及应用
效果增强策略
虽然 MLM 和 NSP 赋予了模型强大的基础语义理解能力,但为了在检索任务中表现更佳,现代嵌入模型通常会引入更具针对性的训练策略。
- 度量学习 (Metric Learning) :
- 思想:直接以“相似度”作为优化目标。
- 方法:收集大量相关的文本对(例如,(问题,答案)、(新闻标题,正文))。训练的目标是优化向量空间中的相对距离:让“正例对”的向量表示在空间中被“拉近”,而“负例对”的向量表示被“推远”。关键在于优化排序关系,而非追求绝对的相似度值(如 1 或 0),因为过度追求极端值可能导致模型过拟合。
- 对比学习 (Contrastive Learning) :
- 思想:在向量空间中,将相似的样本“拉近”,将不相似的样本“推远”。
- 方法:构建一个三元组(Anchor, Positive, Negative)。其中,Anchor 和 Positive 是相关的(例如,同一个问题的两种不同问法),Anchor 和 Negative 是不相关的。训练的目标是让
distance(Anchor, Positive)尽可能小,同时让distance(Anchor, Negative)尽可能大。
模型选型指南
理论已经了解,那么该如何选择最适合你项目的嵌入模型?
从 MTEB 排行榜开始
MTEB (Massive Text Embedding Benchmark) 是一个由 Hugging Face 维护的、全面的文本嵌入模型评测基准。它涵盖了分类、聚类、检索、排序等多种任务,并提供了公开的排行榜,为评估和选择嵌入模型提供了重要的参考依据。

下面这张图是网站中的模型评估图像,直观地展示了在选择开源嵌入模型时需要权衡的四个核心维度:
- 横轴 - 模型参数量 (Number of Parameters) :代表了模型的大小。通常,参数量越大的模型(越靠右),其潜在能力越强,但对计算资源的要求也越高。
- 纵轴 - 平均任务得分 (Mean Task Score) :代表了模型的综合性能。这个分数是模型在分类、聚类、检索等一系列标准 NLP 任务上的平均表现。分数越高(越靠上),说明模型的通用语义理解能力越强。
- 气泡大小 - 嵌入维度 (Embedding Size) :代表了模型输出向量的维度。气泡越大,维度越高,理论上能编码更丰富的语义细节,但同时也会占用更多的存储和计算资源。
- 气泡颜色 - 最大处理长度 (Max Tokens) :代表了模型能处理的文本长度上限。颜色越深,表示模型能处理的 Token 数量越多,对长文本的适应性越好。

MTEB 榜单可以帮助我们快速筛选掉大量不合适的模型。但需要注意,榜单上的得分是在通用数据集上评测的,可能无法完全反映模型在你特定业务场景下的表现。
关键评估维度
在查看榜单时,除了分数,还需要关注以下几个关键维度:
- 任务 (Task) :对于 RAG 应用,需要重点关注模型在
Retrieval(检索) 任务下的排名。 - 语言 (Language) :模型是否支持你的业务数据所使用的语言?对于中文 RAG,应选择明确支持中文或多语言的模型。
- 模型大小 (Size) :模型越大,通常性能越好,但对硬件(显存)的要求也越高,推理速度也越慢。需要根据你的部署环境和性能要求来权衡。
- 维度 (Dimensions) :向量维度越高,能编码的信息越丰富,但也会占用更多的存储空间和计算资源。
- 最大 Token 数 (Max Tokens) :这决定了模型能处理的文本长度上限。这个参数是你设计文本分块(Chunking)策略时必须考虑的重要依据,块大小不应超过此限制。
- 得分与机构 (Score & Publisher) :结合模型的得分排名和其发布机构的声誉进行初步筛选。知名机构发布的模型通常质量更有保障。
- 成本 (Cost) :如果是使用 API 服务的模型,需要考虑其调用成本;如果是自部署开源模型,则需要评估其对硬件资源的消耗(如显存、内存)以及带来的运维成本。
迭代测试与优化
不要只依赖公开榜单做最终决定。
(1)确定基线 (Baseline) :根据上述维度,选择几个符合要求的模型作为你的初始基准模型。
(2)构建私有评测集 :根据真实业务数据,手动创建一批高质量的评测样本,每个样本包含一个典型用户问题和它对应的标准答案(或最相关的文档块)。
(3)迭代优化 : 使用基线模型在你的私有评测集上运行,评估其召回的准确率和相关性。 如果效果不理想,可以尝试更换模型,或者调整 RAG 流程的其他环节(如文本分块策略)。 通过几轮的对比测试和迭代优化,最终选出在你的特定场景下表现最佳的那个“心仪”模型。
多模态嵌入
现代 AI 的一项重要突破,是将简单的词向量发展成了能统一理解图文、音视频的复杂系统。这一发展建立在注意力机制、Transformer 架构和对比学习等关键技术之上,它们解决了在共享向量空间中对齐不同数据模态的核心挑战。其发展环环相扣:Word2Vec 为 BERT 的上下文理解铺路,而 BERT 又为 CLIP 等模型的跨模态能力奠定了基础。
为什么需要多模态嵌入?
前面的章节介绍了如何为文本创建向量嵌入。然而,仅有文本的世界是不完整的。现实世界的信息是多模态的,包含图像、音频、视频等。传统的文本嵌入无法理解“那张有红色汽车的图片”这样的查询,因为文本向量和图像向量处于相互隔离的空间,存在一堵“模态墙”。
多模态嵌入 (Multimodal Embedding) 的目标正是为了打破这堵墙。其目的是将不同类型的数据(如图像和文本)映射到同一个共享的向量空间。在这个统一的空间里,一段描述“一只奔跑的狗”的文字,其向量会非常接近一张真实小狗奔跑的图片向量。
实现这一目标的关键,在于解决 跨模态对齐 (Cross-modal Alignment) 的挑战。以对比学习、视觉 Transformer (ViT) 等技术为代表的突破,让模型能够学习到不同模态数据之间的语义关联,最终催生了像 CLIP 这样的模型。
CLIP 模型浅析
在图文多模态领域,OpenAI 的 CLIP (Contrastive Language-Image Pre-training) 是一个很有影响力的模型,它为多模态嵌入定义了一个有效的范式。
CLIP 的架构清晰简洁。它采用**双编码器架构 (Dual-Encoder Architecture)**,包含一个图像编码器和一个文本编码器,分别将图像和文本映射到同一个共享的向量空间中。
图:CLIP 的工作流程。(1) 通过对比学习训练双编码器,对齐图文向量空间。(2)和(3) 展示了如何利用该空间,通过图文相似度匹配实现零样本预测。
为了让这两个编码器学会“对齐”不同模态的语义,CLIP 在训练时采用了对比学习 (Contrastive Learning) 策略。在处理一批图文数据时,模型的目标是:最大化正确图文对的向量相似度,同时最小化所有错误配对的相似度。通过这种“拉近正例,推远负例”的方式,模型从海量数据中学会了将语义相关的图像和文本在向量空间中拉近。
这种大规模的对比学习赋予了 CLIP 有效的零样本(Zero-shot)识别能力。它能将一个传统的分类任务,转化为一个“图文检索”问题——例如,要判断一张图片是不是猫,只需计算图片向量与“a photo of a cat”文本向量的相似度即可。这使得 CLIP 无需针对特定任务进行微调,就能实现对视觉概念的泛化理解。
常用多模态嵌入模型(以bge-visualized-m3为例)
虽然 CLIP 为图文预训练提供了重要基础,但多模态领域的研究迅速发展,涌现了许多针对不同目标和场景进行优化的模型。例如,BLIP 系列专注于提升细粒度的图文理解与生成能力,而 ALIGN 则证明了利用海量噪声数据进行大规模训练的有效性。
在众多优秀的模型中,由北京智源人工智能研究院(BAAI)开发的 bge-visualized-m3(Visualized-BGE 的 M3 版本) 是一个很有代表性的现代多模态嵌入模型。它是在 BGE-M3(文本嵌入底座)的基础上引入图像能力而来,体现了当前技术向“更统一、更全面”发展的趋势。
bge-visualized-m3 的核心特性也可以概括为“M3”(主要继承自其文本底座 BGE-M3):
- **多语言性 (Multi-Linguality)**:支持超过 100 种语言的文本表示,可用于跨语言的图文检索(文本侧)。
- **多功能性 (Multi-Functionality)**:在文本检索场景下,可按需求使用密集检索(Dense Retrieval)、多向量检索(Multi-Vector Retrieval)等不同范式。
- **多粒度性 (Multi-Granularity)**:文本侧可处理从短句到长达 8192 个 token 的长文档,覆盖更广泛的应用需求。
在技术架构上,bge-visualized-m3 会先用视觉编码器提取图像的 patch token,再将其映射到与文本同维度的“图像 token”,与文本 token 一起送入 BGE 的 Transformer 编码器进行联合建模,最终得到可用于图文检索的统一向量表示。
向量数据库
作用
在前面我们学习了如何使用嵌入模型将文本、图像等非结构化数据转换为高维向量。这些向量是 RAG 系统能够进行语义理解的基础。然而,当向量数量从几百个增长到数百万甚至数十亿时,一个核心问题随之而来:如何快速、准确地从海量向量中找到与用户查询最相似的那几个?
向量数据库主要功能
向量数据库的核心价值在于其高效处理海量高维向量的能力。其主要功能可以概括为以下几点:
- 高效的相似性搜索:这是向量数据库最重要的功能。它利用专门的索引技术(如 HNSW, IVF),能够在数十亿级别的向量中实现毫秒级的近似最近邻(ANN)查询,快速找到与给定查询最相似的数据。
- 高维数据存储与管理:专门为存储高维向量(通常维度成百上千)而优化,支持对向量数据进行增、删、改、查等基本操作。
- 丰富的查询能力:除了基本的相似性搜索,还支持按标量字段过滤查询(例如,在搜索相似图片的同时,指定
年份 > 2023)、范围查询和聚类分析等,满足复杂业务需求。 - 可扩展与高可用:现代向量数据库通常采用分布式架构,具备良好的水平扩展能力和容错性,能够通过增加节点来应对数据量的增长,并确保服务的稳定可靠。
- 数据与模型生态集成:与主流的 AI 框架(如 LangChain, LlamaIndex)和机器学习工作流无缝集成,简化了从模型训练到向量检索的应用开发流程。
向量数据库 vs 传统数据库
传统的数据库(如 MySQL)擅长处理结构化数据的精确匹配查询(例如,WHERE age = 25),但它们并非为处理高维向量的相似性搜索而设计的。在庞大的向量集合中进行暴力、线性的相似度计算,其计算成本和时间延迟无法接受。向量数据库 (Vector Database) 很好的解决了这一问题,它是一种专门设计用于高效存储、管理和查询高维向量的数据库系统。在 RAG 流程中,它扮演着“知识库”的角色,是连接数据与大语言模型的关键桥梁。
向量数据库与传统数据库的主要差异如下:
| 维度 | 向量数据库 | 传统数据库 (RDBMS) |
|---|---|---|
| 核心数据类型 | 高维向量 (Embeddings) | 结构化数据 (文本、数字、日期) |
| 查询方式 | 相似性搜索 (ANN) | 精确匹配 |
| 索引机制 | HNSW, IVF, LSH 等 ANN 索引 | B-Tree, Hash Index |
| 主要应用场景 | AI 应用、RAG、推荐系统、图像/语音识别 | 业务系统 (ERP, CRM)、金融交易、数据报表 |
| 数据规模 | 轻松应对千亿级向量 | 通常在千万到亿级行数据,更大规模需复杂分库分表 |
| 性能特点 | 高维数据检索性能极高,计算密集型 | 结构化数据查询快,高维数据查询性能呈指数级下降 |
| 一致性 | 通常为最终一致性 | 强一致性 (ACID 事务) |
向量数据库和传统数据库并非相互替代的关系,而是互补关系。在构建现代 AI 应用时,通常会将两者结合使用:利用传统数据库存储业务元数据和结构化信息,而向量数据库则专门负责处理和检索由 AI 模型产生的海量向量数据。
工作原理
向量数据库的核心是高效处理高维向量的相似性搜索。向量数据库通常采用四层架构,通过存储层、索引层、查询层和服务层的协同工作来实现高效相似性搜索,其中存储层负责存储向量数据和元数据,优化存储效率并支持分布式存储;索引层维护索引算法(HNSW、LSH、PQ等),负责索引的创建与优化,并支持索引调整;查询层处理查询请求,支持混合查询并实现查询优化;服务层管理客户端连接,提供监控和日志能力,并实现安全管理。
主要技术手段包括:
- 基于树的方法:如 Annoy 使用的随机投影树,通过树形结构实现对数复杂度的搜索
- 基于哈希的方法:如 LSH(局部敏感哈希),通过哈希函数将相似向量映射到同一“桶”
- 基于图的方法:如 HNSW(分层可导航小世界图),通过多层邻近图结构实现快速搜索
- 基于量化的方法:如 Faiss 的 IVF 和 PQ,通过聚类和量化压缩向量
主流向量数据库
当前主流的向量数据库产品包括:
Pinecone 是一款完全托管的向量数据库服务,采用Serverless架构设计。它提供存储计算分离、自动扩展和负载均衡等企业级特性,并保证99.95%的SLA。Pinecone支持多种语言SDK,提供极高可用性和低延迟搜索(<100ms),特别适合企业级生产环境、高并发场景和大规模部署。
Milvus 是一款开源的分布式向量数据库,采用分布式架构设计,支持GPU加速和多种索引算法。它能够处理亿级向量检索,提供高性能GPU加速和完善的生态系统。Milvus特别适合大规模部署、高性能要求的场景,以及需要自定义开发的开源项目。
Qdrant 是一款高性能的开源向量数据库,采用Rust开发,支持二进制量化技术。它提供多种索引策略和向量混合搜索功能,能够实现极高的性能(RPS>4000)和低延迟搜索。Qdrant特别适合性能敏感应用、高并发场景以及中小规模部署。
Weaviate 是一款支持GraphQL的AI集成向量数据库,提供20+AI模块和多模态支持。它采用GraphQL API设计,支持RAG优化,特别适合AI开发、多模态处理和快速开发场景。Weaviate具有活跃的社区支持和易于集成的特点。
Chroma 是一款轻量级的开源向量数据库,采用本地优先设计,无依赖。它提供零配置安装、本地运行和低资源消耗等特性,特别适合原型开发、教育培训和小规模应用。Chroma的部署简单,适合快速原型开发。
选择建议:
- 新手入门/小型项目:从
ChromaDB或FAISS开始是最佳选择。它们与 LangChain/LlamaIndex 紧密集成,几行代码就能运行,且能满足基本的存储和检索需求。 - 生产环境/大规模应用:当数据量超过百万级,或需要高并发、实时更新、复杂元数据过滤时,应考虑更专业的解决方案,如
Milvus、Weaviate或云服务Pinecone。
索引创建实现细节: 通过深入 LangChain 源码,可以发现索引创建是一个分层、解耦的过程,主要涉及以下几个方法的嵌套调用:
from_documents(封装层):- 这是我们直接调用的方法。它的职责很简单:从输入的
Document对象列表中提取出纯文本内容 (page_content) 和元数据 (metadata)。 - 然后,它将这些提取出的信息传递给核心的
from_texts方法。
- 这是我们直接调用的方法。它的职责很简单:从输入的
from_texts(向量化入口):- 这个方法是面向用户的入口。它接收文本列表,并执行关键的第一步:调用
embedding.embed_documents(texts),将所有文本批量转换为向量。 - 完成向量化后,它并不直接处理索引构建,而是将生成的向量和其他所有信息(文本、元数据等)传递给一个内部的辅助方法
__from。
- 这个方法是面向用户的入口。它接收文本列表,并执行关键的第一步:调用
__from(构建索引框架):- 一个内部方法,负责搭建 FAISS 向量存储的“空框架”。
- 它会根据指定的距离策略(默认为 L2 欧氏距离)初始化一个空的 FAISS 索引结构(如
faiss.IndexFlatL2)。 - 同时,它也准备好了用于存储文档原文的
docstore和用于连接 FAISS 索引与文档的index_to_docstore_id映射。 - 最后,它调用另一个内部方法
__add来完成数据的填充。
__add(填充数据):- 真正执行数据添加操作的核心。它接收到向量、文本和元数据后,执行以下关键操作:
- 添加向量: 将向量列表转换为 FAISS 需要的
numpy数组,并调用self.index.add(vector)将其批量添加到 FAISS 索引中。 - 存储文档: 将文本和元数据打包成
Document对象,存入docstore。 - 建立映射: 更新
index_to_docstore_id字典,建立起 FAISS 内部的整数 ID(如 0, 1, 2…)到我们文档唯一 ID 的映射关系。
- 添加向量: 将向量列表转换为 FAISS 需要的
- 真正执行数据添加操作的核心。它接收到向量、文本和元数据后,执行以下关键操作:
Milvus向量数据库
Milvus安装
环境准备
- 安装 Docker 与 Docker Compose: 确保系统中已安装并正在运行 Docker 和 Docker Compose。
下载并启动 Milvus
在你选定的工作目录下,打开终端(Terminal)或命令行工具(PowerShell),执行以下步骤:
第一步:下载配置文件
使用以下命令下载官方的 docker-compose.yml 文件。这个文件定义了 Milvus Standalone 及其运行所需的两个核心依赖服务:etcd 用于存储元数据,MinIO 用于对象存储(更多架构细节请参考官方文档)。
1 | # macOS / Linux (使用 wget) |
第二步:启动 Milvus 服务
在 docker-compose.yml 文件所在的目录中,运行以下命令以后台模式启动 Milvus:
1 | docker compose up -dCopy to clipboardErrorCopied |
Docker 将会自动拉取所需的镜像并启动三个容器:milvus-standalone, milvus-minio, 和 milvus-etcd。这个过程可能需要几分钟,具体取决于你的网络状况。
验证安装
可以通过以下方式验证 Milvus 是否成功启动:
- 查看 Docker 容器: 在终端运行
docker ps命令 (Linux),确认三个 Milvus 相关容器(milvus-standalone,milvus-minio,milvus-etcd)都处于running或up状态。 - 检查服务端口: Milvus Standalone 默认通过
19530端口提供服务,这是后续代码连接时需要用到的地址。
常用管理命令
停止服务:
1
docker compose downCopy to clipboardErrorCopied
此命令会停止并移除容器,但保留存储的数据卷。
彻底清理 (停止并删除数据): 如果想彻底删除所有数据(包括向量、元数据等),可以执行以下命令:
1
docker compose down -v
核心组件
Collection (集合)
可以用一个图书馆的比喻来理解 Collection:
- Collection (集合): 相当于一个图书馆,是所有数据的顶层容器。一个 Collection 可以包含多个 Partition,每个 Partition 可以包含多个 Entity。
- Partition (分区): 相当于图书馆里的不同区域(如“小说区”、“科技区”),将数据物理隔离,让检索更高效。
- Schema (模式): 相当于图书馆的图书卡片规则,定义了每本书(数据)必须登记哪些信息(字段)。
- Entity (实体): 相当于一本具体的书,是数据本身。
- Alias (别名): 相当于一个动态的推荐书单(如“本周精选”),它可以指向某个具体的 Collection,方便应用层调用,实现数据更新时的无缝切换。
Collection 是 Milvus 中最基本的数据组织单位,类似于关系型数据库中的一张**表 (Table)**。是我们存储、管理和查询向量及相关元数据的容器。所有的数据操作,如插入、删除、查询等,都是围绕 Collection 展开的。
一个 Collection 由其 Schema 定义,并包含以下重要的子概念和特性:
Schema
在创建 Collection 之前,必须先定义它的 Schema。 Schema 规定了 Collection 的数据结构,定义了其中包含的所有字段 (Field) 及其属性。一个设计良好的 Schema 是能够保证数据一致性并提升查询性能。
Schema 通常包含以下几类字段:
- 主键字段 (Primary Key Field): 每个 Collection 必须有且仅有一个主键字段,用于唯一标识每一条数据(实体)。它的值必须是唯一的,通常是整数或字符串类型。
- 向量字段 (Vector Field): 用于存储核心的向量数据。一个 Collection 可以有一个或多个向量字段,以满足多模态等复杂场景的需求。
- 标量字段 (Scalar Field): 用于存储除向量之外的元数据,如字符串、数字、布尔值、JSON 等。这些字段可以用于过滤查询,实现更精确的检索。

上图以一篇新闻文章为例,展示了一个典型的多模态、混合向量 Schema 设计。它将一篇文章拆解为:唯一的 Article (ID)、文本元数据(如 Title、Author Info)、图像信息(Image URL),并为图像和摘要内容分别生成了密集向量(Image Embedding, Summary Embedding)和稀疏向量(Summary Sparse Embedding)。
Partition (分区)
Partition 是 Collection 内部的一个逻辑划分。每个 Collection 在创建时都会有一个名为 _default 的默认分区。我们可以根据业务需求创建更多的分区,将数据按特定规则(如类别、日期等)存入不同分区。
为什么使用分区?
- 提升查询性能: 在查询时,可以指定只在一个或几个分区内进行搜索,从而大幅减少需要扫描的数据量,显著提升检索速度。
- 数据管理: 便于对部分数据进行批量操作,如加载/卸载特定分区到内存,或者删除整个分区的数据。
一个 Collection 最多可以有 1024 个分区。合理利用分区是 Milvus 性能优化的重要手段之一。
Alias (别名)
Alias (别名) 是为 Collection 提供的一个“昵称”。通过为一个 Collection 设置别名,我们可以在应用程序中使用这个别名来执行所有操作,而不是直接使用真实的 Collection 名称。
为什么使用别名?
- 安全地更新数据:想象一下,你需要对一个在线服务的 Collection 进行大规模的数据更新或重建索引。直接在原 Collection 上操作风险很高。正确的做法是:
- 创建一个新的 Collection (
collection_v2) 并导入、索引好所有新数据。 - 将指向旧 Collection (
collection_v1) 的别名(例如my_app_collection)原子性地切换到新 Collection (collection_v2) 上。
- 创建一个新的 Collection (
- 代码解耦:整个切换过程对上层应用完全透明,无需修改任何代码或重启服务,实现了数据的平滑无缝升级。
索引 (Index)
如果说 Collection 是 Milvus 的骨架,那么索引 (Index) 就是其加速检索的神经系统。从宏观上看,索引本身就是一种为了加速查询而设计的复杂数据结构。对向量数据创建索引后,Milvus 可以极大地提升向量相似性搜索的速度,代价是会占用额外的存储和内存资源。

上图清晰地展示了 Milvus 向量索引的内部组件及其工作流程:
- 数据结构:这是索引的骨架,定义了向量的组织方式(如 HNSW 中的图结构)。
- 量化(可选):数据压缩技术,通过降低向量精度来减少内存占用和加速计算。
- 结果精炼(可选):在找到初步候选集后,进行更精确的计算以优化最终结果。
Milvus 支持对标量字段和向量字段分别创建索引。
- 标量字段索引:主要用于加速元数据过滤,常用的有
INVERTED、BITMAP等。通常使用推荐的索引类型即可。 - 向量字段索引:这是 Milvus 的核心。选择合适的向量索引是在查询性能、召回率和内存占用之间做出权衡的艺术。
主要向量索引类型
Milvus 提供了多种向量索引算法,以适应不同的应用场景。以下是几种最核心的类型:
- FLAT (精确查找)
- 原理:暴力搜索(Brute-force Search)。它会计算查询向量与集合中所有向量之间的实际距离,返回最精确的结果。
- 优点:100% 的召回率,结果最准确。
- 缺点:速度慢,内存占用大,不适合海量数据。
- 适用场景:对精度要求极高,且数据规模较小(百万级以内)的场景。
- IVF 系列 (倒排文件索引)
- 原理:类似于书籍的目录。它首先通过聚类将所有向量分成多个“桶”(
nlist),查询时,先找到最相似的几个“桶”,然后只在这几个桶内进行精确搜索。IVF_FLAT、IVF_SQ8、IVF_PQ是其不同变体,主要区别在于是否对桶内向量进行了压缩(量化)。 - 优点:通过缩小搜索范围,极大地提升了检索速度,是性能和效果之间很好的平衡。
- 缺点:召回率不是100%,因为相关向量可能被分到了未被搜索的桶中。
- 适用场景:通用场景,尤其适合需要高吞吐量的大规模数据集。
- 原理:类似于书籍的目录。它首先通过聚类将所有向量分成多个“桶”(
- HNSW (基于图的索引)
- 原理:构建一个多层的邻近图。查询时从最上层的稀疏图开始,快速定位到目标区域,然后在下层的密集图中进行精确搜索。
- 优点:检索速度极快,召回率高,尤其擅长处理高维数据和低延迟查询。
- 缺点:内存占用非常大,构建索引的时间也较长。
- 适用场景:对查询延迟有严格要求(如实时推荐、在线搜索)的场景。
- DiskANN (基于磁盘的索引)
- 原理:一种为在 SSD 等高速磁盘上运行而优化的图索引。
- 优点:支持远超内存容量的海量数据集(十亿级甚至更多),同时保持较低的查询延迟。
- 缺点:相比纯内存索引,延迟稍高。
- 适用场景:数据规模巨大,无法全部加载到内存的场景。
如何选择索引?
选择索引没有唯一的“最佳答案”,需要根据业务场景在数据规模、内存限制、查询性能和召回率之间进行权衡。
| 场景 | 推荐索引 | 备注 |
|---|---|---|
| 数据可完全载入内存,追求低延迟 | HNSW | 内存占用较大,但查询性能和召回率都很优秀。 |
| 数据可完全载入内存,追求高吞吐 | IVF_FLAT / IVF_SQ8 | 性能和资源消耗的平衡之选。 |
| 数据量巨大,无法载入内存 | DiskANN | 在 SSD 上性能优异,专为海量数据设计。 |
| 追求 100% 准确率,数据量不大 | FLAT | 暴力搜索,确保结果最精确。 |
在实际应用中,通常需要通过测试来找到最适合自己数据和查询模式的索引类型及其参数。
检索
基础向量检索 (ANN Search)
拥有了数据容器 (Collection) 和检索引擎 (Index) 后,最后一步就是从海量数据中高效地检索信息。这是 Milvus 的核心功能之一,近似最近邻 (Approximate Nearest Neighbor, ANN) 检索。与需要计算全部数据的暴力检索(Brute-force Search)不同,ANN 检索利用预先构建好的索引,能够极速地从海量数据中找到与查询向量最相似的 Top-K 个结果。这是一种在速度和精度之间取得极致平衡的策略。
- 主要参数:
anns_field: 指定要在哪个向量字段上进行检索。data: 传入一个或多个查询向量。limit(或top_k): 指定需要返回的最相似结果的数量。search_params: 指定检索时使用的参数,例如距离计算方式 (metric_type) 和索引相关的查询参数。
增强检索
在基础的 ANN 检索之上,Milvus 提供了多种增强检索功能,以满足更复杂的业务需求。
过滤检索 (Filtered Search)
在实际应用中,我们很少只进行单纯的向量检索。更常见的需求是“在满足特定条件的向量中,查找最相似的结果”,这就是过滤检索。它将向量相似性检索与标量字段过滤结合在一起。
- 工作原理:先根据提供的过滤表达式 (
filter) 筛选出符合条件的实体,然后仅在这个子集内执行 ANN 检索。这极大地提高了查询的精准度。 - 应用示例:
- 电商:”检索与这件红色连衣裙最相似的商品,但只看价格低于500元且有库存的。”
- 知识库:”查找与‘人工智能’相关的文档,但只从‘技术’分类下、且发布于2023年之后的文章中寻找。”
范围检索 (Range Search)
有时我们关心的不是最相似的 Top-K 个结果,而是“所有与查询向量的相似度在特定范围内的结果”。
- 工作原理:范围检索允许定义一个距离(或相似度)的阈值范围。Milvus 会返回所有与查询向量的距离落在这个范围内的实体。
- 应用示例:
- 人脸识别:”查找所有与目标人脸相似度超过 0.9 的人脸”,用于身份验证。
- 异常检测:”查找所有与正常样本向量距离过大的数据点”,用于发现异常。
多向量混合检索 (Hybrid Search)
这是 Milvus 提供的一种极其强大的高级检索模式,它允许在一个请求中同时检索多个向量字段,并将结果智能地融合在一起。
- 工作原理:
- 并行检索:应用针对不同的向量字段(如一个用于文本语义的密集向量,一个用于关键词匹配的稀疏向量,一个用于图像内容的多模态向量)分别发起 ANN 检索请求。
- **结果融合 (Rerank)**:Milvus 使用一个重排策略(Reranker)将来自不同检索流的结果合并成一个统一的、更高质量的排序列表。常用的策略有
RRFRanker(平衡各方结果)和WeightedRanker(可为特定字段结果加权)。
- 应用示例:
- 多模态商品检索:用户输入文本“安静舒适的白色耳机”,系统可以同时检索商品的文本描述向量和图片内容向量,返回最匹配的商品。
- 增强型 RAG: 结合密集向量(捕捉语义)和稀疏向量(精确匹配关键词),实现比单一向量更精准的文档检索效果。
分组检索 (Grouping Search)
分组检索解决了一个常见的痛点:检索结果多样性不足。想象一下,你检索“机器学习”,返回的前10篇文章都来自同一本教科书不同章节。这显然不是理想的结果。
- 工作原理:分组检索允许指定一个字段(如
document_id)对结果进行分组。Milvus 会在检索后,确保返回的结果中每个组(每个document_id)只出现一次(或指定的次数),且返回的是该组内与查询最相似的那个实体。 - 应用示例:
- 视频检索:检索“可爱的猫咪”,确保返回的视频来自不同的博主。
- 文档检索:检索“数据库索引”,确保返回的结果来自不同的书籍或来源。
通过这些灵活的检索功能组合,开发者可以构建出满足各种复杂业务需求的向量检索应用。
索引优化
上下文扩展
在RAG系统中,常常面临一个权衡问题:使用小块文本进行检索可以获得更高的精确度,但小块文本缺乏足够的上下文,可能导致大语言模型(LLM)无法生成高质量的答案;而使用大块文本虽然上下文丰富,却容易引入噪音,降低检索的相关性。为了解决这一矛盾,LlamaIndex 提出了一种实用的索引策略——句子窗口检索(Sentence Window Retrieval)2。该技术巧妙地结合了两种方法的优点:它在检索时聚焦于高度精确的单个句子,在送入LLM生成答案前,又智能地将上下文扩展回一个更宽的“窗口”,从而同时保证检索的准确性和生成的质量。
主要思路
句子窗口检索的思想可以概括为:为检索精确性而索引小块,为上下文丰富性而检索大块。
其工作流程如下:
(1)索引阶段:在构建索引时,文档被分割成单个句子。每个句子都作为一个独立的“节点(Node)”存入向量数据库。同时,每个句子节点都会在元数据(metadata)中存储其上下文窗口,即该句子原文中的前N个和后N个句子。这个窗口内的文本不会被索引,仅仅是作为元数据存储。
(2)检索阶段:当用户发起查询时,系统会在所有单一句子节点上执行相似度搜索。因为句子是表达完整语义的最小单位,所以这种方式可以非常精确地定位到与用户问题最相关的核心信息。
(3)后处理阶段:在检索到最相关的句子节点后,系统会使用一个名为 MetadataReplacementPostProcessor 的后处理模块。该模块会读取到检索到的句子节点的元数据,并用元数据中存储的完整上下文窗口来替换节点中原来的单一句子内容。
(4)生成阶段:最后,这些被替换了内容的、包含丰富上下文的节点被传递给LLM,用于生成最终的答案。
结构化索引
随着知识库的规模不断扩大(例如,包含数百个PDF文件),传统的RAG方法(即对所有文本块进行top-k相似度搜索)会遇到瓶颈。当一个查询可能只与其中一两个文档相关时,在整个文档库中进行无差别的向量搜索,不仅效率低下,还容易被不相关的文本块干扰,导致检索结果不精确。
为了解决这个问题,一个有效的方法是利用结构化索引。其原理是在索引文本块的同时,为其附加结构化的元数据(Metadata)。这些元数据可以是任何有助于筛选和定位信息的标签,例如:
- 文件名
- 文档创建日期
- 章节标题
- 作者
- 任何自定义的分类标签

实际上,RAG-文本分块中介绍的基于文档结构的分块方法,就是实现结构化索引的一种前置步骤。例如,在使用 MarkdownHeaderTextSplitter 时,分块器会自动将Markdown文档的各级标题(如 Header 1, Header 2 等)提取并存入每个文本块的元数据中。这些标题信息就是非常有价值的结构化数据,可以直接用于后续的元数据过滤。
通过这种方式,可以在检索时实现“元数据过滤”和“向量搜索”的结合。例如,当用户查询“请总结一下2023年第二季度财报中关于AI的论述”时,系统可以:
(1)元数据预过滤:首先通过元数据筛选,只在 document_type == '财报'、year == 2023 且 quarter == 'Q2' 的文档子集中进行搜索。
(2)向量搜索:然后,在经过滤的、范围更小的文本块集合中,执行针对查询“关于AI的论述”的向量相似度搜索。
这种“先过滤,再搜索”的策略,能够极大地缩小检索范围,显著提升大规模知识库场景下RAG应用的检索效率和准确性。LlamaIndex 提供了包括“自动检索”(Auto-Retrieval)在内的多种工具来支持这种结构化的检索范式。
