spring ai基于内存RAG尝鲜

news/2025/9/22 11:49:43/文章来源:https://www.cnblogs.com/wzyx6/p/19104866

RAG,数据检索增强生成,简单点说你提供一个数据集,让语言模型根据你的数据集回答问题。
1.新增依赖
这次的练习demo是将一个pdf作为数据集,喂给模型做训练生成内存向量库,以此回答问题。下面新增的依赖是pdf阅读和内存向量库,spring-ai-transformers-spring-boot-starter中没有SimpleVectorStore,所以使用spring-ai-vector-store。

  	 <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-pdf-document-reader</artifactId><version>1.0.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-vector-store</artifactId><version>1.0.0-SNAPSHOT</version></dependency>

2.EmbeddingModel配置
EmbeddingModel用来完成"文本->向量集"的工作,包括数据集转成向量和把用户的问题转成向量。

import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.zhipuai.ZhiPuAiEmbeddingModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class VectorStoreConfiguration {@Beanpublic SimpleVectorStore vectorStore(ZhiPuAiEmbeddingModel zhiPuAiEmbeddingModel){return SimpleVectorStore.builder(zhiPuAiEmbeddingModel).build();}
}

3.加载向量集
项目启动时就需要加载向量集,第一次需要生成.json文件,后面就可以直接load加载,加快启动时间。

    @Autowiredprivate SimpleVectorStore simpleVectorStore; // 内存向量集@Autowiredprivate ResourceLoader resourceLoader;@PostConstruct@Overridepublic void init() {File file = new File("./vector_store.json");if (!file.exists()) {Resource pdfResource = resourceLoader.getResource("file:F:\\2024省政府工作报告.pdf");PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(pdfResource,PdfDocumentReaderConfig.builder().withPageExtractedTextFormatter(ExtractedTextFormatter.builder().build()).build());List<Document> documents = pdfReader.read();// 2. 分割文档TokenTextSplitter textSplitter = new TokenTextSplitter();List<Document> splitDocuments = textSplitter.split(documents);// 3. 嵌入并存储到向量集simpleVectorStore.add(splitDocuments);// 4. 保存到文件,下次启动无需重新处理simpleVectorStore.save(file);}// 加载simpleVectorStore.load(file);}

4.调用
4.1 根据向量集搜索是阻塞操作,但是我用的是webflux,导致报错,所以需要封装成响应式操作。
4.2 目前仅是练手demo,所以历史消息未做持久化存储和用户、话题隔离。

import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;@RestController
public class DataController {@Autowiredprivate ZhiPuAiChatModel model;@Autowiredprivate SimpleVectorStore vectorStore;// todo 后续这里应改成Map<话题id,List<Message>>,这样子才能实现对话隔离List<Message> historyMessage = new ArrayList<>() {{add(new SystemMessage("你是一个乐于助人的AI助手,名字叫小智。你的回答要简洁明了。"));}};@GetMapping("/test/{msg}")public Flux<String> generate(@PathVariable(value = "msg") String msg) {// 1. 将阻塞的向量搜索转换为响应式操作Mono<List<Document>> similarDocumentsMono = Mono.fromCallable(() ->vectorStore.similaritySearch(msg)).subscribeOn(Schedulers.boundedElastic()); // 在弹性线程池执行阻塞操作// 2. 构建完整的响应式处理链return similarDocumentsMono.flatMapMany(documents -> {// 3. 构建系统消息和上下文String systemMessage = """请严格根据以下上下文信息来回答问题。如果上下文信息中没有答案,就说"根据我所知的信息,无法回答这个问题。"。不要编造信息。上下文信息:{context}""";String context = documents.stream().map(Document::getText).collect(Collectors.joining("\n\n"));Message systemDocument = new SystemPromptTemplate(systemMessage).createMessage(Map.of("context", context));// 4. 添加到历史消息(注意:这里需要处理历史消息的线程安全问题)// 异步环境中,需要确保 historyMessage 是线程安全的,后面改成用户和历史消息都隔离就不用加锁了synchronized (historyMessage) {historyMessage.add(systemDocument);Message userMessage = new UserMessage(msg);historyMessage.add(userMessage);}Prompt p = new Prompt(historyMessage);// 5. 调用流式模型Flux<String> responseStream = model.stream(p).handle((chatResponse, sink) -> {if (chatResponse.getResult() != null) {String text = chatResponse.getResult().getOutput().getText();if (text != null) {sink.next(text);}}});// 6. 处理流式响应并保存到历史return responseStream.collectList().flatMapMany(chunks -> {String fullResponse = String.join("", chunks);Message assistantMessage = new AssistantMessage(fullResponse);// 同样需要同步处理共享的historyMessagesynchronized (historyMessage) {historyMessage.add(assistantMessage);}return Flux.fromIterable(chunks);});});}
}

