使用Milvus搭配Ollama搭建RAG知识库

1、RAG介绍

RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索与文本生成的先进AI架构,其核心在于让大语言模型在回答问题前,先从外部知识库中"查找资料",再基于查到的信息生成准确、有依据的回答。这种方法有效缓解了大模型常见的知识过时、幻觉等问题。

1.1、RAG基本原理

RAG的工作流程可分为三个关键阶段:数据准备 → 检索 → 生成,形成一个"先查后答"的闭环机制。

  • 数据准备(索引阶段):将企业文档、网页、PDF等非结构化数据加载并切分为小块(chunking),例如每段300--800字符。 使用嵌入模型(如text-embedding-3-small)将文本块转化为向量,并存储于向量数据库中,便于后续语义检索。
  • 检索阶段(Retrieval): 当用户提问时,系统将问题也转化为向量。 在向量数据库中通过相似度匹配(如余弦相似度)检索出最相关的若干个文本片段。 可结合关键词检索(BM25)与语义检索(DPR)进行多路召回,提升召回率与精准度。
  • 生成阶段(Generation): 将检索到的相关片段与原始问题拼接成提示词(Prompt),输入大语言模型。 模型基于这些"参考资料"生成最终回答,确保内容有据可依,减少虚构风险。

RAG的准确率瓶颈本质上是"检索上下文质量"的瓶颈。如果检索不到正确信息,再强的生成模型也无法给出正确答案。

1.2、RAG应用场景

RAG因其灵活性和高准确性,已在多个领域实现落地应用,尤其适合需要专业性、实时性、可解释性的场景。

  • 企业知识库问答:员工可通过自然语言查询内部制度、产品手册、项目文档。 无需人工整理,系统自动检索并生成摘要,提升信息获取效率。
  • 智能客服与售后服务:客户咨询产品功能、退换货政策时,RAG可实时检索最新服务条款,避免因信息滞后导致误答。 支持个性化回复,如结合用户历史订单生成定制化建议。
  • 医疗与法律辅助决策:医生可输入患者症状,系统检索最新诊疗指南或临床研究,辅助诊断。律师查询合同条款时,RAG能从历史案例或法规库中提取相关判例,提升合规性。
  • 学术研究与文献综述:研究者提出研究问题后,RAG可快速检索大量论文摘要,并生成初步综述框架。节省查阅资料时间,提高科研效率。
  • 动态内容生成与新闻撰写:结合实时数据(如股市行情、体育赛事结果),RAG可生成带最新信息的报告或新闻稿。适用于财经、体育、舆情监控等对时效性要求高的领域。

1.3、RAG核心技术

RAG的核心技术组成主要包括以下几个关键部分:

  • 信息检索模块(Retrieval Module):负责从大规模文档库中检索与用户查询最相关的文档片段。通常使用向量数据库(如Faiss、Pinecone、Milvus)存储文档的向量表示,通过计算查询向量与文档向量的相似度来实现快速检索。检索算法可以是基于关键词的(如BM25)或基于语义的(如DPR、Sentence-BERT)。
  • 嵌入模型(Embedding Model):用于将文本(文档和查询)转换为固定长度的向量表示,以便进行语义相似度计算。常用的嵌入模型包括:Sentence-BERT(SBERT)、OpenAI的text-embedding模型、通义千问的QwenEmbedding等。嵌入模型的质量直接影响检索效果。
  • 生成模型(Generation Model):通常基于大语言模型(LLM),如GPT系列、通义千问、Llama等。接收检索到的相关文档片段和原始查询作为输入,生成最终的回答。生成模型需要具备良好的上下文理解和语言生成能力。
  • 检索-生成融合机制(Retrieval-Generation Fusion):将检索到的文档片段与原始查询组合成提示(Prompt),输入到生成模型中。这个过程可以是简单的拼接,也可以是更复杂的融合策略,如注意力机制。
  • 向量数据库(Vector Database):用于高效存储和检索高维向量数据。支持快速的近似最近邻(ANN)搜索,是实现大规模文档检索的关键。常见的向量数据库包括:Faiss、Pinecone、Milvus、Weaviate等。
  • 数据预处理与后处理:数据预处理包括文档清洗、分块、去除无关内容等,以提高检索效率和质量。后处理可能包括答案过滤、格式化输出、引用标注等,以提升最终回答的可读性和可信度。这些组件协同工作,使得RAG能够在保持大语言模型强大生成能力的同时,通过外部知识库提供更准确、更可靠的问答结果。

