LangChain4j—持久化聊天记忆 Persistence(五)

持久化聊天记忆 Persistence

默认情况下,聊天记忆存储在内存中。如果需要持久化存储,可以实现一个自定义的聊天记忆存储类,以便将聊天消息存储在你选择的任何持久化存储介质中。

1、存储介质的选择

大模型中聊天记忆的存储选择哪种数据库,需要综合考虑数据特点、应用场景和性能要求等因素,以下 是一些常见的选择及其特点:

1. MySQL

  • 特点:关系型数据库。支持事务处理,确保数据的一致性和完整性,适用于结构化数据的存储 和查询
  • 适用场景:如果聊天记忆数据结构较为规整,例如包含固定的字段如对话 ID、用户 ID、时间 戳、消息内容等,且需要进行复杂的查询和统计分析,如按用户统计对话次数、按时间范围查 询特定对话等,MySQL 是不错的选择。

2.Redis

  • 特点:内存数据库,读写速度极高。它适用于存储热点数据,并且支持多种数据结构,如字符 串、哈希表、列表等,方便对不同类型的聊天记忆数据进行处理

  • 适用场景:对于实时性要求极高的聊天应用,如在线客服系统或即时通讯工具,Redis 可以快 速存储和获取最新的聊天记录,以提供流畅的聊天体验。

3.MongoDB

  • 特点:文档型数据库,数据以 JSON - like 的文档形式存储,具有高度的灵活性和可扩展性。它

不需要预先定义严格的表结构,适合存储半结构化或非结构化的数据

  • 适用场景:当聊天记忆中包含多样化的信息,如文本消息、图片、语音等多媒体数据,或者消

息格式可能会频繁变化时,MongoDB 能很好地适应这种灵活性。例如,一些社交应用中用户可

能会发送各种格式的消息,使用 MongoDB 可以方便地存储和管理这些不同类型的数据。

4.Cassandra

特点:是一种分布式的 NoSQL 数据库,具有高可扩展性和高可用性,能够处理大规模的分布

式数据存储和读写请求。适合存储海量的、时间序列相关的数据

适用场景:对于大型的聊天应用,尤其是用户量众多、聊天数据量巨大且需要分布式存储和处

理的场景,Cassandra 能够有效地应对高并发的读写操作。例如,一些面向全球用户的社交媒

体平台,其聊天数据需要在多个节点上进行分布式存储和管理,Cassandra 可以提供强大的支

持。

2、MongoDB

简介

MongoDB 是一个基于文档的 NoSQL 数据库,由 MongoDB Inc. 开发。

NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数

据库的数据库管理系统的统称。

MongoDB 的设计理念是为了应对大数据量、高性能和灵活性需求

MongoDB使用集合(Collections)来组织文档(Documents),每个文档都是由键值对组成的。

  • 数据库(Database):存储数据的容器,类似于关系型数据库中的数据库。

  • 集合(Collection):数据库中的一个集合,类似于关系型数据库中的表。

  • 文档(Document):集合中的一个数据记录,类似于关系型数据库中的行(row),以 BSON 格式 存储。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成,文档类似于 JSON 对象,字段值 可以包含其他文档,数组及文档数组:

安装MongoDB

服务器: mongodb-windows-x86_64-8.0.6-signed.msi www.mongodb.com/try/downloa...

命令行客户端 : mongosh-2.5.0-win32-x64.zip www.mongodb.com/try/downloa...

图形客户端: mongodb-compass-1.39.3-win32-x64.exe www.mongodb.com/try/downloa...

使用 mongosh

启动MongoDB Shell: 在命令行中输入mongosh,启动MongoDB Shell ,如果MongoDB服务器运行在本地默认端口27017,则可以直接连接

连接到 MongoDB 服务器: 如果MongoDB服务器运行在非默认端口或者远程服务器,则可以用以下命令连接:

bash 复制代码
mongosh --host <hostname>:<port>

其中 <hostname> 是 MongoDB 服务器的主机名或 IP 地址, <port> 是 MongoDB 服务器的端口号。

执行基本操作:

连接成功后,可以执行各种 MongoDB 数据库操作。例如:

  • 查看当前数据库: db

  • 显示数据库列表: show dbs

  • 切换到指定数据库: use <database_name>

  • 执行查询操作: db.<collection_name>.find()

  • 插入文档: db.<collection_name>.insertOne({ ... })

  • 更新文档: db.<collection_name>.updateOne({ ... })

  • 删除文档: db.<collection_name>.deleteOne({ ... })

  • 退出 MongoDB Shell: quit() 或者 exit

CRUD:

bash 复制代码
# 插入文档
test> db.mycollection.insertOne({ name: "Alice", age: 30 })

# 查询文档
test> db.mycollection.find()

# 更新文档
test> db.mycollection.updateOne({ name: "Alice" }, { $set: { age: 31 } })

# 删除文档
test> db.mycollection.deleteOne({ name: "Alice" })

# 退出 MongoDB Shell
test> quit()

使用mongodb-compass

整合SpringBoot