5.结果
GET http://localhost:8080/test/2024省政府工作报告可以提供几道题么?

回答:
根据上下文信息,我可以为您提供以下几道关于2024年山东省政府工作报告的题目:

  1. (单选)《2024年山东省政府工作报告》围绕塑造绿色低碳高质量发展新优势,提出2024年要重点抓实抓好十二个方面的工作,其中放在首位的是( )。
    A. 抓实抓好扩大有效需求
    B. 科技创新引领现代化产业体系建设
    C. 推进乡村振兴
    D. 深化改革开放

  2. (单选)根据2024年山东省政府工作报告,今年是中华人民共和国成立( )周年,是实现"十四五"规划目标任务的关键一年。
    A. 70
    B. 75
    C. 80
    D. 85

  3. (多选)2024年山东省经济社会发展主要预期目标包括( )。
    A. 地区生产总值增长5%以上
    B. 一般公共预算收入增长4%
    C. 居民人均可支配收入增长5.5%左右
    D. 城镇新增就业100万人以上

  4. (填空)2024年山东省政府工作以建设____________________为总抓手。

Response code: 200 (OK); Time: 8619ms (8 s 619 ms); Content length: 448 bytes (448 B)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/909299.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于 IOCP 的协程调度器——零基础深入浅出 C++20 协程

将真实的异步 IO 事件与协程相结合、例子规模控制在 200 行、能编译能运行的 Windows C++20 协程 demo,见过没?今天就给各位老铁整一个,它还支持多协程并发哦~前言 上一篇《基于 epoll 的协程调度器》谈到如何基于 …

Gitee PPM风险矩阵:数字化转型中的项目管理预警雷达

Gitee PPM风险矩阵:数字化转型中的项目管理"预警雷达" 在数字化转型浪潮席卷全球的当下,软件研发项目正面临着前所未有的复杂度和不确定性。根据Gartner最新发布的行业报告显示,2023年全球IT项目的平均延…

同一个灰色,POI取出来却是白色:一次Excel颜色解析的踩坑记录

解析Excel单元格颜色时遇到主题色与普通色差异问题。当单元格使用主题色时,直接获取RGB值会失效,需结合ThemesTable获取基础颜色并考虑tint参数(用于调整明暗度)。通过封装工具类,先判断是否为主题色,再解析基础…

坤驰科技携国产化MTCA解决方案,亮相大科学装置控制系统研讨会