上述组件协同工作,使得RAG能够在保持大语言模型强大生成能力的同时,通过外部知识库提供更准确、更可靠的问答结果。

本文选型 "Milvus(向量数据库)、Qwen(生成模型)、Qwen-embedding(嵌入模型)及SpringAI" 讲述及实践。

2、向量数据库

向量数据库是专门用于存储、管理和高效检索高维向量数据的新型数据库系统,它能将文本、图像、音频等非结构化数据,通过AI模型转化为蕴含语义特征的向量序列,再基于向量间的相似度实现"语义级检索",解决传统数据库在非结构化数据处理上的局限性,为RAG智能问答、多模态搜索、智能推荐等AI应用提供底层支撑。

2.1、核心工作步骤

  • 数据向量化 :生成"特征指纹"。这是向量数据库的前置核心环节,需借助Embedding模型将原始非结构化数据转化为高维向量,同时要平衡向量维度:维度越高特征表达越精细、检索精度越高,但存储和计算成本会指数级增长;维度越低效率越高,但可能丢失关键特征导致精度下降,工业级常规选择文本768-1536维、图像512-2048维。
    • 文本数据:可选用OpenAI的text-embedding-ada-002(通用场景最优,1536维)、国产开源的BGE(性价比之选,768维)、微调后的BERT(细分领域首选)等模型。
    • 图像数据:CLIP(支持文本搜图的多模态适配模型)、ResNet(纯图像特征提取模型)是常用工具。
    • 音频数据:Wav2Vec2(语音转向量)、VGGish(音频场景特征提取)可满足需求。
  • 存储与索引构建:加速相似性计算。向量数据库会将生成的高维向量存储起来,并构建特殊索引结构来提升检索效率,常见索引算法有IVF(倒排文件)、HNSW(分层可导航小世界图)等,它们能大幅降低相似性计算的耗时。
  • 相似性检索 :找"最近邻"。当用户发起查询时,系统先将查询内容转为向量,再在数据库中寻找与其"距离最近"的Top-K个向量,常用的距离度量方式有三种:
    • 余弦相似度:最常用,只关注向量方向、忽略长度,适合语义级对比,如文本检索,计算结果取值范围[-1,1],越接近1相似度越高。
    • 欧氏距离:计算两个向量的直线距离,同时考虑方向与长度,适合关注绝对特征差异的场景,如图像检索,值越小相似度越高,需提前对向量进行归一化处理。
    • 点积相似度:计算速度最快,但受向量长度影响大,对向量进行L2归一化后,结果等价于余弦相似度,适合高并发低延迟场景,如实时推荐。

3、Milvus介绍

Milvus 是一款专为高维向量数据设计的云原生向量数据库,广泛应用于人工智能、机器学习和相似性搜索场景。它采用存储与计算分离的架构,具备高可用性、高性能和弹性扩展能力。

3.1、核心架构层次

Milvus 的系统架构分为四个主要层次:

  • 接入层(Access Layer):作为系统的入口,由一组无状态的 Proxy 组件构成,负责请求路由和负载均衡。
  • 协调服务(Coordinator Service):管理元数据、任务调度和状态同步,包括 Root Coordinator、Data Coordinator 和 Index Coordinator 等。
  • 执行节点(Worker Node):处理实际的数据插入、查询和索引构建等操作,包含 Query Node、Index Node 和 Data Node。
  • 存储层(Storage Layer):负责持久化存储,使用对象存储(如 S3、MinIO)来保存向量数据和索引文件,同时通过 etcd 和 Pulsar/Kafka 管理元数据和日志。

3.2、数据模型与存储机制:

