当前位置: 首页 > news >正文

【LangChain4j+Redis】会话记忆功能实现

一、介绍

接着上文继续实现会话记忆功能

前置后端内容: https://blog.csdn.net/2401_84926677/article/details/151962893

前置前端内容:https://blog.csdn.net/2401_84926677/article/details/152051570

Langchain4j 的会话记忆功能核心作用是为 AI 对话提供 “上下文感知能力”,解决大语言模型(LLM)默认 “无状态” 的问题 —— 即让 AI 能记住多轮交互中的历史消息、用户偏好和对话逻辑,从而实现更连贯、个性化且符合场景的对话体验。

二、步骤

1. 定义会话记忆对象

创建config包下的CommonConfig类

@Configuration
public class CommonConfig {@Bean public ChatMemory chatMemory() {MessageWindowChatMemory memory = MessageWindowChatMemory.builder().maxMessages(20).build();return memory;}}

@Bean表示加入到 IOC 容器里

2. 配置会话记忆对象

在@AiService注解里设置chatMemory,配置会话记忆对象

@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,chatModel = "openAiChatModel",streamingChatModel = "openAiStreamingChatModel",chatMemory = "chatMemory"   //这里的chatMemory是配置类@Bean注解下的方法名
)
public interface ConsultantService {// @SystemMessage(fromResource = "system.txt")@UserMessage("你是一位厨师,{{love}}")public Flux<String> chat(@V("love")String message);
}

3. 效果测试

后端请求的日志输出,已经携带了之前的会话历史记录:

但是!如果另一个用户进行访问,这个会话记忆是什么样的?

我们打开另一个浏览器访问,并继续提问:

---------------发现它仍然和上一个用户的关联着,没有实现隔离!----------------

三、会话记忆隔离实现

1. 定义会话记忆对象提供者

在config包下的,CommonConfig类中加入ChatMemoryProvider的定义

//构建ChatMemoryProvider对象@Beanpublic ChatMemoryProvider chatMemoryProvider() {ChatMemoryProvider chatMemoryProvider=new ChatMemoryProvider(){@Overridepublic ChatMemory get(Object memoryId) {return MessageWindowChatMemory.builder().id(memoryId).maxMessages(20).build();}};return chatMemoryProvider;}

2. 配置会话记忆对象提供者

修改@AiService注解里的内容:加入chatMemoryProvider,去掉chatMemory

@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,chatModel = "openAiChatModel",streamingChatModel = "openAiStreamingChatModel",// chatMemory = "chatMemory",chatMemoryProvider = "chatMemoryProvider"
)
public interface ConsultantService {@SystemMessage(fromResource = "system.txt")//@UserMessage("你是一位厨师,{{love}}")public Flux<String> chat(String message);
}

3. ConsultantService接口方法中添加参数MemoryId

在接口方法的参数加入memoryId,并加上相关注解标明这两个参数

@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,chatModel = "openAiChatModel",streamingChatModel = "openAiStreamingChatModel",// chatMemory = "chatMemory",chatMemoryProvider = "chatMemoryProvider"
)
public interface ConsultantService {@SystemMessage(fromResource = "system.txt")//@UserMessage("你是一位厨师,{{love}}")public Flux<String> chat(@MemoryId String memoryId,@UserMessage String message);
}

4. Controller中chat接口接收memoryId

在控制器方法和返回值中加入memoryId参数

@RestController
@RequestMapping("/api")
@CrossOrigin
public class ChatController {@Autowiredprivate ConsultantService consultantService;@GetMapping(value = "/chat",produces = "text/html;charset=utf-8")public Flux<String> chat(@RequestParam String memoryId, @RequestParam String message) {return consultantService.chat(memoryId, message);}}

5. 前端页面请求时传递memoryId

新增会话按钮,设置点击事件:

 <button @click="newSession" class="new-session-btn">+</button>
/*** 创建新会话*/
const newSession = () => {// 生成新的memoryIdmemoryId.value = Date.now().toString()// 清空消息messages.value = []
}

发送请求时加入memoryId参数:

 // 调用后端API,发送用户消息,包含memoryId参数const response = await fetch(`http://localhost:8080/api/chat?memoryId=${encodeURIComponent(memoryId.value)}&message=${encodeURIComponent(messageToSend)}`)

6. 效果测试

第一个用户页面:

第二个用户页面:

可见并没有携带第一个用户的会话,效果达成!

但是!如果系统重启,岂不是就都没有了?

重启后接着问:

可见,系统或者服务器重启后,会话记忆历史也就丢失了,那么就需要再次改进。

四、会话记忆持久化

想要实现持久化,那么必须通过外部的存储工具,例如redis,mysql或者其他存储工具

这里使用redis实现会话记忆持久化:

1. redis环境准备

这里使用VMware虚拟机linux的CentOS系统,通过Docker容器化安装部署Redis

sudo docker run -d \--name redis \-p 6379:6379 \-v /usr/local/redis/data:/data \redis:latest \redis-server --appendonly yes

然后安装Redis的可视化工具,这里使用Redis Insight创建连接:

2. pom.xml文件引入redis起步依赖

  <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

3. 配置redis连接信息

配置application.yaml文件
spring:data:redis:host: 192.168.1.128port: 6379

4. 提供ChatMemoryStore实现类

创建repository包,创建RedisChatMemoryStore类实现ChatMemoryStore接口


@Repository
public class RedisChatMemoryStore implements ChatMemoryStore {//注入redisTemplate@Autowiredprivate StringRedisTemplate redisTemplate;@Overridepublic List<ChatMessage> getMessages(Object memoryId) {// 获取会话消息String json = redisTemplate.opsForValue().get(memoryId);// 把json数据转成List<ChatMessage>List<ChatMessage> list = ChatMessageDeserializer.messagesFromJson(json);return list;}@Overridepublic void updateMessages(Object memoryId, List<ChatMessage> list) {// 更新会话消息//1.把list转成json数据String json = ChatMessageSerializer.messagesToJson(list);//2.保存到redis中redisTemplate.opsForValue().set( memoryId.toString(), json, Duration.ofDays(1));}@Overridepublic void deleteMessages(Object memoryId) {redisTemplate.delete(memoryId.toString());}
}

5. 配置ChatMemoryStore

配置类配置ChatMemoryStore

@Configuration
public class CommonConfig {@Autowiredprivate RedisChatMemoryStore redisChatMemoryStore;  // 注入RedisChatMemoryStore@Beanpublic ChatMemory chatMemory() {MessageWindowChatMemory memory = MessageWindowChatMemory.builder().maxMessages(20).build();return memory;}//构建ChatMemoryProvider对象@Beanpublic ChatMemoryProvider chatMemoryProvider() {ChatMemoryProvider chatMemoryProvider=new ChatMemoryProvider(){@Overridepublic ChatMemory get(Object memoryId) {return MessageWindowChatMemory.builder().id(memoryId).maxMessages(20).chatMemoryStore(redisChatMemoryStore) // 设置存储对象.build();}};return chatMemoryProvider;}}

6. 效果测试

重启项目,进行测试

------------会话记忆正常-------------

那么我们重启一下后端再试试:

------------依旧可以!我们来看看后端-------------

下面我们打开redis看一下

会话历史记录已成功存入Redis缓存,实现了会话历史的限时持久化存储

http://www.dtcms.com/a/409810.html

相关文章:

  • Android Handler的runWithScissors方法
  • 180课时吃透Go语言游戏后端开发3:Go语言中其他常用的数据类型
  • 在 Android 11 上实现 WiFi 热点并发支持(同时开启 STA + AP 模式)
  • 济南高新区网站建设wordpress举报插件
  • html 占位符
  • GPT-5 Codex正式上线 Azure AI Foundry(国际版)
  • C++设计模式之结构型模式:享元模式(Flyweight)
  • STM32 智能垃圾桶项目笔记(一):超声波模块(HC-SR04)原理与驱动实现
  • 全文 -- Vortex: Extending the RISC-V ISA for GPGPU and 3D-Graphics Research
  • 设计网站推荐理由公司网站备案电话
  • 事件驱动与CDS:基于FHIR R5 Subscriptions与Bulk Data的再考察(下)
  • Tigshop开源商城系统 Java v5.2.2 / PHP v5.1.6版本正式发布(ES搜索上新)
  • 仙游县住房和城乡建设局网站1元涨1000粉丝网站
  • 【Linux】进程概念(六):进程地址空间深度解析:虚拟地址与内存管理的奥秘
  • 网站怎么做微信登录界面wordpress restful
  • Linux下写一个简陋的shell程序
  • OpenSource - 异构数据库数据与结构同步工具dbswitch
  • 首次披露潮玩成长性,量子之歌敲响新财年重估的钟声
  • jdk21 list中筛选出符合条件的list
  • Session共享问题
  • 3. Ollama 安装,流式输出,多模态,思考模型
  • Go基础:常用数学函数处理(主要是math包rand包的处理)
  • 做彩票网站被捉将受到什么惩罚北京网站建设公司制作网站
  • 沈阳小程序建设兰州seo优化
  • 低疲劳高响应!硬件软件协同:明基 RD280U 赋能创作开发,解锁新工位高效工作氛围
  • Apache Log4j2 lookup JNDI 注入漏洞(CVE-2021-44228)
  • wpf之 Popup
  • @xyflow/react:构建交互式节点流程图的完整指南
  • LinuxC++项目开发日志——基于正倒排索引的boost搜索引擎(5——通过cpp-httplib库建立网页模块)
  • 消息队列Apache Kafka教程