“2025MicroTCA/ATCA在大科学装置控制系统中的应用研讨会”在重庆君豪大饭店召开,北京坤驰科技携国产化MTCA硬件平台及数据采集解决方案参会。国产化 MTCA平台 坤驰科技深耕大科学装置(高能物理、激光、光子光束线等…

找出所有项目引用了哪些 NuGet 包、版本号、对应项目路径,并筛选出“同一个包名但版本不同”的情况。

全局扫描所有 .csproj 文件 打开 PowerShell,运行以下脚本(替换为你的代码根目录): $root = "D:\YourCodeRoot" $results = Get-ChildItem -Path $root -Recurse -Filter *.csproj | ForEach-Object {$p…

人形机器人 —— 电机控制的三种模式 —— 力矩、速度、位置

人形机器人 —— 电机控制的三种模式 —— 力矩、速度、位置电机控制的三种模式: 力矩、速度、位置其实,这三种模式说的并不是很清晰,准确来说应该是缺少了一个变量,那就是时间变量,准确的来说就是在单位时间内的…

解决Windows更新后WPF代码报TypeLoadException异常的困难

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

PC与基恩士PLC通信的C#实现

1 确定通信方式与协议 PC与基恩士PLC通信通常主要通过以太网进行,有时也会使用串口。关键在于PLC型号和支持的协议,常见的有:MC协议 (MELSEC Communication Protocol):这是三菱PLC的协议,但概念类似,基恩士有其自…

Excel 表格技能

1:添加删除线:Alt + 1 , 调出设置面板,添加

labelme标注后的json文件和原图同步按角度旋转

点击查看代码 import json import os import base64 import numpy as np import cv2 from math import cos, sin, radians import argparsedef rotate_point_opencv_style(point, rotation_matrix):"""…

rk3588的ai功能和deepseek

rk3588的ai功能 该型号cpu支持 6TOPS NPU、Mali-G610 MP4 GPU。 支持针对rk系列开发的RKNN框架,能够完成模型转换,量化,推理,性能评估,内存评估和量化分析功能。TOPS是Tera Operations Per Second的缩写,1TOPS代…

EPSON L1300打印机清零教程

症状分析 打印机电源灯不断闪烁,旁边的三个状态灯,依次亮红灯闪烁。连接打印机的电脑会有如下提示:如果你的打印机是这种情况,那就说明该清零了。 使用前提 清零软件需要在USB直连打印机的电脑上工作,请确保先满足…

「线性代数」矩阵运算与初等变换

矩阵基本知识基本概念略。 矩阵的运算 矩阵加法、数乘 加法:对于两个 \(n\times m\) 的矩阵 \(A, B\) 定义 \(A + B = C\),\(C\) 仍为 \(n \times m\),且 \(c_{i, j} = a_{i, j} + b_{i, j}\)。 数乘:\(B = xA\),…

移动号码线上复机

记录一下过程: 1.先是抖音搜索; 2.给移动人工客服打电话,询问变成空号原因,是欠费超过3个月,9月7日变成空号;如何解决呢,可以通过中国移动app线上复机;我用联通号码登录的,搜索不到线上复机; 3.再给移动人工…

Uni-App 使用android studio打包最新教程

字数 530,阅读大约需 3 分钟Uni-App 使用android studio打包最新教程 1、下载uniapp离线sdk Dcloud 官方平台地址Android 离线SDK - 正式版 | uni小程序SDK[1] 2、找个自己的文件夹解压注意文件夹不要带中文,android…

tomcat CPU数量和线程数的关系

这个设置建议是基于线程的执行特性和服务器资源的合理利用。以下详细解释为什么这样设置: 1. CPU密集型任务 对于CPU密集型任务,线程主要在执行计算操作,几乎不会主动让出CPU。在这种情况下,线程数过多会导致线程切…

NASA运货飞船天鹅座再次推迟,航天任务为什么总是“彩排”不断

​9月16日,原本计划为国际空间站运送约5000公斤科学实验设备和物资的天鹅座XL货运飞船,再次在轨道抬升过程中遭遇挑战。在两次点火过程中,其主发动机均提前停止工作,导致原定于9月17日的交会对接计划被迫推迟。美国…

Centos系统切换为光盘本地源

Centos系统切换为光盘本地源首先把 centos 的安装 IOS 挂载到光盘 方法一: --切换到根目录 cd / --新建目录 mkdir /media/cdrom --将镜像挂载到这个目录下面 mount /dev/cdrom /media/cdrom -- 进入yum仓库指定目录…

python处理Excel单机小程序:匹数据,增强版VLookup

2025年9月22日 场景: 如果使用vlookup匹数据的话, 每次只能匹配一列, 并且关联的列只能有一列, 比如有同名同姓的数据, 在匹配时就会出现错误 实现目标: 1. 可以同时使用多列数据进行关联, 比如用 姓名和工号, 同时进行…

深入解析:颜群JVM【01】类的生命周期_JMM_volatile

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …