一、整体功能概述

这部分代码是基于 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)

四、依赖与环境要求

  1. 核心依赖(需在 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>
    
  2. 环境配置
    • 配置 MongoDB 连接(application.yml/application.properties):

      yaml

      spring:
        data:
          mongodb:
            uri: mongodb://localhost:27017/你的数据库名
            # 或分开配置
            # host: localhost
            # port: 27017
            # database: 你的数据库名
      

五、核心流程梳理

预览

查看代码

业务层调用 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 删除指定消息

六、注意事项与优化建议

  1. memoryId 设计
    • memoryId 是聊天记忆的唯一标识,建议使用用户 ID + 会话 ID组合,避免不同用户 / 会话的消息混淆;
    • 当前代码中 ChatMessages 实体缺少 memoryId 字段(代码中查询条件用了 memoryId 但实体未定义),需补充:

      java

      运行

      // 在 ChatMessages 类中添加
      private String memoryId; // 对应查询条件的 memoryId 字段
      
  2. 消息序列化 / 反序列化
    • LangChain4j 的 ChatMessageSerializer/Deserializer 基于 Jackson 实现,需确保 ChatMessage 的序列化格式兼容;
  3. 性能优化
    • 高频读取场景可添加 MongoDB 索引(针对 memoryId 字段):

      java

      运行

      // 在 ChatMessages 实体中添加索引注解
      @Indexed(unique = true) // 确保 memoryId 唯一
      private String memoryId;
      
  4. 异常处理
    • 当前代码未处理 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);
          }
      }
      

总结

  1. 核心逻辑:通过实现 LangChain4j 的 ChatMemoryStore 接口,结合 Spring Data MongoDB 完成聊天记忆的持久化,配置 MessageWindowChatMemory 限制消息数量;
  2. 关键组件:MongoChatMemoryStore(数据库操作)、ChatMessages(数据载体)、SeparateChatAssistantConfig(Bean 配置);
  3. 注意点:补充 ChatMessagesmemoryId 字段、添加异常处理、为 memoryId 建立索引提升查询性能。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