引入MongoDB依赖:

java 复制代码
<!-- Spring Boot Starter Data MongoDB -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

添加远程连接配置:

java 复制代码
#MongoDB连接配置
spring.data.mongodb.uri=mongodb://localhost:27017/chat_memory_db

测试

实体类

java 复制代码
package com.atguigu.java.ai.langchain4j.bean;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document("chat_messages")
public class ChatMessages {

    //唯一标识,映射到 MongoDB 文档的 _id 字段
    @Id
    private ObjectId messageId;

    private String content; //存储当前聊天记录列表的json字符串

}

测试类:

java 复制代码
package com.atguigu.java.ai.langchain4j;

@SpringBootTest
public class MongoCrudTest {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
    * 插入文档
    */
    /* @Test
    public void testInsert() {
        mongoTemplate.insert(new ChatMessages(1L, "聊天记录"));
    }
    */
    /**
    * 插入文档
    */
    @Test
    public void testInsert2() {
        ChatMessages chatMessages = new ChatMessages();
        chatMessages.setContent("聊天记录列表");
        mongoTemplate.insert(chatMessages);
    }

    /**
    * 根据id查询文档
    */
    @Test
    public void testFindById() {
        ChatMessages chatMessages = mongoTemplate.findById("6801ead733ba9c4a0d9b6c7b",
        ChatMessages.class);
        System.out.println(chatMessages);
    }
    
    /**
    * 修改文档
    */
    @Test
    public void testUpdate() {
        Criteria criteria = Criteria.where("_id").is("6801ead733ba9c4a0d9b6c7b");
        Query query = new Query(criteria);
        Update update = new Update();
        update.set("content", "新的聊天记录列表");

        //修改或新增
        mongoTemplate.upsert(query, update, ChatMessages.class);
    }

    /**
    * 新增或修改文档
    */
    @Test
    public void testUpdate2() {
        Criteria criteria = Criteria.where("_id").is("100");
        Query query = new Query(criteria);
        Update update = new Update();
        update.set("content", "新的聊天记录列表");
        //修改或新增
        mongoTemplate.upsert(query, update, ChatMessages.class);
    }

3、持久化聊天

实体类

java 复制代码
package com.atguigu.java.ai.langchain4j.bean;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document("chat_messages")
public class ChatMessages {
    //唯一标识,映射到 MongoDB 文档的 _id 字段
    @Id
    private ObjectId id;

    private int messageId;

    private String content; //存储当前聊天记录列表的json字符串
}

创建持久化类

创建一个类实现ChatMemoryStore接口

java 复制代码
package com.atguigu.java.ai.langchain4j.store;

@Component
public class MongoChatMemoryStore implements ChatMemoryStore {

@Autowired
private MongoTemplate mongoTemplate;

@Override
public List<ChatMessage> getMessages(Object memoryId) {
    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());
}

@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();
    update.set("content", ChatMessageSerializer.messagesToJson(messages));
    //根据query条件能查询出文档,则修改文档;否则新增文档
    mongoTemplate.upsert(query, update, ChatMessages.class);
}

@Override
public void deleteMessages(Object memoryId) {
    Criteria criteria = Criteria.where("memoryId").is(memoryId);
    Query query = new Query(criteria);
    mongoTemplate.remove(query, ChatMessages.class);
    }
}

在SeparateChatAssistantConfig中,添加MongoChatMemoryStore对象的配置

java 复制代码
package com.atguigu.java.ai.langchain4j.config;

@Configuration
public class SeparateChatAssistantConfig {
    //注入持久化对象
    @Autowired
    private MongoChatMemoryStore mongoChatMemoryStore;

    @Bean
    ChatMemoryProvider chatMemoryProvider() {
        return memoryId -> MessageWindowChatMemory.builder()
        .id(memoryId)
        .maxMessages(10)
        .chatMemoryStore(mongoChatMemoryStore)//配置持久化对象
        .build();
    }
}
相关推荐
Dcs几秒前
常见 GC 垃圾收集器对比分析
java
Jamence2 分钟前
多模态大语言模型arxiv论文略读(110)
论文阅读·人工智能·语言模型·自然语言处理·论文笔记
程序员岳焱3 分钟前
Java高级反射实战:15个场景化编程技巧与底层原理解析
java·后端·编程语言
程序员小假4 分钟前
说一说 Netty 中的心跳机制
java·后端
真实的菜11 分钟前
消息队列处理模式:流式与批处理的艺术
java
袁庭新18 分钟前
使用扣子+飞书+DeepSeek搭建批量提取公众号文章内容并改写的智能体
人工智能·aigc·coze
盖世英雄酱5813626 分钟前
Java 内存管理技巧(新手必看集合篇)
java
码农小灰28 分钟前
Java 8 Stream API 入门到实践详解
java·java案例
黑心萝卜三条杠32 分钟前
解码微生物适应性的关键:基因组序列与栖息地预测的深度关联
人工智能
步、步、为营34 分钟前
.NET 事件模式举例介绍
java·开发语言·.net