🎉🎉《Spring Boot实战案例合集》目前已更新114个案例,我们将持续不断的更新。文末有电子书目录。
💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
1. 什么是RAG?
检索增强生成(Retrieval-Augmented Generation,简称RAG)是一种结合大型语言模型(LLM)和外部知识库的技术,旨在提高生成文本的准确性和相关性。
如下是维基百科的对RAG的解释:
RAG是赋予生成式人工智能模型信息检索能力的技术。检索增强生成优化大型语言模型(LLM) 的交互方式,让模型根据指定的一组文件内容回答用户的查询,并使用这些信息增强模型从自身庞大的静态训练数据中提取的信息。
简单说,RAG通过引入外部知识源来增强LLM的输出能力。它允许模型在生成答案之前,从特定的知识库中检索相关信息,从而提供更准确和上下文相关的回答。
如下图是整个RAG技术的应用过程:

上图总结:
(线下)将一个完整的文档查分了多个较小的文档片段存入向量数据库
(运行时)当回答用户的问题时,先根据问题(提示词)从向量数据库中查找相似的内容,最后会将问题和所有“相似”的文档片段放入发送给AI模型的提示信息中
1.2 什么是向量数据库?
在向量数据库中,查询方式与传统关系型数据库不同。它不进行精确匹配,而是执行相似性搜索。当给定一个向量作为查询条件时,向量数据库会返回与该查询向量“相似”的向量。
通俗点讲:如果你有一堆照片,你想快速找到 "某一个人",或者你有一篇文章,想找出“和这句话意思最接近的话”。这时候,用传统数据库(比如按文件名、标签搜索)根本搞不定,因为电脑看不懂图片和文字里的 "意思"。向量数据库就是帮电脑 "看懂" 内容——它把图片、文字、视频都变成一串数字(向量),然后通过“计算数字之间的距离”来判断内容有多像。比如,两张猫图的数字串离得近,一张猫图和一张狗图的数字串离得远,这样就能快速找到相似的东西。
向量长啥样?
文本内容:我爱Spring全家桶实战案例源码
通过Embedding模型生成对应的向量数字:[0.24, -0.56, 0.89]
最终将文本内容转换为一种数字,而这种数字是能被计算机"认识"的,最终会通过该向量数据来计算相似性。
向量数据库有很多,本篇文章将通过Milvus实现数据向量化存储。
1.3 Milvus简介
关于Milvus的详细介绍,不在本篇文章范围内(我们只需要知道如何使用即可);如需要详细了解学习请查看下面链接:
https://milvus.io/docs/zh
接下来,我们将详细的介绍如何通过Spring AI + ARG实现本地知识库。
2. 实战案例
2.1 环境准备
我们需要先准备如下环境:
向量数据库Milvus的安装
# 下载脚本$ curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh# 启动容器$ bash standalone_embed.sh start
Embedding模型bge-m3安装
我们还需要一个能够将文本转换为向量数据的大模型;我们这里使用bge-m3模型,该模型能够生成1024纬的向量。
ollama pull bge-m3:latest
环境准备好后,我们就可以开始本地知识库的实现了。
2.2 项目配置
首先,我们需要引入如下的依赖:
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-milvus-store-spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-ollama-spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId><version>1.0.0-M6.1</version></dependency>
说明:
Milvus用来存储我们的文档数据
Ollama引入是我们需要调用对应的接口来生成向量数据
alibaba ai我们将使用它的模型进行Chat对话
相关配置
spring:ai:dashscope:api-key: sk-xxxooobase-url: https://dashscope.aliyuncs.com/compatible-mode/v1chat:options:model: qwen-turboembedding:enabled: false---spring:ai:ollama:chat:enabled: falsebase-url: http://localhost:11111embedding:enabled: truemodel: bge-m3:latest---spring:ai:vectorstore:milvus:client:host: localhostport: 19530username: rootpassword: rootinitialize-schema: trueembeddingDimension: 1024
说明:上面有2个enabled必须进行相应的关闭,否则无法启动服务(存在多个对应的实现)。
接下来我们开始代码编写。
2.3 向量数据库基本操作
我们这里只实现了文本内容的保存和相似性搜索功能。
public class DocumentService {private final VectorStore vectorStore ;public DocumentService(VectorStore vectorStore) {this.vectorStore = vectorStore;}// 将任何文本内容保存到向量数据库public void save() {List<Document> documents = List.of(new Document("香蕉"), new Document("苹果"),new Document("橘子"), new Document("草莓"),new Document("Java"), new Document("python"),new Document("C#"), new Document("老虎")) ;// 在插入内容时会自动的调用Embedding模型将文本内容转换为向量this.vectorStore.add(documents) ;}// 根据提示词在向量数据库中进行相似性搜索// prompt 提示词// topK 返回多少结果(越靠后相似性越低,得分越小)public List<Document> query(String prompt, int topK) {SearchRequest request = SearchRequest.builder().query(prompt).topK(topK).build();// 相似性搜索;会自动将提示词转换为向量后再进行搜索return this.vectorStore.similaritySearch(request) ;}}
Controller接口测试
public class RagController {private final DocumentService documentService ;public RagController(DocumentService documentService) {this.documentService = documentService;}public ResponseEntity<String> save() {this.documentService.save() ;return ResponseEntity.ok("success") ;}public ResponseEntity<List<Document>> query( Integer topK, String prompt) {return ResponseEntity.ok(this.documentService.query(prompt, topK)) ;}}
首先,调用/rag/save方法后,我们通过attu客户端查看Milvus中的数据
最后,我们调用/rag/{topK}接口进行相似性搜索
注意,我们使用的提示词。我们设置的topK为5,水果数据我们插入的是4条,最后一条将编程语言也搜索出来了;因为是相似性搜索这很正常(只要你想,你都能将所有结果拿出,只是越相似的越靠前)。
所以,我们还需要通过LLM来重新组织过滤最终的结果。
接下来我们要将从向量数据库中查询出的结果与LLM结合输出最终的结果。
2.4 结合LLM模型
首先,我们需要配置ChatClient:
public class ChatConfig {ChatClient chatClient(ChatClient.Builder chatClientBuilder) {return chatClientBuilder.defaultAdvisors(List.of(new SimpleLoggerAdvisor())).build() ;}}
我们添加了日志切面,这样方便我们查看请求响应的数据内容。
接下来,我们就可以构建最终的提示词Prompt:
("/query/{topK}")public ResponseEntity<String> queryLLM( Integer topK, String prompt) {SearchRequest request = SearchRequest.builder().query(prompt).topK(topK).build();List<Document> docs = this.vectorStore.similaritySearch(request) ;// 提示词模板PromptTemplate promptTemplate = new PromptTemplate("{userMessage}\n\n 用以下信息回答问题:\n {contents}");// 组装提示词Prompt finalPrompt = promptTemplate.create(Map.of("userMessage", prompt, "contents", docs)) ;String result = this.chatClient.prompt(finalPrompt).call().content() ;return ResponseEntity.ok(result) ;}
自动过滤了 "python" 并给了提示。
修改查询的提示词如下:
干净的结果。
以上就RAG技术的整个应用过程。
推荐文章
优雅!Spring 基于 Plugin 插件开发(官方推荐)
Tika 与 Spring Boot 的完美结合:支持任意文档解析的神器
高级版@ResponseBody,接口响应数据格式完全自定义
技术专家:零代码,Spring Boot存储加密解密,支持JDBC、MyBatis及JPA
Spring Boot 3太强:全新Controller接口定义方式
Spring Boot开发利器:精通六大必备技能,轻松应对开发挑战


