干LangChain4j开发的朋友,是不是都踩过这个坑:
1.用内存存对话,服务一重启,用户聊天记录全没了
2.线上项目不敢用内存,用户换个设备对话就断了
3.想做持久化,又纠结选MongoDB还是MySQL,怕后期改结构麻烦?
别慌,今天就给你一套线上项目可直接落地的LangChain4j聊天记录持久化方案,用MongoDB搞定,不用拆表、不用改字段,json格式完美适配LangChain4j的消息结构,看完就能直接用在项目里。
前面章节介绍了下LangChain4j的内存持久化,最头疼的就是 “内存里的对话一重启就没了”,线上项目更是不敢用内存存,用户换个设备对话就断了。
这时候就得搞持久化,选 Mongodb 是真的省心,不用提前定义表结构,存 JSON 格式的聊天记录刚好适配 LangChain4j 的消息结构。
为啥选 MongoDB,而不是 MySQL?说句实在的,聊天记录这种半结构化数据,放 MySQL 里得拆表、建字段,每次改个消息格式都要改表结构,巨麻烦。
MongoDB 的文档型存储就刚好适配,一条对话历史直接整个 JSON 塞进去,字段想加就加,不用改库表结构,线上业务里改需求也不慌。
而且 LangChain4j 的 ChatMessage 序列化后就是 JSON,直接存进去,读的时候反序列化就行,不用做复杂的字段映射。主打一个方便
一步到位,SpringBoot MongoDB 持久化聊天记忆1. 先把 MongoDB 和依赖装好我本地安装了docker-desktop,直接容器安装
#拉取镜像docker pull mongodb/mongodb-community-server:latest#运行 powershell 运行脚本docker run -d `--name mongodb `-p 27017:27017 `-v D:Studyfiles-tmpMongodbdata:/data/db `-e MONGO_INITDB_ROOT_USERNAME=admin `-e MONGO_INITDB_ROOT_PASSWORD=123456 `--restart=always `mongodb/mongodb-community-server:latest
SpringBoot 里加 MongoDB 依赖,就这一个 starter:
org.springframework.boot spring-boot-starter-data-mongodb
配置文件里连一下库,直接用本地默认端口:
spring: application: name: java-ai-langchain data: mongodb: uri: mongodb://admin:123456@127.0.0.1:27017/chat_memory_data?authSource=admin2. 写个实体类,映射聊天记录
这个实体类很简单,就存三个东西:MongoDB 主键、会话 ID、序列化后的消息 JSON:
@Data@AllArgsConstructor@NoArgsConstructor@Document("chat_messages")public class CustomerChatMessages implements Serializable { //唯一标识,映射到 MongoDB 文档的 _id 字段 @Id private ObjectId id; /** * 聊天记录的ID memoryId */ private String memoryId; /** * 聊天记录列表 存储当前聊天记录列表的json字符串 */ private String content;}3. 实现 ChatMemoryStore,接管持久化
LangChain4j 给了个ChatMemoryStore接口,实现它就能自定义持久化逻辑,读和写都自己控制:
/** * 功能描述: 持久化聊天记录 * * @author 周五不部署 * @date 2026-05-08 */@Component@Slf4j(topic = "MongodbChatMemoryStore")public class MongodbChatMemoryStore implements ChatMemoryStore { @Autowired private MongoTemplate mongoTemplate; /** * 获取聊天记录 // 读消息:根据会话ID从MongoDB里查,再反序列化成ChatMessage列表 * @param memoryId * @return */ @Override public List getMessages(Object memoryId) { Criteria criteria = Criteria.where("memoryId").is(memoryId); Query query = new Query(criteria); CustomerChatMessages chatMessage = mongoTemplate.findOne(query, CustomerChatMessages.class); if(chatMessage != null){ String chatMessageContent = chatMessage.getContent(); log.info("memoryId: {} , getMessages:{}",memoryId,chatMessageContent); return ChatMessageDeserializer.messagesFromJson(chatMessageContent); } return List.of(); } @Override public void updateMessages(Object memoryId, List messages) { log.info("memoryId: {} , updateMessages:{}",memoryId,messages); Criteria criteria = Criteria.where("memoryId").is(memoryId); Query query = new Query(criteria); Update update = new Update(); update.set("content", ChatMessageSerializer.messagesToJson(messages)); // 根据memoryId 查询 文档数据 有则更新,没有则新增 mongoTemplate.upsert(query,update,CustomerChatMessages.class); } // 删消息:按会话ID删掉MongoDB里的记录 @Override public void deleteMessages(Object memoryId) { Criteria criteria = Criteria.where("memoryId").is(memoryId); Query query = new Query(criteria); mongoTemplate.remove(query,CustomerChatMessages.class); log.info("memoryId: {} , deleteMessages",memoryId); }}4. 把持久化 Store 绑到 ChatMemory 上
配置里把 Mongo 的 Store 和 ChatMemoryProvider 绑在一起,这样每个会话的消息都会自动存到 MongoDB 里:
@Autowired private MongodbChatMemoryStore mongodbChatMemoryStore; /** * 配置 ChatMemoryProvider 聊天记录隔离 * @return */ @Bean public ChatMemoryProvider chatMemoryProvider() { return (memoryId) -> MessageWindowChatMemory .builder() .id(memoryId) .maxMessages(10) .chatMemoryStore(mongodbChatMemoryStore) .build(); }5. 接口里加 @MemoryId,测试一下
在你的 AiService 接口里加上会话 ID 参数,这样不同用户 / 对话的记忆就会隔离存到 MongoDB 里:
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT, chatModel = "qwenChatModel", chatMemory = "chatMemory", chatMemoryProvider = "chatMemoryProvider")public interface AssistantChatIsolation { /** * 聊天 * @param memoryId 会话ID * @param userMessage 用户消息 * @return 聊天结果 */ String chat(@MemoryId String memoryId, @UserMessage String userMessage);}
测试的时候用不同的 memoryId,重启项目再发消息,模型还是能记住你之前说的话:
@Test public void chatStoreTest() { String chatted = assistantChatIsolation.chat("1","我是张三三"); log.info("chatted:{}" , chatted); String chatted1 = assistantChatIsolation.chat("1", "我是谁"); log.info("chatted1: {}" , chatted1); }
表中的数据:
几个踩过的小坑JSON 序列化反序列化失败:别自己写序列化工具,LangChain4j 自带的ChatMessageSerializer和ChatMessageDeserializer就够了,用第三方库容易有格式问题。会话 ID 类型不一致:@MemoryId的参数类型和 MongoDB 里存的类型要一致,别一会用 int 一会用 String,不然查不到数据。消息数设太大:maxMessages别设成 100,不然 MongoDB 里存的 JSON 会越来越大,模型调用也会变慢,一般 10-20 条就够了。MongoDB 连接没加 authSource:如果你的 MongoDB 开了账号密码,连接 URI 里要加?authSource=admin,不然认证失败连不上。说句实在的,持久化聊天记忆没什么复杂的,就是实现一个ChatMemoryStore接口,把读写逻辑换成 MongoDB 就行。
线上项目里这么一套下来,用户换设备、重启服务都不会丢对话,稳定性比内存里存强太多了。
记得 MongoDB 里给memoryId字段建个索引,不然会话多了查询会慢。
相关文章









猜你喜欢
成员 网址收录40418 企业收录2986 印章生成263660 电子证书1157 电子名片68 自媒体110111