参考文档:聊天记忆
聊天记忆含义
LangChain4j 提供的聊天记忆的抽象容器,用于简化手动维护和管理聊天消息的繁琐工作。
记忆 vs 历史的区别:
- 历史:保持用户和AI之间所有消息的完整记录,是用户在UI中看到的实际对话内容
- 记忆:保存部分信息呈现给LLM,使其表现得"记住"对话,可以通过淘汰、总结、修改消息等方式处理历史
主要功能特性
- 淘汰策略:自动管理消息数量以适应LLM上下文窗口限制
MessageWindowChatMemory(消息计数):保留最近的N条消息TokenWindowChatMemory(Tokenizer计数):保留最近的N个 Token
- 持久化支持:可将聊天消息存储到持久化存储(
ChatMemoryStore)中 - SystemMessage特殊处理:系统消息的专门管理机制
- 工具消息特殊处理:避免孤立工具执行结果消息导致的问题
代码示例
在创建 AiService 时,再添加一个 chatMemoryProvider 即可。
// LLMConfig.java
// MessageWindowChatMemory示例
@Bean(name = "chatMessageWindowChatMemory")
public ChatMemoryAssistant chatMessageWindowChatMemory(ChatModel chatModel)
{ return AiServices.builder(ChatMemoryAssistant.class) .chatModel(chatModel) //按照memoryId对应创建了一个chatMemory .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(100)) .build();
} // TokenWindowChatMemory示例(需要Tokenizer计数)
@Bean(name = "chatTokenWindowChatMemory")
public ChatMemoryAssistant chatTokenWindowChatMemory(ChatModel chatModel)
{TokenCountEstimator openAiTokenCountEstimator = new OpenAiTokenCountEstimator("gpt-4"); return AiServices.builder(ChatMemoryAssistant.class) .chatModel(chatModel) .chatMemoryProvider(memoryId -> TokenWindowChatMemory.withMaxTokens(1000,openAiTokenCountEstimator)) .build();
}
聊天记忆持久化
用 redis 为例。
- 实现
ChatMemoryStore接口。注意需要用messagesToJson和messagesToJson进行序列化和反序列化。
// RedisChatMemoryStore.java
@Component
public class RedisChatMemoryStore implements ChatMemoryStore
{public static final String CHAT_MEMORY_PREFIX = "CHAT_MEMORY:";@Resourceprivate RedisTemplate<String,String> redisTemplate;@Overridepublic List<ChatMessage> getMessages(Object memoryId){String retValue = redisTemplate.opsForValue().get(CHAT_MEMORY_PREFIX + memoryId);return ChatMessageDeserializer.messagesFromJson(retValue);}@Overridepublic void updateMessages(Object memoryId, List<ChatMessage> messages){redisTemplate.opsForValue().set(CHAT_MEMORY_PREFIX + memoryId, ChatMessageSerializer.messagesToJson(messages));}@Overridepublic void deleteMessages(Object memoryId){redisTemplate.delete(CHAT_MEMORY_PREFIX + memoryId);}
}
- 创建
ChatMemoryProvider,添加ChatMemoryStore
// LLMConfig.java
// ...
@Bean
public ChatPersistenceAssistant chatMemoryAssistant(ChatModel chatModel)
{ ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder() .id(memoryId) .maxMessages(1000) .chatMemoryStore(redisChatMemoryStore) .build(); // TokenCountEstimator openAiTokenCountEstimator = new OpenAiTokenCountEstimator("gpt-4");
// ChatMemoryProvider chatMemoryProvider1 = memoryId -> TokenWindowChatMemory.builder()
// .id(memoryId)
// .maxTokens(1000, openAiTokenCountEstimator)
// .chatMemoryStore(redisChatMemoryStore)
// .build(); return AiServices.builder(ChatPersistenceAssistant.class) .chatModel(chatModel) .chatMemoryProvider(chatMemoryProvider) .build();
}
// ...