维度 Milvus 关系型数据库 说明
数据组织结构 Database → Collection → Partition → Segment → Entity Database → Table → Row Milvus 以 Segment 为最小存储单元,支持分片;关系库以页或块为单位
存储介质 对象存储(S3/MinIO)+ 元数据存储(etcd)+ 消息队列(Pulsar/Kafka) 磁盘文件 + 日志(Redo Log) Milvus 使用对象存储持久化数据,元数据由 etcd 管理;关系库依赖本地存储
索引机制 支持多种 ANN 索引(HNSW、IVF、FLAT 等) B-tree、Hash、Bitmap 等 Milvus 为高维向量优化索引,支持近似搜索;关系库为低维结构化字段设计

3.3、术语映射关系:

Milvus 术语 关系型数据库术语 说明
Database Database 数据库是组织和管理数据的逻辑单元。为了提高数据安全性并实现多租户,你可以创建多个数据库,为不同的应用程序或租户从逻辑上隔离数据。Milvus 在集合之上引入了数据库层,为管理和组织数据提供了更有效的方式,同时支持多租户
Collection Table 数据集合,定义字段结构。用于存储和管理实体的主要逻辑对象。
Partition Partition 集合内的物理分区
Segment Page / Block 定义数据类型和数据属性的元信息。每个 Collections 都有自己的 Collections Schema,该 Schema 定义了 Collections 的所有字段、自动 ID(主键)分配启用和 Collection 说明
Field Column 字段类型支持标量与向量
Entity Row 单条数据记录
Index Index 向量索引,类型多样

4、Milvus本地部署

4.1、Docker Compose 部署

Milvus 提供了 Docker Compose 配置文件:

shell 复制代码
wget https://github.com/milvus-io/milvus/releases/download/v2.6.11/milvus-standalone-docker-compose.yml -O docker-compose.yml

sudo docker compose up -d

Creating milvus-etcd  ... done
Creating milvus-minio ... done
Creating milvus-standalone ... done

启动完成后可以访问 Milvus WebUI网址( http://127.0.0.1:9091/webui/ )了解有关 Milvus 实例的更多信息。

4.2、Attu(可视化工具)安装

Attu是 Milvus 官方推出的图形化管理工具,提供直观的可视化界面,方便用户查看和管理向量数据库。通过 Attu,用户可以轻松完成数据库架构设计、数据操作、向量搜索等复杂任务,大大降低 Milvus 的使用门槛。

shell 复制代码
docker run -d --name milvus-attu \
  -p 8000:3000 \
  -e MILVUS_URL=localhost:19530 \
  zilliz/attu:v2.6

Attu 启动完成后可以访问( http://localhost:8000 ),以图形化方式查看和管理Milvus 实例。

5、模型本地安装

RAG系统依赖Embedding与Generation两类模型:

  • 嵌入模型(Embedding Model):用于将文本(文档和查询)转换为固定长度的向量表示,以便进行语义相似度计算。常用的嵌入模型包括:Sentence-BERT(SBERT)、OpenAI的text-embedding模型、通义千问的QwenEmbedding等。嵌入模型的质量直接影响检索效果。
  • 生成模型(Generation Model):通常基于大语言模型(LLM),如GPT系列、通义千问、Llama等。接收检索到的相关文档片段和原始查询作为输入,生成最终的回答。生成模型需要具备良好的上下文理解和语言生成能力。

本文分别选择 "qwen3-embedding" 与 "qwen3.5" 作为嵌入模型与生成模型,Ollama本地安装如下;

复制代码
admin@Mac-miniM4 milvus % ollama list
NAME                                ID              SIZE      MODIFIED    
qwen3.5:2b                          324d162be6ca    2.7 GB    3 hours ago    
qwen3-embedding:0.6b                ac6da0dfba84    639 MB    4 hours ago    

6、RAG系统设计

RAG 知识库的核心价值在于「结构化检索(关系型)+ 语义检索(向量)」的融合,实体模型设计需同时兼顾关系型数据的结构化关联能力和向量数据的语义匹配能力,既要保证实体间的逻辑关联清晰,又要实现基于语义的精准检索。以下聚焦「关系型 + 向量数据融合」的实体模型设计,包含核心实体定义、数据存储分工、关联逻辑、落地实现四大核心模块。

6.1、核心设计原则(融合版)

  • 分工明确:关系型数据库(MySQL)存储「实体元数据、关联关系、检索过滤条件」,向量数据库(Milvus)存储「文本语义向量」,避免单库承载所有压力;
  • 双向关联:关系型数据与向量数据通过唯一 ID(chunk_id)绑定,支持「从关系型维度筛选→向量语义检索」「从向量检索结果→回溯关系型元数据」;
  • 轻量化融合:向量数据仅存储核心检索单元(Chunk)的向量,不冗余存储文档 / 实体的全量向量,关系型数据补充向量无法表达的结构化信息(如实体类型、文档来源)。

6.2、核心实体模型(关系型 + 向量融合)

实体分工总览

数据类型 存储载体 存储内容 核心作用
关系型数据 MySQL/PostgreSQL 文档 / Chunk / 业务实体的元数据、实体间关联关系、检索过滤字段(状态 / 租户 / 类型) 结构化筛选、实体关联、结果回溯
向量数据 Milvus/PGVector/FAISS Chunk 的 Embedding 向量、向量索引(IVF_FLAT/HNSW) 语义相似度检索

关系型实体表设计(核心元数据 + 关联)

  • Knowledge(知识库实体,关系型):存储知识库定义元数据,维护知识库Embedding模型、向量数据库设置信息。

  • Document(文档实体,关系型):存储文档级结构化元数据,是所有子实体的根节点,不存储完整内容和向量。

  • Chunk (文本块实体,关系型):

    存储 Chunk 的元数据,仅保留向量 ID(与向量库绑定),不存储原始向量,是关系型与向量数据的核心桥梁。

  • 向量数据模型设计(语义检索核心)

    Milvus 中创建「knowledge_vector_collection」集合,与关系型 Chunk 表的vector_id一一对应:

7、RAG关键代码

7.1、Maven依赖引入

使用SpringAI进行模型与向量数据库集成,需要添加如下依赖:

复制代码
<!-- milvus -->
<dependency>
    <groupId>io.milvus</groupId>
    <artifactId>milvus-sdk-java</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>

7.2、知识数据向量化入库

核心流程为:「文档分块 → 向量化 → Milvus 入库」

复制代码
// 1、初始化Embedding模型
EmbeddingModel embeddingModel = OllamaEmbeddingModel
                .builder()
                .defaultOptions(OllamaEmbeddingOptions
                        .builder()
                        .model(EMBEDDING_MODEL_NAME)
                        .dimensions(VECTOR_DIMENSION)
                        .build())
                .ollamaApi(ollamaApi)
                .build();

// 2、知识文档正文分块
List<String> chunks = splitDocument(doc.getContent());

// 3、Chunk文档向量化处理
List<float[]> vectors = embeddingModel.embed(texts);

// 4、知识数据向量化入库
List<JsonObject> vectorData = process(vectors);
UpsertResp upsertResp = client.upsert(UpsertReq.builder()
                .collectionName(collectionName)
                .data(vectorData)
                .build());

7.3、知识相似度检索

核心流程为:「问题向量化 → Milvus 检索」

复制代码
// 1、问题向量化
float[] keywordVector = embed(List.of(keyword)).get(0);

// 2、向量 检索
SearchReq searchReq = SearchReq.builder()
                    .collectionName(buildCollectionName(kbId))                          		
                    .data(Collections.singletonList(new FloatVec(keywordVector)))  
                    .annsField("contentVector")                                         			
                    .outputFields(Arrays.asList("id", "chunkId", "contentVector"))     
                    .limit(TOP_K_COUNT)
                    .searchParams(Map.of("radius", SIMILARITY_THRESHOLD))   // 相似度阈值
                    .build();
SearchResp searchResp = client.search(searchReq);

7.4、知识库系统交互

知识库系统交互见下文,支持针对文档进行新建、管理、向量化/Embedding、相似度检索等操作。为RAG、

部分截图如下:

  • 知识库管理:

  • 知识相似度检索: