news 2026/4/15 14:44:18

Spring AI 高级:RAG 优化与向量数据库集成实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI 高级:RAG 优化与向量数据库集成实战

上一篇文章中Spring AI 进阶:RAG 技术原理拆解与本地知识库检索落地
,我们完成了 RAG 本地知识库检索的基础版本开发,其核心目标在于验证 RAG 技术的基础链路可行性。但该版本仅适用于技术验证场景,无法直接满足实际业务的生产级需求。接下来,本文将聚焦 RAG 技术的优化升级,通过集成 Milvus 向量数据库打造可直接落地的生产级 RAG 应用。

一、优化方向与核心策略

之前,我们归纳了基于 RAG 技术落地实践中存在的核心痛点。在正式开展优化工作之前,需先围绕这些痛点明确对应的优化方向与实施策略,以保障优化方案的精准性与有效性。

二、优化准备:Milvus 向量数据库部署与集成

1. 什么是 Milvus?
Milvus 是一款开源的高性能向量数据库,专为 AI 场景设计,支持海量向量数据的存储、检索与管理。它具备以下核心优势:

支持多种距离计算(余弦相似度、欧氏距离等),适配 Embedding 向量检索场景。
高吞吐量与低延迟,可满足大规模知识库的快速检索需求。
兼容 Spring AI 生态,通过 Spring AI Starter 可快速集成。

2. Milvus 部署(Docker 方式)
步骤 1:安装 Docker 与 Docker Compose
确保本地已安装 Docker(版本 20.10+)与 Docker Compose(版本 2.10+),安装教程参考 Docker 官方文档。

步骤 2:下载 Milvus 配置文件

# 创建Milvus目录 mkdir-p/software/milvus&&cd/software/milvus # 下载 docker-compose.yml 文件 wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml-Odocker-compose.yml

步骤 3:启动 Milvus

# 后台启动Milvusdocker compose up-d # 查看启动状态(确保所有容器都为 running 状态) docker compose ps

启动成功后,Milvus 服务默认监听端口 19530(gRPC)与 9091(HTTP)。

Milvus提供了后台管理服务,默认地址:http://10.8.0.233:8000/#

3. Spring AI 集成 Milvus 依赖配置
在 Spring Boot 项目(可以复制之前的Weiz-SpringAI-RAG项目)的 pom.xml 中添加 Milvus 依赖:

<!--Milvus向量数据库Starter--><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-vector-store-milvus</artifactId></dependency>

4. 配置 Milvus 连接信息
在 src/main/resources/application.properties 中添加 Milvus 配置:

spring.application.name=Weiz-SpringAI-RAG-Milvusserver.port=8080#AIEmbeddingspring.ai.zhipuai.api-key=你的智谱api key spring.ai.zhipuai.base-url=https://open.bigmodel.cn/api/paas spring.ai.zhipuai.embedding.options.model=embedding-2# AIChatspring.ai.zhipuai.chat.options.model=GLM-4-Flash#Milvus连接配置 spring.ai.vectorstore.milvus.client.host=10.8.0.233spring.ai.vectorstore.milvus.client.port=19530# 认证信息 spring.ai.vectorstore.milvus.client.username=root spring.ai.vectorstore.milvus.client.password=hadoop # 数据库名称(默认default) spring.ai.vectorstore.milvus.database-name=default# 向量集合名称(自定义,不存在会自动创建) spring.ai.vectorstore.milvus.collection-name=travel_safety_embedding # 是否自动初始化Schema(建议开启) spring.ai.vectorstore.milvus.initialize-schema=true# 向量维度(与智普 AI embedding-2模型一致,为1024) spring.ai.vectorstore.milvus.embedding-dimension=1024

三、RAG 优化实战:生产级本地知识库检索

1. 编写优化后的 RAG Service
创建 com.example.weizspringai.service.RagOptimizedService 类,实现优化后的 RAG 逻辑:

importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.ai.document.Document;importorg.springframework.ai.embedding.EmbeddingModel;importorg.springframework.ai.reader.TextReader;importorg.springframework.ai.transformer.splitter.TokenTextSplitter;importorg.springframework.ai.vectorstore.VectorStore;importorg.springframework.core.io.ClassPathResource;importorg.springframework.core.io.Resource;importorg.springframework.stereotype.Service;importjakarta.annotation.PostConstruct;importjava.io.IOException;importjava.nio.charset.StandardCharsets;importjava.util.ArrayList;importjava.util.List;importjava.util.Set;importjava.util.TreeSet;importjava.util.stream.Collectors;@ServicepublicclassRagOptimizedService{// 注入核心依赖privatefinalEmbeddingModelembeddingModel;privatefinalChatClientchatClient;privatefinalVectorStorevectorStore;// 缓存切分后的文本片段,避免重复读取privatefinalList<String>docChunks=newArrayList<>();// 构造方法注入依赖publicRagOptimizedService(EmbeddingModelembeddingModel,ChatClient.BuilderchatClientBuilder,VectorStorevectorStore){this.embeddingModel=embeddingModel;this.chatClient=chatClientBuilder.build();this.vectorStore=vectorStore;}/** * 项目启动时初始化:加载知识库、切分文本、向量入库(仅执行一次) */@PostConstructpublicvoidinitKnowledgeBase()throwsIOException{System.out.println("开始初始化知识库,加载文件并写入 Milvus 向量数据库...");// 1. 加载本地知识库文件(户外旅行安全指南)Resourceresource=newClassPathResource("户外旅行安全指南.txt");TextReadertextReader=newTextReader(resource);List<Document>rawDocs=textReader.read();// 2. 优化文本切分(TokenTextSplitter 按语义切分)TokenTextSplittertextSplitter=TokenTextSplitter.builder().withChunkSize(800)// 每段最大 800 Token.withMinChunkSizeChars(400)// 每段最小 400 字符(避免过短).withKeepSeparator(true)// 保留分隔符,提升语义连贯性.build();List<Document>splitDocs=textSplitter.apply(rawDocs);// 3. 缓存文本片段,同时将向量写入 Milvusfor(Documentdoc:splitDocs){Stringtext=doc.getText().strip();if(!text.isBlank()){docChunks.add(text);// 向量入库(Spring AI 自动调用 EmbeddingModel 完成向量化)vectorStore.add(List.of(doc));}}System.out.println("知识库初始化完成,共加载 "+docChunks.size()+" 个文本片段");}/** * 处理用户提问,返回优化后的 RAG 回答 * @param question 用户问题 * @return 大模型生成的回答 */publicStringanswer(Stringquestion){// 1. 生成用户问题的向量float[]questionVector=embeddingModel.embed(question);// 2. 检索相关片段:Top5 + 相似度阈值 + 相邻片段扩展List<String>relevantChunks=retrieveRelevantChunks(questionVector,5,0.05);// 3. 构建上下文(拼接相关片段,去除重复内容)Stringcontext=relevantChunks.stream().distinct().collect(Collectors.joining("\n---\n"));// 4. 构建提示词(明确要求基于上下文回答,禁止添加额外信息)Stringprompt=String.format("以下是户外旅行安全指南的知识库内容:\n%s\n请严格基于上述内容,简洁、准确地回答用户问题,不要添加额外信息。问题:%s",context,question);// 5. 调用 Chat 模型生成回答returnchatClient.prompt().system("你是专业的户外旅行安全助手,仅基于提供的上下文回答问题,若上下文无相关信息,回复'抱歉,未查询到相关安全指南信息'。").user(prompt).call().content();}/** * 检索相关文本片段:TopK + 相似度阈值 + 相邻片段扩展 * @param questionVector 问题向量 * @param topK 最多返回 K 个相似片段 * @param threshold 相似度阈值(低于该值的片段过滤) * @return 最终用于构建上下文的片段列表 */privateList<String>retrieveRelevantChunks(float[]questionVector,inttopK,doublethreshold){// 存储需要保留的片段索引(TreeSet 自动去重并排序)Set<Integer>targetIndexes=newTreeSet<>();// 1. 计算问题向量与所有片段向量的相似度List<ChunkSimilarity>similarityList=newArrayList<>();for(inti=0;i<docChunks.size();i++){float[]chunkVector=embeddingModel.embed(docChunks.get(i));doublesim=SimilarityCalculator.cosineSimilarity(questionVector,chunkVector);// 过滤低于阈值的低相关片段if(sim>=threshold){similarityList.add(newChunkSimilarity(i,sim));}}// 2. 按相似度降序排序,取 TopK 个高相关片段similarityList.sort((a,b)->Double.compare(b.similarity,a.similarity));List<ChunkSimilarity>topKInfos=similarityList.stream().limit(topK).collect(Collectors.toList());// 3. 扩展相邻片段(每个相关片段的前后各 1 个),提升上下文连贯性for(ChunkSimilarityinfo:topKInfos){intindex=info.index;targetIndexes.add(index);// 当前高相关片段if(index-1>=0){targetIndexes.add(index-1);// 前一个相邻片段}if(index+1<docChunks.size()){targetIndexes.add(index+1);// 后一个相邻片段}}// 4. 转换为文本片段列表返回returntargetIndexes.stream().map(docChunks::get).collect(Collectors.toList());}/** * 辅助类:存储文本片段索引与相似度 */privatestaticclassChunkSimilarity{intindex;doublesimilarity;ChunkSimilarity(intindex,doublesimilarity){this.index=index;this.similarity=similarity;}}}

2. 编写优化后的 RAG Controller
创建 com.example.weizspringai.controller.RagOptimizedController 类,提供优化后的 RAG 检索接口:

importcom.example.weizspringai.service.RagOptimizedService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;importjava.util.Map;@RestController@RequestMapping("/rag/optimized")publicclassRagOptimizedController{@AutowiredprivateRagOptimizedServiceragOptimizedService;/** * 优化后的 RAG 本地知识库检索接口 * @param question 用户问题 * @return 包含问题与回答的响应 */@GetMapping("/ask")publicMap<String,String>ask(@RequestParam("question")Stringquestion){Stringanswer=ragOptimizedService.answer(question);returnMap.of("question",question,"answer",answer);}}

3. 测试优化后的 RAG 系统
测试 1:查询复杂问题(需要多片段拼接)
访问 http://localhost:8080/rag/optimized/ask?question=户外旅行中露营、徒步、城市漫游分别有哪些核心安全注意事项?,响应结果:

{"question":"户外旅行中露营、徒步、城市漫游分别有哪些核心安全注意事项?","answer":"户外旅行中三类场景的核心安全注意事项如下:\n1. 露营安全:选址避开低洼积水区、陡坡和落石区域,优先选平坦硬质地面;远离易燃物,使用炉具保持通风,睡前熄灭明火;携带驱蚊液和防虫网,避免在草丛密集处搭帐篷;随身携带手电筒、急救包和足量饮用水,提前下载离线地图。\n2. 徒步安全:提前查询路线难度和天气,选择适配自身体能的路线并告知亲友行程;穿防滑登山鞋、戴防晒帽,携带充足食物、水、登山杖和护膝;遇暴雨立即找高地躲避,不涉险过河,遭遇野生动物保持冷静不投喂;匀速前进,每小时休息10-15分钟,避免过度疲劳。\n3. 城市漫游安全:骑行遵守交通规则,不逆行闯红灯,佩戴安全头盔;乘坐公共交通妥善保管个人财物;避开偏僻小巷和治安较差区域,优先选择人流密集的商业街区和景点;保存当地派出所、医院联系方式,携带少量现金,保持手机电量充足。"}

测试 2:查询低相关问题(验证阈值过滤)
访问http://localhost:8080/rag/optimized/ask?question=室内健身房锻炼有哪些安全要点?,响应结果:

{"question":"室内健身房锻炼有哪些安全要点?","answer":"抱歉,未查询到相关安全指南信息"}

测试 3:查询需要上下文扩展的问题
访问 http://localhost:8080/rag/optimized/ask?question=徒步时遇到野生动物该怎么处理?,响应结果:

{"question":"徒步时遇到野生动物该怎么处理?","answer":"徒步时遭遇野生动物,核心处理原则是保持冷静,切勿投喂或驱赶。同时需结合徒步安全的整体要求,避免单独行动,提前了解路线上的野生动物分布情况,遇到时与动物保持安全距离,缓慢撤离至安全区域,切勿惊慌奔跑引发动物追击。"}

4. 优化效果分析

测试结果表明,优化后的 RAG 系统具备以下生产级特性:

回答完整性:能整合多个相关片段信息,精准回应复杂问题,无语义断裂;

噪声过滤:通过相似度阈值有效过滤低相关内容,避免无关回答;

上下文连贯性:相邻片段扩展策略让回答逻辑更清晰,符合实际使用场景;

稳定性:向量存储基于 Milvus,服务重启后数据不丢失,支持长期使用。

五、生产环境注意事项

1、Milvus 集群部署
单机版 Milvus 仅适用于测试,生产环境需部署 Milvus 集群,确保高可用与高吞吐量。
2、文本切分参数调优
根据知识库类型调整 chunkSize 与 minChunkSizeChars,例如技术文档可设置为 1000 Token / 段,文学类文档可设置为 500 Token / 段。
3、相似度阈值动态调整
不同知识库的向量分布不同,需通过测试调整阈值(如 0.03~0.1),平衡召回率与精确率。
4、上下文长度限制
大模型有最大上下文长度限制(如 GLM-4-Flash 支持 8k Token),需控制拼接后的上下文长度,避免超限。
5、缓存优化
对高频查询的向量结果进行缓存(如使用 Redis),减少 Milvus 检索压力。

总结

本文通过集成 Milvus 向量数据库、优化文本切分策略、升级检索逻辑,成功解决了基础版 RAG 的核心痛点,打造了具备高可用性、高精准度的生产级 RAG 应用。核心优化价值在于:Milvus 提供了向量持久化存储能力,TokenTextSplitter 确保了文本片段的语义完整性,相似度阈值与相邻片段扩展提升了检索精度与上下文连贯性。

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

凌晨两点还在调 Dify 环境?我后悔没早点知道 Sealos

那是一个普通的周三&#xff0c;产品经理下午三点甩来需求&#xff1a;"咱们搭个 AI 客服系统&#xff0c;用 Dify 对接 DeepSeek&#xff0c;下周演示。" 我心想&#xff1a;小场面。 然后时间快进到凌晨两点&#xff0c;我对着屏幕上第 47 次报错的 Docker Compose…

作者头像 李华
网站建设 2026/3/27 14:38:28

decode html

电子邮件 decode html 转义处理 支持 </& gt; 中间有空格的情况&#xff08;如 & lt;&#xff09;。这样即使内容被多次编码或含空格&#xff0c;也能正确恢复成 <img> 标签显示表情。 /*** 转义处理* 支持 </& gt; 中间有空格的情况&#xff08;如…

作者头像 李华
网站建设 2026/3/26 20:42:06

lvgl v8 label滚动模式

void lvgl_label_animation() {lv_obj_t* parent = lv_scr_act();lv_obj_t* lab = lv_label_create(

作者头像 李华
网站建设 2026/4/8 23:58:10

快速上手Ultimate#x2B;#x2B;的编译链接和配置

U简介 U&#xff08;全称 Ultimate&#xff09;是一个开源的 C 跨平台应用程序框架&#xff0c;以其高性能、低资源占用和高度集成的开发理念而闻名。它旨在提供“更少代码、更快执行”的开发体验。 主要特点&#xff1a; 高度集成 包含GUI、数据库、网络、XML、JSON等完整工…

作者头像 李华
网站建设 2026/4/10 19:45:36

Zigbee技术在智慧酒店中的应用设计与实现

Zigbee技术在智慧酒店中的应用设计与实现 一、应用背景与意义 在消费升级与数字化转型浪潮下&#xff0c;智慧酒店成为行业发展的核心方向&#xff0c;其核心需求是通过技术赋能提升宾客体验、优化运营效率、降低能耗成本。传统酒店控制系统多采用有线布线或单一无线技术&…

作者头像 李华
网站建设 2026/4/8 22:15:08

Comsol狄拉克半金属BDS超材料的探讨

Comsol狄拉克半金属BDS超材料。在电磁超材料领域玩拓扑材料总有种开挂的感觉。今天咱们拿COMSOL折腾个硬核活——基于狄拉克半金属(BDS)的可调谐超表面。这玩意儿在太赫兹波段的表现就像物理界的变色龙&#xff0c;通过外加电场就能改变电磁响应特性。先整活材料参数设置。BDS的…

作者头像 李华