news 2026/7/14 17:04:03

Spring AI 集成 Milvus 实战:向量数据库从入门到 RAG 应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI 集成 Milvus 实战:向量数据库从入门到 RAG 应用

一、先搞懂向量数据库是干什么的

想象你去图书馆找书。传统数据库的工作方式像这样的对话:你问"有没有讲机器学习的书?",图书馆员只会找书名里带"机器学习"三个字的书。如果一本书叫《统计学习方法》,即使内容全是机器学习,他也找不到,因为名字不一样。

向量数据库就不一样了。它把人话转成一串数字(叫向量),然后比较这些数字的"远近"。"机器学习"和"统计学习方法"意思相近,向量就离得近;"机器学习"和"红烧肉"意思不相干,向量就离得远。所以它能按"意思"搜索,而不是按关键词。

Milvus 就是目前最主流的开源向量数据库。Zilliz 公司开发,2019 年开源,Linux Foundation AI 基金会项目。十亿级数据几十毫秒就能找出最相似的内容。

二、Spring AI 集成 Milvus 的整体流程

Spring AI 对 Milvus 的支持走的是 VectorStore 接口——和 JDBC 一个思路:统一接口,切换底层实现不用改业务代码。整体链路是这样的:

1. Embedding 模型把文档转成向量

2. Milvus 存这些向量(Collection + Index)

3. 用户提问时,同样的 Embedding 模型把问题也转成向量

4. Spring AI 调用 Milvus 做相似度搜索,返回最相关的文档片段

5. 把这些片段拼成 Prompt,发给大模型,得到最终回答

三、实战:搭一个 RAG 知识库

3.1 引入依赖

<!-- Spring AI Milvus 向量存储 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-milvus-store</artifactId> </dependency> <!-- Embedding 模型(用通义千问) --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-dashscope</artifactId> </dependency>

3.2 配置 Milvus 连接

