前置文章JAVA25 Spring Boot 4.1.0 Spring AI 2.0.1 调用 DeepSeek 模型JAVA25 Spring Boot 4.1.0 Spring AI 2.0.1 加载本地 embeddings 模型 bge-m3前言向量数据库是一种特殊类型的数据库在人工智能应用中扮演着至关重要的角色。向量数据库的查询方式与传统关系型数据库有所不同它不进行精确匹配而是执行相似性搜索。当以向量作为查询条件时向量数据库会返回与查询向量“相似”的向量。关于相似度的具体计算方式请参阅“向量相似性”一节。向量数据库用于将数据与人工智能模型集成。使用向量数据库的第一步是把数据加载到向量数据库中随后当用户向人工智能模型发起查询时系统会先检索出一组相似的文档这些文档将作为用户问题的上下文与用户的查询一并发送给人工智能模型。这种技术被称为检索增强生成RAG。Spring AI 提供了大量接口支持多种向量数据库实现并附有若干进阶用法示例。详细信息可查阅官方文档Spring AI 官网 Vector DatabasesSpring AI 官网 Vector Databases Milvus本文在前置文章的基础上进一步扩展讲解如何在项目中使用 Spring AI 对接 Milvus 向量数据库。注意请务必先完成前置文章JAVA25 Spring Boot 4.1.0 Spring AI 2.0.1 加载本地 embeddings 模型 bge-m3中的配置否则项目启动时会报错。一、安装 Milvus 3.0.xMilvus 3.0.x 版本里面会更新了很多功能为了以后扩展建议安装 Milvus 3.0.x。Milvus 官网Milvus 官网安装页面安装 Milvuswgethttps://github.com/milvus-io/milvus/releases/download/v3.0.3/milvus-standalone-docker-compose.yaml-Odocker-compose.yamlsudodockercompose up-dCreating milvus-etcd...doneCreating milvus-minio...doneCreating milvus-standalone...done注意指令在哪个文件夹下运行会在当前目录创建数据文件创建的数据文件记得给权限否则docker 启动有可能报错。停止并删除 Milvussudodockercompose downsudorm-rfvolumes安装 Milvus 连接工具Attu 首页下载 Attu 页面二、Maven 引入!-- Milvus 向量存储 Spring AI 官方 Starter --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-vector-store-milvus/artifactId/dependency三、添加 application.yml 配置# Spring 配置spring:# Spring AI 配置 ai:# 向量库配置 vectorstore:# Milvus 向量库配置 milvus:client:# 连接 Milvus 向量库 IPhost:121.43.122.232# 连接 Milvus 向量库端口port:19530# username: root# password: Milvus#默认数据库名称databaseName:default#数据库中集合名称collectionName:vector_store#存入 Milvus 的向量Embedding的维度大小 务必与 向量化模型 输出维度一致embeddingDimension:1024# 索引类型 IVF_FLAT适合中等规模数据平衡查询速度和精度indexType:IVF_FLAT# 相似度度量类型 COSINE 余弦相似度常用于文本向量metricType:COSINE#是否要为你自动在 Milvus 中创建用于存储向量数据的集合Collection及其结构SchemainitializeSchema:true四、创建 DTO向量新增修改请求参数记录对象importio.swagger.v3.oas.annotations.media.Schema;importlombok.*;importlombok.experimental.Accessors;importorg.springframework.ai.document.Document;importjava.io.Serial;importjava.io.Serializable;importjava.util.List;/** * description: 向量新增修改请求参数记录对象 * author: LIHAO * createDate: 2026-11-02 17:13:49 */DataBuilder(toBuildertrue)WithNoArgsConstructorAllArgsConstructorAccessors(chaintrue)Schema(title向量新增修改请求参数对象)publicclassVectorUpsertRequestimplementsSerializable{SerialprivatestaticfinallongserialVersionUID1L;Schema(description存储名称用于标识使用的向量存储实例RedisVectorStore Bean名称主要作用获取集合名称如果传递collectionName参数以collectionName参数为主。没有传递以storeBeanName获取为主)privateStringstoreBeanName;Schema(description集合名称)privateStringcollectionName;Schema(description分区名称一个数据库中一个集合里面的不同分区名称)privateStringpartitionName;Schema(description拆分好的文档数据,requiredModeSchema.RequiredMode.REQUIRED)privateListDocumentdocumentList;}向量检索请求参数importio.swagger.v3.oas.annotations.media.Schema;importlombok.*;importlombok.experimental.Accessors;importjava.io.Serial;importjava.io.Serializable;importjava.util.List;/** * description: 向量检索请求参数 * author: LIHAO * createDate: 2026-11-02 17:13:58 */DataBuilder(toBuildertrue)WithNoArgsConstructorAllArgsConstructorAccessors(chaintrue)Schema(title向量检索请求参数对象)publicclassVectorQueryRequestimplementsSerializable{SerialprivatestaticfinallongserialVersionUID1L;Schema(description向量数据id)privateStringid;Schema(description向量数据id集合)privateListStringidList;Schema(description存储Bean名称用于标识使用的向量存储实例RedisVectorStore Bean名称)(主要作用获取集合名称如果传递collectionName参数以collectionName参数为主。没有传递以storeBeanName获取为主))privateStringstoreBeanName;Schema(description集合名称)privateStringcollectionName;Schema(description分区名称一个数据库中一个集合里面有不同分区名称)privateStringpartitionName;Schema(description检索文本,requiredModeSchema.RequiredMode.AUTO)privateStringtext;Schema(description返回结果数量可为空使用系统默认值通常为4)privateIntegertopK;Schema(description相似度阈值仅返回相似度高于此值的文档范围通常为0~1可为空系统默认值通常为0.0无阈值限制)privateFloatsimilarityThreshold;Schema(description是否重排序true重排序false不重排序)privateBooleanisReranker;Schema(description元数据过滤条件用于在检索时对文档元数据进行过滤如果添加向量时是章节拆分默认添加元数据字段fileName文件名称、chapters章、section节、subsection小节、detailedChapters章/节/小节语法示例metadata[country] UK metadata[year] 2020 metadata[isActive] true Or metadata[country] BG (metadata[city] NOT IN [Sofia, Plovdiv] || price 134.34))privateStringmetaDataWhere;Schema(description分词匹配词间隔位置允许匹配词之间最多间隔几个位置0代表必须相邻中间没有间隔位置。只限于短语匹配)privateIntegerslop;}五、创建向量库操作 Serviceimportcom.lh.vectorDatabases.milvus.dto.VectorQueryRequest;importcom.lh.vectorDatabases.milvus.dto.VectorUpsertRequest;importlombok.extern.slf4j.Slf4j;importorg.apache.commons.collections4.CollectionUtils;importorg.apache.commons.lang3.StringUtils;importorg.springframework.ai.document.Document;importorg.springframework.ai.vectorstore.SearchRequest;importorg.springframework.ai.vectorstore.VectorStore;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.util.Assert;importjava.util.List;importjava.util.Map;/** * description: Milvus Store 向量操作 * author: LIHAO * createDate: 2026-11-02 15:05:58 */Slf4jService(milvusVectorStoreService)publicclassMilvusVectorStoreService{privateVectorStorevectorStore;publicMilvusVectorStoreService(VectorStorevectorStore){this.vectorStorevectorStore;}/** * description: 新增或修改向量数据 * author: LIHAO * createDate: 2026-11-02 17:16:58 * param: [storeBeanName RedisVectorStore Bean名称, documentList] * return: void */publicvoidupsert(VectorUpsertRequestvectorAddRequest){ListDocumentdocumentParamtListvectorAddRequest.getDocumentList();// 检查集合不为空Assert.notEmpty(documentParamtList,MilvusVectorStoreService#upsert参数vectorRequest#documentList不能为空);//新增或修改数据vectorStore.add(documentParamtList);}/** * description: 根据数据id据删除数据 * author: LIHAO * createDate: 2026-11-02 17:16:58 * param: [storeBeanName RedisVectorStore Bean名称, idList 数据id] * return: void */publicvoiddeleteById(VectorQueryRequestvectorRequest){ListStringidListvectorRequest.getIdList();// 检查集合不为空Assert.notEmpty(idList,MilvusVectorStoreService#deleteById参数vectorRequest#idList不能为空);if(CollectionUtils.isNotEmpty(idList)){//删除数据vectorStore.delete(idList);}}/** * description: 根据文本查询相关向量数据如语义搜索 * author: LIHAO * createDate: 2026-11-02 17:16:58 * param: [vectorRequest] * return: java.util.Listorg.springframework.ai.document.Document */publicListDocumentsearchByVector(VectorQueryRequestvectorRequest){//搜索内容StringtextvectorRequest.getText();//检查字符串不为空不是 null且长度 0Assert.hasLength(text,MilvusVectorStoreService#searchByVector,参数vectorRequest#text不能为空);// 构建 SearchRequest先设置固定参数SearchRequest.BuilderbuilderSearchRequest.builder().query(vectorRequest.getText());// 查询文本//获取搜索结果数量IntegertopKvectorRequest.getTopK();// 仅当 topK 不为 null 时才设置 topK否则使用系统默认值4由 RedisVectorStore 决定if(topK!nulltopK0){builder.topK(topK);}//获取相似度阈值仅返回相似度高于此值的文档范围通常为0~1可为空系统默认值通常为0.0无阈值限制FloatsimilarityThresholdvectorRequest.getSimilarityThreshold();// similarityThreshold 不为 null 时才设置 similarityThreshold否则使用系统默认值0.0由 RedisVectorStore 决定if(similarityThreshold!nullsimilarityThreshold0.0similarityThreshold1.0){builder.similarityThreshold(similarityThreshold);// 相似度阈值若为 nullbuilder 可能使用默认值}//元数据过滤条件用于在检索时对文档元数据进行过滤StringmetaDataWherevectorRequest.getMetaDataWhere();// 判断是否有元数据过滤if(StringUtils.isNotBlank(metaDataWhere)){builder.filterExpression(metaDataWhere);// 元数据过滤条件 metaDataWhere}// 生成最终的 SearchRequest 对象SearchRequestsearchRequestbuilder.build();//查询向量数据ListDocumentresultsvectorStore.similaritySearch(searchRequest);returnresults;}}六、测试用例Maven 引入!-- Milvus 向量存储 Spring AI 官方 Starter --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-vector-store-milvus/artifactId/dependencyjava代码importcom.lh.vectorDatabases.milvus.dto.VectorQueryRequest;importcom.lh.vectorDatabases.milvus.dto.VectorUpsertRequest;importcom.lh.vectorDatabases.milvus.service.MilvusVectorStoreService;importlombok.extern.slf4j.Slf4j;importorg.apache.commons.collections4.CollectionUtils;importorg.junit.jupiter.api.Test;importorg.springframework.ai.document.Document;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importjava.util.List;importjava.util.Map;Slf4jSpringBootTestpublicclassOriginApplicationTest{AutowiredprivateMilvusVectorStoreServicemilvusVectorStoreService;TestpublicvoidmilvusVectorStoreTest(){ListDocumentdocumentsList.of(newDocument(今天天气很好,Map.of(meta1,meta1)),newDocument(世界很大救赎就在拐角处),newDocument(你面对过去向前走然后转身面向未来。,Map.of(meta2,meta2)));//新增数据milvusVectorStoreService.upsert(VectorUpsertRequest.builder().documentList(documents).build());//查询数据ListDocumentresultsmilvusVectorStoreService.searchByVector(VectorQueryRequest.builder().text(今天).topK(20).build());System.out.println(results);if(CollectionUtils.isNotEmpty(results)){ListStringidListresults.stream().map(Document::getId).toList();//根据id删除数据milvusVectorStoreService.deleteById(VectorQueryRequest.builder().idList(idList).build());}}}七、总结本文围绕 Spring AI 对接 Milvus 向量数据库完整走通了从环境搭建到代码落地的全流程主要包含以下几个环节环境准备通过 Docker Compose 安装 Milvus 3.0.x并使用 Attu 作为可视化管理工具方便查看集合与向量数据。依赖与配置引入spring-ai-starter-vector-store-milvus官方 Starter在application.yml中完成连接地址、集合名称、向量维度、索引类型与相似度度量等关键参数配置。请求对象封装通过VectorUpsertRequest与VectorQueryRequest统一承载新增、删除、检索所需的参数便于后续扩展与复用。服务层实现MilvusVectorStoreService基于 Spring AI 的VectorStore抽象实现了向量新增/修改、按 ID 删除以及基于文本的相似性检索并对入参做了必要的校验。测试验证通过单元测试完成「写入 → 检索 → 删除」的闭环验证确认配置与代码均可正常工作。需要特别注意的几点embeddingDimension必须与所用向量化模型如 bge-m3的输出维度保持一致否则写入时会报维度不匹配错误。initializeSchema: true可让 Spring AI 自动创建集合与 Schema生产环境建议改为手动管理避免误建或结构变更。检索时topK、similarityThreshold等参数可按业务场景灵活调整配合metaDataWhere元数据过滤能显著提升召回质量。至此Spring AI Milvus 的基础集成已经完成。后续可以在此基础上继续扩展接入 RAG 问答链路、结合重排序模型优化召回结果或将向量检索能力封装为统一的内部服务供多个业务模块调用。
企业数字化 ERP 产品动态
相关推荐
超重载高抗脉冲风冷却器:如何抵御液压油锤冲击? 在锻压、压铸、铝挤压等重载液压设备中,冷却器不仅要承担散热任务,还要面对频繁动作带来的压力波动。本文面向重载液压设备用户,从液压油锤的成因讲起,说明压力脉冲如何影响冷却器的芯体、油道与接口,并梳理高抗脉冲风… · 2026/11/4 19:58:17
从一家奶茶店讲透 Redis:缓存、持久化与高可用的一次完整拆解 下午四点,店里挤了二十多号人,收银台的小票机"嘀嘀"响成一片。你低头刷 App,"焦糖云朵拿铁"那一行转了八秒圈,最后弹出一句"该商品已售罄"。可隔壁桌那位客人手里,正举着同一杯。 这不是… · 2026/11/4 19:58:17
我们小区上了智慧社区小程序,半年后业主常打开的是这些 我们小区上了智慧社区小程序,半年后业主常打开的是这些
一、半年后还在被打开的功能,只有三类
半年下来,业主反复打开的入口集中在缴费、报修和通知三类,其余功能多是上线时热闹一阵。 以下是我们小区的观察记录,属行… · 2026/11/4 19:58:17
鸿蒙 Map Kit 地图开发:控件交互、事件交互与选点性能优化 1. 先拆标题:Map Kit 这次讲的不是“画地图”,而是“让地图活起来” 鸿蒙 Map Kit 地图这个话题,很多人第一反应是“把地图显示出来”,以为调个组件、传个坐标就完事了。真做过的人都知道,把地图渲染出来只是整件事的起… · 2026/11/4 20:37:49
CC-Switch:多AI编程工具配置档案与一键切换 多装几套命令行 AI 编程工具,几乎是这两年一线开发者的常态。终端里一个窗口跑对话式编码助手、IDE 里挂着补全插件、再加一个专门做大批量重构的 Agent,还有一个只能在公司内网用的私有化版本——四个工具、四套密钥、四份配置文件、四种环境变量命名规… · 2026/11/4 20:37:49
Agent服务化落地:RPC、SDK、Web界面与安全防护全攻略 做 Pi Agent 这个项目做到第六篇,我自己最明显的感受是:代码能力已经不是瓶颈,生态才是。前面几篇我都在讲内核,讲任务编排、工具调用、记忆结构和对话流程,但一个 Agent 框架如果只在自己机器上跑通,价值始… · 2026/11/4 20:37:49
Qt MinGW 32位工程接入FFmpeg 3.4:解码编码与避坑指南 简介:面向32位Windows平台及MinGW32、Qt开发环境的多媒体开发包,提供FFmpeg 3.4预编译头文件、导入库、动态库与示例源码,适合在C/C项目中集成音视频编解码、格式转换、滤镜处理和流媒体功能的开发者。压缩包共170个文件,以107个h… · 2026/11/4 20:37:49
栈结构实现括号匹配:原理与C++/Java代码详解 1. 括号匹配问题的核心思路括号匹配是数据结构与算法中的经典问题,也是栈这一数据结构的典型应用场景。这个问题的核心在于验证一个字符串中的括号是否正确配对和嵌套。让我们先从一个实际开发中的例子说起。去年我在参与一个大型项目的编译器模块开发时,… · 2026/11/4 20:37:49
Unity远距离贴图闪烁根因与7步精准修复指南 1. 项目概述:为什么远距离贴图闪烁不是“玄学”,而是可定位、可修复的工程问题Unity里模型一拉远就出现“雪花噪点”“彩色马赛克”“忽明忽暗的抖动”——很多开发者第一反应是“显卡不行”“Shader写错了”“压缩格式有问题”,甚至反复重装… · 2026/11/4 20:36:43
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38