LangChain4j + MongoDB 聊天记忆存储
这部分代码是基于 Spring Boot 框架,结合 LangChain4j 库实现聊天记忆(Chat Memory)的 MongoDB 持久化存储方案。核心功能是将 LangChain4j 中的聊天消息列表序列化后存入 MongoDB,并提供读取、更新、删除聊天记忆的能力,同时配置了基于消息窗口的聊天记忆提供者。核心逻辑:通过实现 LangChain4j 的接口,结合 Spring Data M
一、整体功能概述
这部分代码是基于 Spring Boot 框架,结合 LangChain4j 库实现聊天记忆(Chat Memory) 的 MongoDB 持久化存储方案。核心功能是将 LangChain4j 中的聊天消息列表序列化后存入 MongoDB,并提供读取、更新、删除聊天记忆的能力,同时配置了基于消息窗口的聊天记忆提供者。
二、代码结构与模块拆分
表格
| 包路径 | 类名 | 核心作用 |
|---|---|---|
| com.qcby.config | SeparateChatAssistantConfig | 配置类:定义 ChatMemoryProvider Bean,指定基于消息窗口的聊天记忆规则 |
| com.qcby.store | MongoChatMemoryStore | 存储实现类:实现 LangChain4j 的 ChatMemoryStore 接口,对接 MongoDB 操作 |
| com.qcby.model | ChatMessages | 实体类:映射 MongoDB 的 chat_messages 集合,存储聊天记录的 JSON 字符串 |
三、核心类详细解析
1. 实体类:ChatMessages(com.qcby.model)
作用
映射 MongoDB 中的 chat_messages 集合,是聊天记录持久化的载体,存储序列化后的聊天消息 JSON 字符串。
关键代码与注解说明
java
运行
package com.qcby.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Data // Lombok:自动生成get/set/toString/hashCode/equals等方法
@AllArgsConstructor // 生成全参构造器
@NoArgsConstructor // 生成无参构造器
@Document("chat_messages") // 映射到 MongoDB 的 chat_messages 集合
public class ChatMessages {
// 唯一标识,映射 MongoDB 文档的 _id 字段(MongoDB 默认主键类型为 ObjectId)
@Id
private ObjectId id;
// 存储聊天消息列表的 JSON 字符串(核心字段)
private String content;
// 冗余字段(当前代码未使用,可根据业务调整)
private int messageId;
}
核心字段说明
表格
| 字段名 | 类型 | 作用 |
|---|---|---|
| id | ObjectId | MongoDB 文档主键,由 MongoDB 自动生成,唯一标识一条聊天记录文档 |
| content | String | 核心字段:存储 LangChain4j 中 ChatMessage 列表序列化后的 JSON 字符串 |
| messageId | int | 自定义消息 ID(当前代码未使用,可用于业务层的消息标识) |
2. 存储实现类:MongoChatMemoryStore(com.qcby.store)
作用
实现 LangChain4j 提供的 ChatMemoryStore 接口,重写聊天记忆的读取、更新、删除方法,底层通过 Spring Data MongoDB 的 MongoTemplate 操作数据库。
关键代码与解析
java
运行
package com.qcby.store;
import com.qcby.model.ChatMessages;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import java.util.LinkedList;
import java.util.List;
@Component // 注册为 Spring 组件,可被自动注入
public class MongoChatMemoryStore implements ChatMemoryStore {
// 注入 Spring Data MongoDB 的核心操作类
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据 memoryId 读取聊天消息
* @param memoryId 聊天记忆唯一标识(如用户ID/会话ID)
* @return 反序列化后的 ChatMessage 列表
*/
@Override
public List<ChatMessage> getMessages(Object memoryId) {
// 构建查询条件:根据 memoryId 匹配文档
Criteria criteria = Criteria.where("memoryId").is(memoryId);
Query query = new Query(criteria);
// 查询 MongoDB 中对应的 ChatMessages 文档
ChatMessages chatMessages = mongoTemplate.findOne(query, ChatMessages.class);
// 无数据时返回空链表,避免空指针
if(chatMessages == null) return new LinkedList<>();
// 将 JSON 字符串反序列化为 ChatMessage 列表
return ChatMessageDeserializer.messagesFromJson(chatMessages.getContent());
}
/**
* 更新聊天消息(不存在则新增,存在则修改)
* @param memoryId 聊天记忆唯一标识
* @param messages 待存储的 ChatMessage 列表
*/
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
Criteria criteria = Criteria.where("memoryId").is(memoryId);
Query query = new Query(criteria);
Update update = new Update();
// 将 ChatMessage 列表序列化为 JSON 字符串,存入 content 字段
update.set("content", ChatMessageSerializer.messagesToJson(messages));
// upsert:查询到则更新,未查询到则插入新文档
mongoTemplate.upsert(query, update, ChatMessages.class);
}
/**
* 根据 memoryId 删除聊天消息
* @param memoryId 聊天记忆唯一标识
*/
@Override
public void deleteMessages(Object memoryId) {
Criteria criteria = Criteria.where("memoryId").is(memoryId);
Query query = new Query(criteria);
// 删除匹配的文档
mongoTemplate.remove(query, ChatMessages.class);
}
}
核心依赖与工具类说明
表格
| 类名 | 作用 |
|---|---|
| MongoTemplate | Spring Data MongoDB 核心类,提供 MongoDB 的 CRUD 操作 |
| ChatMessageSerializer | LangChain4j 工具类:将 ChatMessage 列表序列化为 JSON 字符串 |
| ChatMessageDeserializer | LangChain4j 工具类:将 JSON 字符串反序列化为 ChatMessage 列表 |
| Criteria/Query/Update | Spring Data MongoDB 查询构建器:用于构建查询条件和更新操作 |
核心方法逻辑
getMessages:根据memoryId查询文档 → 无数据返回空链表 → 有数据则反序列化 JSON 为消息列表;updateMessages:将消息列表序列化为 JSON → 执行upsert操作(新增 / 更新);deleteMessages:根据memoryId删除对应文档。
3. 配置类:SeparateChatAssistantConfig(com.qcby.config)
作用
配置 LangChain4j 的 ChatMemoryProvider Bean,定义聊天记忆的规则(如消息窗口大小、持久化存储实现)。
关键代码与解析
java
运行
package com.qcby.config;
import com.qcby.store.MongoChatMemoryStore;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // 标识为 Spring 配置类
public class SeparateChatAssistantConfig {
// 注入自定义的 MongoDB 聊天记忆存储实现
@Autowired
private MongoChatMemoryStore mongoChatMemoryStore;
/**
* 定义 ChatMemoryProvider Bean
* @return 基于消息窗口的聊天记忆提供者
*/
@Bean
ChatMemoryProvider chatMemoryProvider() {
// 函数式接口:根据 memoryId 创建对应的 MessageWindowChatMemory
return memoryId -> MessageWindowChatMemory.builder()
.id(memoryId) // 绑定聊天记忆唯一标识
.maxMessages(10) // 消息窗口大小:最多保留最近 10 条消息
.chatMemoryStore(mongoChatMemoryStore) // 配置持久化存储实现
.build();
}
}
核心配置说明
表格
| 配置项 | 作用 |
|---|---|
| MessageWindowChatMemory | LangChain4j 提供的聊天记忆实现,基于 “窗口” 保留最近 N 条消息 |
| maxMessages(10) | 限制聊天记忆最多保留 10 条消息,超出则自动丢弃最早的消息 |
| chatMemoryStore | 指定聊天记忆的持久化存储实现(即自定义的 MongoChatMemoryStore) |
四、依赖与环境要求
- 核心依赖(需在 pom.xml 中引入):
xml
<!-- Spring Data MongoDB --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <!-- LangChain4j 核心 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-core</artifactId> <version>最新版本</version> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> - 环境配置:
- 配置 MongoDB 连接(application.yml/application.properties):
yaml
spring: data: mongodb: uri: mongodb://localhost:27017/你的数据库名 # 或分开配置 # host: localhost # port: 27017 # database: 你的数据库名
- 配置 MongoDB 连接(application.yml/application.properties):
五、核心流程梳理
预览
查看代码
业务层调用 ChatMemoryProvider
根据 memoryId 创建 MessageWindowChatMemory
MessageWindowChatMemory 调用 MongoChatMemoryStore
getMessages:从 MongoDB 读取并反序列化消息
updateMessages:序列化消息并 upsert 到 MongoDB
deleteMessages:从 MongoDB 删除指定消息
D1/D2/D3
MongoTemplate 执行 MongoDB CRUD 操作
flowchart TD
A[业务层调用 ChatMemoryProvider] --> B[根据 memoryId 创建 MessageWindowChatMemory]
B --> C[MessageWindowChatMemory 调用 MongoChatMemoryStore]
C --> D1[getMessages:从 MongoDB 读取并反序列化消息]
C --> D2[updateMessages:序列化消息并 upsert 到 MongoDB]
C --> D3[deleteMessages:从 MongoDB 删除指定消息]
D1/D2/D3 --> E[MongoTemplate 执行 MongoDB CRUD 操作]
业务层调用 ChatMemoryProvider
根据 memoryId 创建 MessageWindowChatMemory
MessageWindowChatMemory 调用 MongoChatMemoryStore
getMessages:从 MongoDB 读取并反序列化消息
updateMessages:序列化消息并 upsert 到 MongoDB
deleteMessages:从 MongoDB 删除指定消息
六、注意事项与优化建议
- memoryId 设计:
memoryId是聊天记忆的唯一标识,建议使用用户 ID + 会话 ID组合,避免不同用户 / 会话的消息混淆;- 当前代码中
ChatMessages实体缺少memoryId字段(代码中查询条件用了memoryId但实体未定义),需补充:java
运行
// 在 ChatMessages 类中添加 private String memoryId; // 对应查询条件的 memoryId 字段
- 消息序列化 / 反序列化:
- LangChain4j 的
ChatMessageSerializer/Deserializer基于 Jackson 实现,需确保 ChatMessage 的序列化格式兼容;
- LangChain4j 的
- 性能优化:
- 高频读取场景可添加 MongoDB 索引(针对
memoryId字段):java
运行
// 在 ChatMessages 实体中添加索引注解 @Indexed(unique = true) // 确保 memoryId 唯一 private String memoryId;
- 高频读取场景可添加 MongoDB 索引(针对
- 异常处理:
- 当前代码未处理 MongoDB 连接异常、序列化 / 反序列化异常,建议添加 try-catch 并抛出业务异常:
java
运行
@Override public List<ChatMessage> getMessages(Object memoryId) { try { Criteria criteria = Criteria.where("memoryId").is(memoryId); Query query = new Query(criteria); ChatMessages chatMessages = mongoTemplate.findOne(query, ChatMessages.class); if(chatMessages == null) return new LinkedList<>(); return ChatMessageDeserializer.messagesFromJson(chatMessages.getContent()); } catch (Exception e) { throw new RuntimeException("读取聊天记忆失败:" + e.getMessage(), e); } }
- 当前代码未处理 MongoDB 连接异常、序列化 / 反序列化异常,建议添加 try-catch 并抛出业务异常:
总结
- 核心逻辑:通过实现 LangChain4j 的
ChatMemoryStore接口,结合 Spring Data MongoDB 完成聊天记忆的持久化,配置MessageWindowChatMemory限制消息数量; - 关键组件:
MongoChatMemoryStore(数据库操作)、ChatMessages(数据载体)、SeparateChatAssistantConfig(Bean 配置); - 注意点:补充
ChatMessages的memoryId字段、添加异常处理、为memoryId建立索引提升查询性能。
更多推荐
所有评论(0)