【Spring AI】模型记忆持久化 + 自动加载记忆上下文

当我们利用大模型进行开发时,有时会因为项目重启而丢失模型的记忆,会给开发的过程带来不方便

接下来我将介绍如何将模型的记忆持久化,并保证在项目重启后依然能能够正常加载记忆上下文。

我们在配置ChatClient时,由于想要实现模型的记忆,便需要管理会话信息,而Spring AI给我们提供了Advisors的自动管理机制,其有两种实现方式,即内存记忆和缓存记忆,但是其根源都是建立在缓存中,主机重启都会数据丢失。

在模型会话记忆ChatMemory的底层是通过创建不同类型的Message存储会话,所以我们可以利用这个机制,在每次模型响应后,将模型的响应和用户的请求信息分别手动创建不同类型的Message进行存储,而存储则可以选择数据库。

但是首先要给ChatClient配置记忆容器

this.chatClient = chatClient.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)).build();

我将分别来讲记忆的持久化以及记忆的读取

模型记忆持久化

以下是ChatClient的捕获响应方式

public Flux<String> chat(@RequestBody GetRequest request) {//用户消息String userMessage = request.getMessage();//保存会话idchatHistoryService.save("chat",request.getChatId(),request.getSid());//构建提示词,用户提示词,调用模型,取出响应//流式响应// 创建响应收集器,不断加载响应内容,用于在中断时保存已生成内容StringBuilder assistantResponse = new StringBuilder();System.out.println("调用"+modelName+"模型进行响应");Flux<String> response = chatClient.prompt().system(System_Prompt) // 设置系统提示词.user(userMessage)   // 设置用户提示词.advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY,request.getChatId()))  //  设置会话ID.stream()        //流式响应.content()  //获取响应内容.doOnNext(assistantResponse::append) // 追加到响应收集器中
//                .doOnSubscribe(sub -> activeSubscriptions.put(request.getChatId(), sub)) // 直接存储Subscription.doFinally(Message->{//将响应信息存储到数据库String type = "assistant"; //将用户信息保存到数据库saveChatHistory(request.getChatId(),"user", userMessage);//将响应信息存储到数据库saveChatHistory(request.getChatId(),type, assistantResponse.toString());});return response;}

可以看到在相应开始前首先创建一个builder容器用于不断追加模型的响应,在ChatClient的dofinally中调用方法分别存储用户和模型信息。

以下是存储方法

可以看到方法参数为会话ID,类型和内容,其中类型是user或者assistant,这是底层源码所定义的,我们需要保持一致以便模型能够正确读取

//将会话信息存储到数据库public void saveChatHistory(String chatId, String type,  String content) {ChatDetail chatDetail = new ChatDetail();chatDetail.setChatId(chatId);chatDetail.setMessageType(type);chatDetail.setContent(content);chatDetailMapper.insert(chatDetail);}

这里注意需要提前定义数据库表,有类型字段和内容字段

最终存储的效果:

 加载模型记忆

已经将对话数据持久化,那么在进行项目重启后为了不丢失原有记忆,我们需要想办法吧数据库中存储的内容加载到模型的记忆中

前面已经说到记忆的存储在底层时Message类型,而其有不同的实现类,其中UserMessage和AssistantMessage是我们所需要的只要根据从数据库中消息类型的不同分别创建不同的Message并将其存储到ChatMemory中即可。

以下是具体流程:

当用户访问某个会话时,先将其余会话的记忆清除,再根据会话id从数据库取得对应记忆,并遍历存入模型记忆上下文

List<ChatDetail> chatDetails = chatDetailMapper.selectList(new LambdaQueryWrapper<ChatDetail>().eq(ChatDetail::getChatId, chatId));//将当前会话的信息保存到模型记忆上下文//清除其他会话记忆chatHistoryService.getChatIds(type).forEach(chat->chatMemory.clear(chat.getChatId()));activeSubscriptions.clear(); // 同时清理订阅关系//加入当前会话记忆if (!chatDetails.isEmpty()) {chatDetails.forEach(c -> {if (c.getMessageType().equals("user")) {chatMemory.add(chatId, new UserMessage(c.getContent()));     //用户信息} else if (c.getMessageType().equals("assistant")) {chatMemory.add(chatId, new AssistantMessage(c.getContent())); //模型回复信息}});System.err.println("当前模型记忆为:"+chatMemory.get(chatId,  Integer.MAX_VALUE));

这样一来便实现了模型记忆的持久化功能,并在多个会话的情况下保证内存的容量问题。

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

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

相关文章

(C语言)超市管理系统 (正式版)(指针)(数据结构)(清屏操作)(文件读写)

目录 前言&#xff1a; 源代码&#xff1a; product.h product.c fileio.h fileio.c main.c 代码解析&#xff1a; 一、程序结构概述 二、product.c 函数详解 1. 初始化商品列表 Init_products 2. 添加商品 add_product 3. 显示商品 display_products 4. 修改商品 mo…

[服务器面板对比] 宝塔、aaPanel、Plesk、cPanel 哪家强?功能、性能与价格横评 (2025)

对于很多 Linux 服务器用户来说&#xff0c;直接面对黑乎乎的命令行界面 (CLI) 进行各种操作&#xff0c;虽然强大灵活&#xff0c;但也确实有一定的学习门槛和操作复杂度。特别是当你需要管理多个网站、数据库、FTP账户&#xff0c;或者进行日常的软件安装、安全配置、日志查看…

WebGL图形编程实战【7】:变换流水线 × 坐标系与矩阵精讲

变换流水线 #mermaid-svg-Omabd9LSNCdIvWqB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Omabd9LSNCdIvWqB .error-icon{fill:#552222;}#mermaid-svg-Omabd9LSNCdIvWqB .error-text{fill:#552222;stroke:#552222;…

电力电容器故障利用沃伦森(WARENSEN)工业设备智能运维系统解决方案

行业工况背景 当配电室报警显示“电容器故障”时&#xff0c;管理者可能会感到焦虑。沃伦森&#xff08;WARENSEN&#xff09;凭借十多年的电力补偿设备服务经验&#xff0c;提供了科学的故障应对流程&#xff0c;帮助避免大部分二次损失。 一、五大常见故障现象快速识别 温度…

星海智算云平台部署GPT-SoVITS模型教程

背景 随着 GPT-SoVITS 在 AI 语音合成领域的广泛应用&#xff0c;越来越多的个人和团队开始关注这项前沿技术。你是否也在思考&#xff0c;如何快速、高效地部署并体验这款强大的声音克隆模型&#xff1f;遗憾的是&#xff0c;许多本地部署方案不仅配置复杂&#xff0c;而且对…

高吞吐与低延迟的博弈:Kafka与RabbitMQ数据管道实战指南

摘要 本文全面对比Apache Kafka与RabbitMQ在数据管道中的设计哲学、核心差异及协同方案。结合性能指标、应用场景和企业级实战案例,揭示Kafka在高吞吐流式处理中的优势与RabbitMQ在复杂路由和低延迟传输方面的独特特点;介绍了使用Java生态成熟第三方库(如Apache Kafka Clie…

Python零基础入门到高手8.4节: 元组与列表的区别

目录 8.4.1 不可变数据类型 8.4.2 可变数据类型 8.4.3 元组与列表的区别 8.4.4 今天彩票没中奖 8.4.1 不可变数据类型 不可变数据类型是指不可以对该数据类型进行原地修改&#xff0c;即只读的数据类型。迄今为止学过的不可变数据类型有字符串&#xff0c;元组。 在使用[]…

无人机数据处理与特征提取技术分析!

一、运行逻辑 1. 数据采集与预处理 多传感器融合&#xff1a;集成摄像头、LiDAR、IMU、GPS等传感器&#xff0c;通过硬件时间戳或PPS信号实现数据同步&#xff0c;确保时空一致性。 边缘预处理&#xff1a;在无人机端进行数据压缩&#xff08;如JPEG、H.265&#xff09;…

LeetCode 热题 100 105. 从前序与中序遍历序列构造二叉树

LeetCode 热题 100 | 105. 从前序与中序遍历序列构造二叉树 大家好&#xff0c;今天我们来解决一道经典的二叉树问题——从前序与中序遍历序列构造二叉树。这道题在 LeetCode 上被标记为中等难度&#xff0c;要求根据给定的前序遍历和中序遍历序列&#xff0c;构造并返回二叉树…

CSS- 1.1 css选择器

本系列可作为前端学习系列的笔记&#xff0c;代码的运行环境是在HBuilder中&#xff0c;小编会将代码复制下来&#xff0c;大家复制下来就可以练习了&#xff0c;方便大家学习。 HTML系列文章 已经收录在前端专栏&#xff0c;有需要的宝宝们可以点击前端专栏查看&#xff01; 系…

MongoClient和AsyncIOMotorClient的区别和用法

示例代码&#xff1a; from motor.motor_asyncio import AsyncIOMotorClient from pymongo import MongoClient&#x1f50d; 这两个库分别是&#xff1a; 名字说明举个例子pymongo.MongoClient同步版 的 MongoDB 客户端&#xff08;常规阻塞式操作&#xff09;你在主线程里一…

5.15打卡

浙大疏锦行 DAY 26 函数专题1 知识点回顾&#xff1a; 1. 函数的定义 2. 变量作用域&#xff1a;局部变量和全局变量 3. 函数的参数类型&#xff1a;位置参数、默认参数、不定参数 4. 传递参数的手段&#xff1a;关键词参数 5. 传递参数的顺序&#xff1a;同时出现三种参数…

针对面试-mysql篇

1.如何定位慢查询? 1.1.介绍一下当时产生问题的场景(我们当时的接口测试的时候非常的慢&#xff0c;压测的结果大概5秒钟))&#xff0c;可以监测出哪个接口&#xff0c;最终因为是sql的问题 1.2.我们系统中当时采用了运维工具(Skywalking就是2秒&#xff0c;一旦sql执行超过2秒…

window 显示驱动开发-报告图形内存(三)

图形内存报告示例 示例 1&#xff1a;笔记本电脑上的 128 MB 专用板载图形内存 以下屏幕截图显示了使用 Intel Iris 离散图形适配器运行 Windows 11 的 Surface 笔记本电脑的计算图形内存数。 适配器的可用内存总数为 16424 MB&#xff0c;用于图形用途&#xff0c;细分如下&…

极简主义现代商务风格PPT模版6套一组分享下载

现代商务风格PPT模版下载https://pan.quark.cn/s/12fbc52124d9 第一张PPT模版&#xff0c;简约风&#xff0c;橄榄绿背景&#xff0c;黑色竖条装饰&#xff0c;文字有中英文标题和占位符。需要提取关键元素&#xff1a;简约、橄榄绿、对称布局、占位文本的位置。 风格​&#…

SpringBoot中10种动态修改配置的方法

在SpringBoot应用中&#xff0c;配置信息通常通过application.properties或application.yml文件静态定义&#xff0c;应用启动后这些配置就固定下来了。 但我们常常需要在不重启应用的情况下动态修改配置&#xff0c;以实现灰度发布、A/B测试、动态调整线程池参数、切换功能开…

嵌入式自学第二十二天(5.15)

顺序表和链表 优缺点 存储方式&#xff1a; 顺序表是一段连续的存储单元 链表是逻辑结构连续物理结构&#xff08;在内存中的表现形式&#xff09;不连续 时间性能&#xff0c; 查找顺序表O(1)&#xff1a;下标直接查找 链表 O(n)&#xff1a;从头指针往后遍历才能找到 插入和…

高并发内存池(三):TLS无锁访问以及Central Cache结构设计

目录 前言&#xff1a; 一&#xff0c;thread cache线程局部存储的实现 问题引入 概念说明 基本使用 thread cache TLS的实现 二&#xff0c;Central Cache整体的结构框架 大致结构 span结构 span结构的实现 三&#xff0c;Central Cache大致结构的实现 单例模式 thr…

Ubuntu 安装 Docker(镜像加速)完整教程

Docker 是一款开源的应用容器引擎&#xff0c;允许开发者打包应用及其依赖包到一个轻量级、可移植的容器中。本文将介绍在 Ubuntu 系统上安装 Docker 的步骤。 1. 更新软件源 首先&#xff0c;更新 Ubuntu 系统的软件源&#xff1a; sudo apt update2. 安装基本软件 接下来…

【深度学习】数据集的划分比例到底是选择811还是712?

1 引入 在机器学习中&#xff0c;将数据集划分为训练集&#xff08;Training Set&#xff09;、验证集&#xff08;Validation Set&#xff09;和测试集&#xff08;Test Set&#xff09;是非常标准的步骤。这三个集合各有其用途&#xff1a; 训练集 (Training Set)&#xff…