> 自媒体 > (AI)人工智能 > 别再重启就丢对话!LangChain4j聊天记录持久化实战
别再重启就丢对话!LangChain4j聊天记录持久化实战
来源:发际线守护局
2026-05-16 15:52:56
109
管理

干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字段建个索引,不然会话多了查询会慢。

0
点赞
赏礼
赏钱
0
收藏
免责声明:本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本网证实,对本文以及其中全部或者 部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。 凡本网注明 “来源:XXX(非本站)”的作品,均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对 其真实性负责。 如因作品内容、版权和其它问题需要同本网联系的,请在一周内进行,以便我们及时处理。 QQ:617470285 邮箱:617470285@qq.com
相关文章
马斯克2018年邮件曝光,坦言已不再信任OpenAI
IT之家 4 月 30 日消息,2018 年,小岛秀夫造访 Valve 总部,洽谈《死亡..
OpenAI 挥刀 Sora,不只是止损
OpenAI突然宣布关闭Sora应用,背后暗藏战略大转向。从视频生成到电商功能..
OpenAI 发布 Daybreak 安全项目:对标 Anthropic,将安全检查融入日常代码..
5月12日消息,OpenAI 正式发布名为 Daybreak 的安全项目,旨在将安全审查..
马斯克悬了?曾给奥尔特曼特斯拉席位,红颜知己证词反帮OpenAI..
智东西编译 | 杨京丽编辑 | 李水青智东西5月7日消息,马斯克与OpenAI的世..
刚刚,OpenAI Codex登陆ChatGPT手机App,所有用户都能用
机器之心编辑部大家等这个等太久了。本周五,OpenAI 宣布 Codex 手机版在..
2023年被罢免后,OpenAI CEO奥尔特曼“短信轰炸”穆拉蒂寻求复职..
IT之家 5 月 7 日消息,据《商业内幕》7 日(今天)晚间报道,马斯克诉奥..
出门在外也能用!OpenAI 将 Codex 接入 ChatGPT 移动端
曾经在企业办公室工作过的人,可能都见过这样的场景:同事们把笔记本电脑..
奥尔特曼爆猛料:马斯克曾提出让其子女继承OpenAI
IT之家 5 月 13 日消息,OpenAI 首席执行官山姆・奥尔特曼终于出庭应诉,..
凌晨,OpenAI 与亚马逊云科技史上最大联合发布来了
作者 | 骆驼 4 月 20 日,Amazon 宣布在已有 $80 亿投资基础上再向 Anthr..
关于作者
婆罗花开(普通会员)
文章
2024
关注
0
粉丝
0
点击领取今天的签到奖励!
签到排行

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

0
0
分享
请选择要切换的马甲:

个人中心

每日签到

我的消息

内容搜索