spring: ai: dashscope: api-key: ${DASHSCOPE_API_KEY} chat: options: model: qwen3 vectorstore: milvus: uri: ${MILVUS_URI:http://localhost:19530} username: ${MILVUS_USERNAME:} password: ${MILVUS_PASSWORD:} database-name: default collection-name: knowledge_base index-type: HNSW metric-type: COSINE embedding-dimension: 768

几个配置项的含义:

index-type:索引类型。HNSW 精度高、速度快,适合在线检索。如果是超大数据量图省内存可以用 IVF_FLAT。

metric-type:距离计算方式。文本搜索一般用 COSINE(余弦相似度),因为不受向量长度影响。

embedding-dimension:你用的 Embedding 模型输出的向量维度。bge-base-zh 是 768,text-embedding-3 是 1536,要和模型对齐。

3.3 文档入库

Spring AI 自动注入了 VectorStore Bean,直接注入就能用:

@Service public class KnowledgeService { private final VectorStore vectorStore; public KnowledgeService(VectorStore vectorStore) { this.vectorStore = vectorStore; } /** * 把文档存进 Milvus * Spring AI 会自动调用 DashScope Embedding 模型把文本转成向量 */ public void addDocument(String content, String source) { Document doc = new Document(content, Map.of("source", source, "timestamp", Instant.now().toString())); vectorStore.add(List.of(doc)); } /** * 批量入库 */ @Transactional public void batchAdd(List<String> contents, String source) { List<Document> docs = contents.stream() .map(c -> new Document(c, Map.of("source", source))) .collect(Collectors.toList()); vectorStore.add(docs); } }

3.4 语义搜索 + RAG

用户提一个问题,先在 Milvus 里找到相关文档,再送给大模型生成回答:

@Service public class RagService { private final VectorStore vectorStore; private final ChatClient chatClient; public RagService(VectorStore vectorStore, ChatClient.Builder builder) { this.vectorStore = vectorStore; this.chatClient = builder.build(); } public String ask(String question) { // 1. 在 Milvus 中找到最相关的 3 个文档片段 List<Document> docs = vectorStore .similaritySearch(SearchRequest.query(question) .withTopK(3)); // 2. 把文档片段拼成上下文 String context = docs.stream() .map(d -> "【" + d.getMetadata().get("source") + "】" + d.getContent()) .collect(Collectors.joining("\n\n")); // 3. 发给大模型,生成回答 return chatClient.prompt() .user(u -> u.text(""" 基于以下知识回答问题。 如果知识不够,直接说不知道。 知识库内容: {context} 问题:{question} """) .param("context", context) .param("question", question)) .call() .content(); } }

3.5 加一个 Controller

@RestController @RequestMapping("/knowledge") public class KnowledgeController { private final KnowledgeService knowledgeService; private final RagService ragService; @PostMapping("/add") public Result add(@RequestBody AddDocDTO dto) { knowledgeService.addDocument(dto.content(), dto.source()); return Result.success(); } @PostMapping("/ask") public Result ask(@RequestBody AskDTO dto) { String answer = ragService.ask(dto.question()); return Result.success(answer); } }

四、Milvus 部署与注意事项

部署方式

开发测试用 Milvus Standalone,一个 docker-compose.yml 搞定:

# docker-compose.yml version: '3.5' services: etcd: image: quay.io/coreos/etcd:v3.5.16 environment: ETCD_AUTO_COMPACTION_MODE: revision ETCD_AUTO_COMPACTION_RETENTION: '1000' minio: image: minio/minio:RELEASE.2024-11-17T00-39-20Z standalone: image: milvusdb/milvus:v2.5.0 ports: - 19530:19530 # gRPC - 9091:9091 # HTTP depends_on: [etcd, minio]

几个坑

Embedding 维度要对齐:配置文件里的 embedding-dimension 必须和实际使用的模型一致,否则存进去搜不出来。

索引要显式创建:Spring AI 创建 Collection 时不会自动建索引,需要先调 createIndex() 或等数据量够了再建。也可以在配置里把 index-type 配好,Spring AI 会自动处理。

内存规划:向量数据在内存中检索最快。HNSW 索引的内存大约是数据量的 1.5-2 倍。如果是 10 亿条 768 维向量,大约需要 800GB 内存——这时候就用 DiskANN 或者上 GPU。

元数据过滤:Milvus 支持标量字段过滤(相当于 SQL 的 WHERE 条件),对常用过滤字段建标量索引能大幅提升混合检索性能。

五、进阶:自定义 Embedding 模型

如果你的场景需要特定的 Embedding 模型(比如中文效果更好的 bge-large-zh-v1.5),可以实现 EmbeddingModel 接口:

@Configuration public class MilvusConfig { @Bean public VectorStore milvusVectorStore(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel) { return new MilvusVectorStore(milvusClient, embeddingModel, MilvusVectorStoreConfig.builder() .withCollectionName("knowledge_base") .withIndexType(IndexType.HNSW) .withMetricType(MetricType.COSINE) .build()); } }

这样就能灵活切换不同的 Embedding 模型,不受 starter 自动配置的限制。

常见面试题与参考答案

1. Milvus 为什么比 ES 更适合向量检索?

参考答案:Elasticsearch 的向量检索插件(如 dense_vector)本质上还是暴力搜索或简单的 HNSW,性能和可扩展性有限。Milvus 从底层就是为向量设计的:支持多种 ANN 索引(IVF、HNSW、DiskANN)、支持 GPU 加速、有专门的调度和分片策略。在十亿级数据上,Milvus 的检索速度比 ES 快 2-3 个数量级。但 ES 在全文搜索和日志分析场景仍然不可替代,两个数据库通常是配合使用。

2. Spring AI 的 VectorStore 接口怎么切换不同的向量数据库?

参考答案:Spring AI 的 VectorStore 是顶层抽象接口,定义了 add()、similaritySearch()、delete() 等方法。Milvus、Pinecone、Weaviate、Pgvector 等都有各自的实现类。切换时只需换依赖和配置,业务代码不需要改动。比如从 Milvus 切到 Pgvector:把 spring-ai-milvus-store 换成 spring-ai-pgvector-store,修改 yml 中的连接配置,代码里的 VectorStore 注入不用动。

3. 向量检索的召回率(Recall)怎么保证?

参考答案:向量检索本质是近似搜索(ANN),不是精确搜索,所以召回率不可能 100%。影响召回率的关键因素:索引类型(HNSW 召回率高于 IVF)、索引参数(HNSW 的 efConstruction 和 ef、IVF 的 nprobe)、向量质量(Embedding 模型的好坏)。提召回率的常用方法:提高 ef/nprobe 参数(但会降低速度)、使用集成多索引投票、或者结合 BM25 关键词搜索做混合检索。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 17:03:47

openEuler summer2022:探索开源世界的终极入门指南

openEuler summer2022&#xff1a;探索开源世界的终极入门指南 【免费下载链接】summer2022 This reposiroty will provide the content of openEuler summer of code 2022. 项目地址: https://gitcode.com/openeuler/summer2022 前往项目官网免费下载&#xff1a;https…

作者头像 李华
网站建设 2026/7/14 17:02:24

Windows C盘空间优化:从系统机制到实战清理的完整方案

你的C盘是不是又红了&#xff1f;每次看到那个红色的空间不足提示&#xff0c;是不是既焦虑又无奈&#xff1f;删了几个文件后发现空间根本没释放多少&#xff0c;反而担心误删了系统文件导致电脑崩溃。作为一名长期与Windows系统打交道的开发者&#xff0c;我经历过太多次C盘爆…

作者头像 李华
网站建设 2026/7/14 17:02:20

数字治理落地:智能门锁如何破解网约房民宿合规与运营双重难题

随着全国公安、文旅部门对网约房、分散式民宿行业监管体系持续迭代完善&#xff0c;传统人工登记、线下值守、静态密码开锁的运营模式&#xff0c;已无法适配“实名、实人、实证、实时”的四实监管标准。分散式房源点位零散、租客流动性强、入住频次高、无固定前台的业态特性&a…

作者头像 李华
网站建设 2026/7/14 17:02:17

YOLOv8目标检测实战:从原理到蜜蜂识别系统完整实现

如果你正在寻找一个完整的深度学习项目来入门计算机视觉&#xff0c;或者需要为农业监测、生态研究等场景开发一个实用的蜜蜂识别系统&#xff0c;那么基于YOLOv8的蜜蜂识别检测系统可能正是你需要的解决方案。这个项目不仅包含了从数据标注到模型训练的全流程&#xff0c;还提…

作者头像 李华
网站建设 2026/7/14 17:01:41

高压隔离系统设计:ISOM8710与TM4C1294NCZAD应用指南

1. 高压安全隔离系统设计背景在工业控制和电力电子领域&#xff0c;高压安全隔离是保障人员和设备安全的关键技术。我曾参与过一个光伏逆变器项目&#xff0c;当时由于隔离设计不当&#xff0c;导致控制板在雷击测试中损坏&#xff0c;这个教训让我深刻认识到高压隔离的重要性。…

作者头像 李华
网站建设 2026/7/14 16:59:42

pyloudnorm终极指南:如何在Python中实现专业的音频响度测量

pyloudnorm终极指南&#xff1a;如何在Python中实现专业的音频响度测量 【免费下载链接】pyloudnorm Flexible audio loudness meter in Python with implementation of ITU-R BS.1770-4 loudness algorithm 项目地址: https://gitcode.com/gh_mirrors/py/pyloudnorm 想…

作者头像 李华