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

3 月 8 日
 xuxueli

1 、RAG 介绍

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

1.1 、RAG 基本原理

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

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

1.2 、RAG 应用场景

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

1.3 、RAG 核心技术

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

上述组件协同工作,使得 RAG 能够在保持大语言模型强大生成能力的同时,通过外部知识库提供更准确、更可靠的问答结果。 本文选型 “Milvus (向量数据库)、Qwen (生成模型)、Qwen-embedding (嵌入模型)及 SpringAI” 讲述及实践。

2 、向量数据库

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

2.1 、核心工作步骤

3 、Milvus 介绍

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

3.1 、核心架构层次

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

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 配置文件:

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 的使用门槛。

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 两类模型:

本文分别选择 “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 、核心设计原则(融合版)

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

实体分工总览

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

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

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 、 部分截图如下:

1911 次点击
所在节点    程序员
6 条回复
defunct9
3 月 9 日
好文。更详细的代码有吗
body007
3 月 9 日
学到了。感觉这个系统最难的就是第一步,用户问题如何在向量库搜索到最合适最匹配的记录。搜索分数大于 0.8 和小于 0.8 的结果差别可能很大啊。
landerwong99
3 月 9 日
分块的时候是不是要调整重叠度,免得块之间丢失必要的上下文
TheBlade
3 月 9 日
@landerwong99 对的, chunking 的时候要根据文档本身来做设计 或者你把前后 chunk 一起喂进去 避免上下文丢失 结构化比较好的文档 你可以根据章节切分 策略还是比较多的 还是看具体场景做一个比较好的 chunking 策略
GBQissac
3 月 10 日
文档分块目前的做法是,第一有章节的,挂章节树,然后分块,无章节的平铺分块,第二分块的时候使用滑动窗口分块,这样上下文有重叠度,不会怎么丢上下文
还有一个就是 milvs 有个毛病,就是设置密码的时候巨麻烦,之前搞那个密码登录搞了好久
xuxueli
3 月 15 日
相关代码在 GitHub ( “xxl-boot-plugin” 模块 ),若感兴趣可自取: https://github.com/xuxueli/xxl-boot

————————
@defunct9 @body007 @landerwong99 @TheBlade @GBQissac

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1196665

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX