LangChain4j记忆缓存+持久化
·

记忆缓存
记忆缓存是聊天系统中的一个重要组件,用于存储和管理对话的上下文信息。它的主要作用是让AI助手能够 “记住” 之前的对话内容,从而提供连贯和个性化的回复。
两种淘汰策略
- MessageWindowChatMemory: 基于消息数量的简单实现,它采用滑动窗口的方式,保留最新的N条消息并淘汰旧消息。
- TokenWindowChatMemory: 基于令牌数量限制,确保模型处理的上下文保持在指定范围内,需要结合TokenCountEstimator计算ChatMessage的token数量。
1. 引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- LangChain4j原生 基础-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!-- LangChain4j原生 高阶-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2. yml配置
server:
port: 9006
spring:
application:
name: langchain4j-memory
3. 主启动类
@SpringBootApplication
public class MemoryLangChain4jApp {
public static void main(String[] args) {
SpringApplication.run(MemoryLangChain4jApp.class, args);
}
}
4. 自定义 ChatMemoryAssistant 接口
public interface ChatMemoryAssistant {
/**
* 聊天带记忆缓存
* @param userId 用户ID
* @param msg 消息
* @return
*/
String chatMemory(@MemoryId Long userId, @UserMessage String msg);
}
5. 配置类 LLMConfig
@Configuration
public class LLMConfig {
@Bean(name = "qwen-long")
public ChatModel chatModelQwen() {
return OpenAiChatModel.builder()
.apiKey(System.getenv("ALIYUN_KEY"))
.modelName("qwen-long")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
// 按照 MessageWindowChatMemory 基于滑动窗口消息数量的淘汰策略
@Bean(name = "messageWindowChatMemory")
public ChatMemoryAssistant chatMessageWindowChatMemory(@Qualifier("qwen-long") ChatModel chatModelQwen) {
return AiServices.builder(ChatMemoryAssistant.class)
.chatModel(chatModelQwen)
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(100))
.build();
}
// 按照 TokenWindowChatMemory 基于令牌数量的淘汰策略
@Bean(name = "tokenWindowChatMemory")
public ChatMemoryAssistant chatTokenWindowChatMemory(@Qualifier("qwen-long") ChatModel chatModelQwen) {
// 使用 TokenCountEstimator 默认的token分词器
TokenCountEstimator tokenCountEstimator = new OpenAiTokenCountEstimator("gpt-4");
return AiServices.builder(ChatMemoryAssistant.class)
.chatModel(chatModelQwen)
.chatMemoryProvider(memoryId -> TokenWindowChatMemory.withMaxTokens(1000, tokenCountEstimator))
.build();
}
}
6. 控制类 MemoryLangChain4jController
@RestController
public class MemoryLangChain4jController {
@Resource(name = "messageWindowChatMemory")
private ChatMemoryAssistant chatMessageWindowChatMemory;
@Resource(name = "tokenWindowChatMemory")
private ChatMemoryAssistant chatTokenWindowChatMemory;
// MessageWindowChatMemory 实现聊天功能
// http://localhost:9006/chatMemory/test1
@GetMapping("/chatMemory/test1")
public String chatMessageWindowChatMemory() {
// 1号用户
chatMessageWindowChatMemory.chatMemory(1L, "你好,我的名字叫jack");
String result1 = chatMessageWindowChatMemory.chatMemory(1L, "我的名字叫什么");
// 3号用户
chatMessageWindowChatMemory.chatMemory(3L, "你好,我的名字叫tom");
String result3 = chatMessageWindowChatMemory.chatMemory(3L, "我的名字叫什么");
return "result1:" + result1 + "<br> result3:" + result3;
}
// TokenWindowChatMemory 实现聊天功能
// http://localhost:9006/chatMemory/test2
@GetMapping("/chatMemory/test2")
public String chatTokenWindowChatMemory() {
// 1号用户
chatTokenWindowChatMemory.chatMemory(1L, "你好,我的名字叫java");
String result1 = chatTokenWindowChatMemory.chatMemory(1L, "我的名字叫什么");
// 3号用户
chatTokenWindowChatMemory.chatMemory(3L, "你好,我的名字叫python");
String result3 = chatTokenWindowChatMemory.chatMemory(3L, "我的名字叫什么");
return "result1:" + result1 + "<br> result3:" + result3;
}
}
7. 测试
访问 http://localhost:9006/chatMemory/test1
访问 http://localhost:9006/chatMemory/test2
持久化
1. 引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- LangChain4j原生 基础-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!-- LangChain4j原生 高阶-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<!-- SpringBoot-redis 记忆缓存持久化-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2. yml配置
server:
port: 9008
spring:
application:
name: langchain4j-memory
# redis配置
data:
redis:
host: 192.168.195.135
port: 6379
database: 0
connect-timeout: 3s
timeout: 2s
3. 主启动类
@SpringBootApplication
public class PersistenceLangChain4jApp {
public static void main(String[] args) {
SpringApplication.run(PersistenceLangChain4jApp.class, args);
}
}
4. 自定义 ChatPersistenceAssistant 接口
public interface ChatPersistenceAssistant {
/**
* 聊天带记忆缓存
* @param userId 用户ID
* @param msg 消息
* @return
*/
String chat(@MemoryId Long userId, @UserMessage String msg);
}
5. 配置类
RedisTemplate配置类
@Configuration
public class RedisConfig
{
/**
* RedisTemplate配置
* redis序列化的工具配置类,下面这个请一定开启配置
* 127.0.0.1:6379> keys *
* 1) "ord:102" 序列化过
* 2) "\xac\xed\x00\x05t\x00\aord:102" 野生,没有序列化过
* this.redisTemplate.opsForValue(); //提供了操作string类型的所有方法
* this.redisTemplate.opsForList(); // 提供了操作list类型的所有方法
* this.redisTemplate.opsForSet(); //提供了操作set的所有方法
* this.redisTemplate.opsForHash(); //提供了操作hash表的所有方法
* this.redisTemplate.opsForZSet(); //提供了操作zset的所有方法
* @param redisConnectionFactor
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactor)
{
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactor);
//设置key序列化方式string
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
RedisChatMemoryStore配置类,实现ChatMemoryStore接口
@Component
public class RedisChatMemoryStore implements ChatMemoryStore {
public static final String CHAT_MEMORY_PREFIX = "CHAT_MEMORY:";
@Resource
private RedisTemplate<String, String> redisTemplate;
@Override
public List<ChatMessage> getMessages(Object memoryId) {
String value = redisTemplate.opsForValue().get(CHAT_MEMORY_PREFIX + memoryId);
return ChatMessageDeserializer.messagesFromJson(value);
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
redisTemplate.opsForValue().set(CHAT_MEMORY_PREFIX + memoryId, ChatMessageSerializer.messagesToJson(messages));
}
@Override
public void deleteMessages(Object memoryId) {
redisTemplate.delete(CHAT_MEMORY_PREFIX + memoryId);
}
}
大模型配置类LLMConfig
@Configuration
public class LLMConfig {
@Resource
private RedisChatMemoryStore redisChatMemoryStore;
@Bean(name = "qwen")
public ChatModel chatModelQwen() {
return OpenAiChatModel.builder()
.apiKey(System.getenv("ALIYUN_KEY"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
@Bean
public ChatPersistenceAssistant chatPersistenceAssistant(@Qualifier("qwen") ChatModel chatModelQwen) {
ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(1000)
.chatMemoryStore(redisChatMemoryStore)
.build();
return AiServices.builder(ChatPersistenceAssistant.class)
.chatModel(chatModelQwen)
.chatMemoryProvider(chatMemoryProvider)
.build();
}
}
6. 控制类 PersistenceLangChain4jController
@RestController
public class PersistenceLangChain4jController {
@Resource
private ChatPersistenceAssistant chatPersistenceAssistant;
// http://localhost:9008/chatPersistence/redis/chat
@GetMapping("/chatPersistence/redis/chat")
public String chat() {
chatPersistenceAssistant.chat(1L, "你好,我叫redis");
chatPersistenceAssistant.chat(2L, "你好,我的名字叫mysql");
String result1 = chatPersistenceAssistant.chat(1L, "我的名字叫什么");
String result2 = chatPersistenceAssistant.chat(2L, "我的名字叫什么");
return "result1:" + result1 + "<br> result2:" + result2;
}
}
7. 测试
访问 http://localhost:9008/chatPersistence/redis/chat
连接上redis,我们看到对话信息已经存储到redis中
注意:这里连接redis客户端,一定要加 --raw,否则中文乱码
总结
以上主要介绍了 LangChain4j 记忆缓存、持久化相关知识,想了解更多 LangChain4j 知识的小伙伴请参考 LangChain4j 官网 进行学习,学习更多 LangChain4j 实战实用技巧的小伙伴,请关注后期发布的文章,认真看完一定能让你有所收获。
更多推荐
所有评论(0)