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

第五章Langchain4j之基于内存和redis实现聊天持久化

📁langchain4j基于内存的聊天记忆实现

创建子模块langchain4j-08chat-memory

📦1.pom.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.yumeko.stduy</groupId><artifactId>langchain4j</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>langchain4j-08chat-memory</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--langchain4j-open-ai + langchain4j + langchain4j-reactor--><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId></dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId></dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-reactor</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.22</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

⚙️2.application.properties配置文件

server.port=9008
spring.application.name=langchain4j-08chat-memory
# 设置响应的字符编码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

🔧3.service服务

import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;public interface ChatMemoryAssistant {/*** 聊天带记忆缓存功能* @param userId 用户 ID* @param prompt 消息* @return {@link String }*/String chatWithChatMemory(@MemoryId Long userId, @UserMessage String prompt);
}

🤖4.AI模型配置类

import com.yumeko.study.service.ChatAssistant;
import com.yumeko.study.service.ChatMemoryAssistant;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.model.TokenCountEstimator;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiTokenCountEstimator;
import dev.langchain4j.service.AiServices;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class LLMConfig {@Beanpublic ChatModel chatModel() {return OpenAiChatModel.builder().apiKey(System.getenv("qwen-api")).modelName("qwen-long").baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1").build();}@Bean(name = "chat")public ChatAssistant chatAssistant(ChatModel chatModel) {return AiServices.create(ChatAssistant.class, chatModel);}/*** @Description: 按照MessageWindowChatMemory方式配置聊天记忆* 知识出处,https://docs.langchain4j.dev/tutorials/chat-memory/#eviction-policy* <p>* 该Bean提供基于消息数量限制的聊天记忆功能:* 1. 使用MessageWindowChatMemory实现聊天历史记录的存储和管理* 2. 限制最大保存100条消息记录(包括用户和AI的消息)* 3. 当消息超过限制时,会自动移除最旧的消息以保持窗口大小* 4. 通过memoryId参数区分不同用户的聊天上下文* <p>* MessageWindowChatMemory特点:* - 基于消息条数进行驱逐策略(eviction policy)* - 简单直接,适合对token数量控制要求不严格的场景* - 每个memoryId维护独立的聊天上下文*/@Bean(name = "chatMessageWindowChatMemory")public ChatMemoryAssistant chatMessageWindowChatMemory(ChatModel chatModel) {return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel)// 按照memoryId对应创建了一个chatMemory,每个memoryId代表一个独立的聊天上下文// MessageWindowChatMemory.withMaxMessages(100) 设置最大保存100条消息.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(100)).build();}/*** @Description: 按照TokenWindowChatMemory方式配置聊天记忆* <p>* 该Bean提供基于Token数量限制的聊天记忆功能:* 1. 使用TokenWindowChatMemory实现聊天历史记录的存储和管理* 2. 限制聊天历史记录的总Token数量不超过1000个Token* 3. 当Token数量超过限制时,会自动移除最旧的消息以保持Token窗口大小* 4. 通过memoryId参数区分不同用户的聊天上下文* <p>* TokenWindowChatMemory特点:* - 基于Token数量进行驱逐策略(eviction policy),更精确地控制内存使用* - 适合需要精确控制token消耗的场景,避免超出模型的token限制* - 每个memoryId维护独立的聊天上下文* <p>* 注意事项:* - 需要TokenCountEstimator来计算每条消息的token数量* - 这里使用OpenAiTokenCountEstimator作为token计算器*/@Bean(name = "chatTokenWindowChatMemory")public ChatMemoryAssistant chatTokenWindowChatMemory(ChatModel chatModel) {// 创建TokenCountEstimator,默认使用OpenAI的token分词器// TokenCountEstimator用于计算ChatMessage的token数量// 这里使用"gpt-4"模型的分词器进行token计算TokenCountEstimator openAiTokenCountEstimator = new OpenAiTokenCountEstimator("gpt-5");return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel)// 配置chatMemoryProvider,使用TokenWindowChatMemory// TokenWindowChatMemory.withMaxTokens(1000, openAiTokenCountEstimator)// 第一个参数:最大token数量限制为1000// 第二个参数:token计数器,用于计算每条消息的token数量.chatMemoryProvider(memoryId -> TokenWindowChatMemory.withMaxTokens(1000, openAiTokenCountEstimator)).build();}
}

🌐5.Web控制器

import cn.hutool.core.date.DateUtil;
import com.yumeko.study.service.ChatAssistant;
import com.yumeko.study.service.ChatMemoryAssistant;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
public class ChatMemoryController {@Resource(name = "chatMessageWindowChatMemory")private ChatMemoryAssistant chatMessageWindowChatMemory;@Resource(name = "chatTokenWindowChatMemory")private ChatMemoryAssistant chatTokenWindowChatMemory;/*** @Description: MessageWindowChatMemory实现聊天功能*/@GetMapping(value = "/chatmemory/test2")public String chatMessageWindowChatMemory() {chatMessageWindowChatMemory.chatWithChatMemory(1L, "你好!我的名字是Java.");String answer01 = chatMessageWindowChatMemory.chatWithChatMemory(1L, "我的名字是什么");System.out.println("answer01返回结果:" + answer01);chatMessageWindowChatMemory.chatWithChatMemory(3L, "你好!我的名字是python");String answer02 = chatMessageWindowChatMemory.chatWithChatMemory(3L, "我的名字是什么");System.out.println("answer02返回结果:" + answer02);return "chatMessageWindowChatMemory success : "+ DateUtil.now() + "<br> \n\n answer01: " + answer01 + "<br> \n\n answer02: " + answer02;}/*** @Description: TokenWindowChatMemory实现聊天功能*/@GetMapping(value = "/chatmemory/test3")public String chatTokenWindowChatMemory() {chatTokenWindowChatMemory.chatWithChatMemory(1L, "你好!我的名字是mysql");String answer01 = chatTokenWindowChatMemory.chatWithChatMemory(1L, "我的名字是什么");System.out.println("answer01返回结果:" + answer01);chatTokenWindowChatMemory.chatWithChatMemory(3L, "你好!我的名字是redis");String answer02 = chatTokenWindowChatMemory.chatWithChatMemory(3L, "我的名字是什么");System.out.println("answer02返回结果:" + answer02);return "chatTokenWindowChatMemory success : "+ DateUtil.now() + "<br> \n\n answer01: " + answer01 + "<br> \n\n answer02: " + answer02;}
}

🧪6.测试接口

http://localhost:9008/chatmemory/test2

http://localhost:9008/chatmemory/test3


📁langchain4j持久化聊天记忆

创建子模块langchain4j-10chat-persistence

📦1.pom.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.yumeko.stduy</groupId><artifactId>langchain4j</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>langchain4j-10chat-persistence</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--langchain4j-open-ai + langchain4j + langchain4j-reactor--><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId></dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId></dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-reactor</artifactId></dependency><!--spring-boot-starter-data-redishttps://docs.langchain4j.dev/tutorials/chat-memory#persistence--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.22</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

⚙️2.application.properties配置文件

server.port=9010spring.application.name=langchain4j-10chat-persistence# 设置响应的字符编码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true# ==========config redis===============
spring.data.redis.host=192.168.88.129
spring.data.redis.port=6379
spring.data.redis.database=0
spring.data.redis.password=yumeko
spring.data.redis.connect-timeout=3s
spring.data.redis.timeout=2s

🔧3.service服务

import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;public interface ChatPersistenceAssistant {/*** 聊天** @param userId  用户 ID* @param message 消息* @return {@link String }*/String chat(@MemoryId Long userId, @UserMessage String message);
}

🤖4.AI模型配置类

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
@Slf4j
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactor) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactor);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.ChatMessageDeserializer;
import dev.langchain4j.data.message.ChatMessageSerializer;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import java.util.List;/*** Redis聊天记忆存储实现类* * 该类实现了ChatMemoryStore接口,使用Redis作为聊天历史记录的持久化存储方案。* 它负责将用户的聊天记录序列化后存储到Redis中,并在需要时反序列化取出,* 实现了聊天上下文的持久化保存,即使应用重启也不会丢失历史记录。* * 主要功能:* 1. 将聊天消息序列化并存储到Redis* 2. 从Redis中获取并反序列化聊天消息* 3. 删除指定用户的聊天记录*/
@Component
public class RedisChatMemoryStore implements ChatMemoryStore {/*** Redis中聊天记录的键前缀* 所有聊天记录将以 "CHAT_MEMORY:{memoryId}" 的格式存储在Redis中*/public static final String CHAT_MEMORY_PREFIX = "CHAT_MEMORY:";/*** Redis操作模板,用于执行各种Redis操作* 通过@Resource注解自动注入Spring容器中的RedisTemplate实例*/@Resourceprivate RedisTemplate<String, String> redisTemplate;/*** 根据memoryId获取存储的聊天消息列表* * @param memoryId 用户会话标识符,用于区分不同用户的聊天记录* @return 该用户的所有聊天消息列表,如果不存在则返回空列表* * 实现原理:* 1. 构造Redis键名:CHAT_MEMORY_PREFIX + memoryId* 2. 从Redis中获取对应的值(JSON字符串)* 3. 使用ChatMessageDeserializer将JSON字符串反序列化为ChatMessage列表*/@Overridepublic List<ChatMessage> getMessages(Object memoryId) {String retValue = redisTemplate.opsForValue().get(CHAT_MEMORY_PREFIX + memoryId);return ChatMessageDeserializer.messagesFromJson(retValue);}/*** 更新指定memoryId的聊天消息列表* * @param memoryId 用户会话标识符,用于区分不同用户的聊天记录* @param messages 需要更新的聊天消息列表* * 实现原理:* 1. 使用ChatMessageSerializer将ChatMessage列表序列化为JSON字符串* 2. 构造Redis键名:CHAT_MEMORY_PREFIX + memoryId* 3. 将序列化后的JSON字符串存储到Redis中* * 持久化特点:* - 数据以字符串形式存储在Redis中,便于查看和调试* - 每个用户的聊天记录独立存储,通过memoryId进行隔离* - Redis的高性能保证了聊天记录读写的效率*/@Overridepublic void updateMessages(Object memoryId, List<ChatMessage> messages) {redisTemplate.opsForValue().set(CHAT_MEMORY_PREFIX + memoryId, ChatMessageSerializer.messagesToJson(messages));}/*** 删除指定memoryId的聊天消息* * @param memoryId 用户会话标识符,用于定位需要删除的聊天记录* * 使用场景:* - 用户主动清除聊天历史* - 系统定期清理过期聊天记录* - 隐私保护需求下的数据删除*/@Overridepublic void deleteMessages(Object memoryId) {redisTemplate.delete(CHAT_MEMORY_PREFIX + memoryId);}
}import com.yumeko.study.service.ChatPersistenceAssistant;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class LLMConfig {@Resourceprivate RedisChatMemoryStore redisChatMemoryStore;@Beanpublic ChatModel chatModel() {return OpenAiChatModel.builder().apiKey(System.getenv("qwen-api")).modelName("qwen-plus").baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1").build();}/*** @Description: 配置持久化聊天记忆助手* * 该Bean提供具备持久化能力的聊天记忆功能:* 1. 使用Redis作为聊天记录的持久化存储* 2. 结合MessageWindowChatMemory实现聊天历史记录的管理* 3. 限制最大保存1000条消息记录* 4. 通过memoryId参数区分不同用户的聊天上下文* * 实现原理:* 1. 创建ChatMemoryProvider,用于根据memoryId提供独立的聊天记忆实例* 2. 使用MessageWindowChatMemory作为聊天记忆的实现方式* 3. 通过redisChatMemoryStore实现聊天记录的持久化存储* 4. 构建AiServices服务,将chatModel和chatMemoryProvider整合* * 持久化特点:* - 聊天记录存储在Redis中,即使应用重启也不会丢失* - 每个用户(通过memoryId区分)拥有独立的聊天上下文* - 支持大规模并发用户访问,通过Redis实现高性能读写* * 相关组件:* - redisChatMemoryStore: Redis存储实现* - MessageWindowChatMemory: 基于消息窗口的聊天记忆管理* - ChatPersistenceAssistant: 持久化聊天助手接口*/@Beanpublic ChatPersistenceAssistant chatMemoryAssistant(ChatModel chatModel) {// 创建聊天记忆提供者,用于根据memoryId提供独立的聊天记忆实例// MessageWindowChatMemory.builder() 构建基于消息窗口的聊天记忆管理器// .id(memoryId) 设置记忆实例的唯一标识// .maxMessages(1000) 设置最大保存1000条消息// .chatMemoryStore(redisChatMemoryStore) 设置使用Redis作为持久化存储ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(1000).chatMemoryStore(redisChatMemoryStore).build();// 构建AiServices服务// 指定ChatPersistenceAssistant接口作为服务接口// .chatModel(chatModel) 设置使用的聊天模型// .chatMemoryProvider(chatMemoryProvider) 设置聊天记忆提供者return AiServices.builder(ChatPersistenceAssistant.class).chatModel(chatModel).chatMemoryProvider(chatMemoryProvider).build();}}

🌐5.Web控制器

import cn.hutool.core.date.DateUtil;
import com.yumeko.study.service.ChatPersistenceAssistant;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
public class ChatPersistenceController {@Resourceprivate ChatPersistenceAssistant chatPersistenceAssistant;// http://localhost:9010/chatpersistence/redis@GetMapping(value = "/chatpersistence/redis")public String testChatPersistence() {chatPersistenceAssistant.chat(1L, "你好!我的名字是redis");chatPersistenceAssistant.chat(2L, "你好!我的名字是nacos");String chat = chatPersistenceAssistant.chat(1L, "我的名字是什么");System.out.println(chat);chat = chatPersistenceAssistant.chat(2L, "我的名字是什么");System.out.println(chat);return "testChatPersistence success : " + DateUtil.now();}}

🧪6.测试接口

http://localhost:9010/chatpersistence/redis

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

相关文章:

  • 微信如何建立网站如何制作营销网站模板下载
  • 做网站图片多少钱推广普通话手抄报一等奖
  • android面试题2
  • AI学习日记——Transformer的架构:编码器与解码器
  • 如何推广自己网站的关键词网络营销方案例文
  • 网站文章收录慢微信小程序制作费用
  • Nginx第三方模块集成:丰富功能实战
  • ms-swift框架微调qwen3-0.6b模型
  • 企业网站架构德阳建设局网站
  • 电子电力技术的准谐振电路和LLC电路相关习题学习记录分享
  • 陕西省档案馆建设网站淘宝客建网站怎么做
  • 2025年江西省职业院校技能大赛高职组“区块链技术应用”任务书(4卷)
  • 大型电商网站开发成本wordpress远程媒体库
  • 聚云测网站怎么做的wordpress博客订单系统
  • Ax=b稀疏线性方程组的解法介绍
  • 深入理解跳表:数据结构解析与应用
  • 买了个域名 如何建网站移动营销型网站建设
  • Windows电脑数据迁移实战:如何无损迁移应用程序与系统设置
  • 专科医院网站建设管理类培训课程
  • 轮询中断 串口实训
  • IO接口介绍
  • 石家庄做物流的网站室内设计方案设计说明
  • rocketMQ-基本使用和原理简介
  • 2025出海品牌系统选型报告:破解业财一体化的隐形鸿沟
  • 自适应网站推广开发网站教程
  • ESP32 FreeRTOS任务与内存全指南
  • HeidiSQL导入与导出数据
  • 深圳龙华住房和建设局网站在线做gif图网站
  • 顺通建设集团有限公司 网站网站面包屑导航代码
  • springDI注入