02.使用H2持久化对话历史

一灰灰blogSpringAISpringSpringAI约 1124 字大约 4 分钟

02.使用H2持久化对话历史

上面一篇文章介绍了 SpringAI官方提供的 jdbc start来实现持久化对话历史 使用MySql持久化对话历史,官方实现的几个数据库已经很有代表性了,接下来我们将看一下,如果沿用官方的思路,来为h2添加持久化对话历史功能。

一、H2持久化对话历史

1. 创建项目

创建一个SpringAI项目,基本流程同 创建一个SpringAI-Demo工程

2. 添加依赖

在pom.xml中添加关键依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-zhipuai</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

3. 配置数据库连接

在配置文件 application.yml 文件中,指定SpringAI配置 + 数据库连接信息

spring:
  datasource:
    # 本地开发环境,使用h2数据库,减少外部依赖项
    url: jdbc:h2:file:${user.dir}/advance-projects/A02-memory-jdbc-h2/datas/test-db;DB_CLOSE_DELAY=-1
    driver-class-name: org.h2.Driver
    username: sa
    password:
  h2:
    console:
      enabled: true
  ai:
    chat:
      memory:
        repository:
          jdbc:
            # 因为我们使用的是 h2:file 方式,因此这里还是选择 always 始终创建数据库,不然不会自动创建表
            # 如果我们使用的是 h2:mem 模式,则这里选择 embedded,SpringBoot会自行执行下面的 schema
            initialize-schema: always
            schema: classpath:schema-h2.sql
            platform: h2
    zhipuai:
      # api-key 使用你自己申请的进行替换;如果为了安全考虑,可以通过启动参数进行设置
      api-key: ${zhipuai-api-key}
      chat: # 聊天模型
        options:
          model: GLM-4-Flash

# 修改日志级别
logging:
  level:
    org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor: debug

说明,虽然我们这里使用的是 H2,但是 spring.ai.chat.memory.repository.jdbc.initialize-schema 配置项,还是建议选择 always,因为上面配置的是使用文件来存储db;如果使用内存 jdbc:h2:mem 的方式,则这里可以选择 embedded

embeded是否创建表的关键判断逻辑
embeded是否创建表的关键判断逻辑

其次就是我们需要指定 schema 文件,这个文件,就是用来创建数据库表结构,这里我们使用 h2 的默认结构,因此这里我们使用 classpath:schema-h2.sql

CREATE TABLE IF NOT EXISTS SPRING_AI_CHAT_MEMORY
(
    `conversation_id` VARCHAR(36)                                  NOT NULL,
    `content`         TEXT                                         NOT NULL,
    `type`            ENUM ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL') NOT NULL,
    `timestamp`       TIMESTAMP                                    NOT NULL
);

4. 初始化 ChatMemory

因为我们使用的是系统未提供支持的h2,因此无法使用自动注入的ChatMemoryRepository,因为它选择的Dialect是 PostgresChatMemoryRepositoryDialect,无法支持h2的使用场景

我们这里直接使用MysqlChatMemoryRepositoryDialect来作为h2的Dialect(当然也可以自行实现一个Dialect)

@Configuration
public class MemConfig {
    @Bean
    public ChatMemory jdbcChatMemory(JdbcTemplate jdbcTemplate) {
        ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder()
                .jdbcTemplate(jdbcTemplate)
                // 在这里,指定不同数据库对应的Dialect
                .dialect(new MysqlChatMemoryRepositoryDialect())
                .build();

        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(chatMemoryRepository)
                .build();
    }
}

5. ChatClient 配置

然后通过MessageChatMemoryAdvisor来为ChatClient提供聊天历史能力支撑


@RestController
public class ChatController {
    private final ChatClient chatClient;

    public ChatController(ChatModel chatModel, ChatMemory chatMemory) {
        this.chatClient = ChatClient.builder(chatModel)
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build(),
                        new SimpleLoggerAdvisor())
                .build();
    }
}

6. 示例测试

提供一个聊天接口,第一个参数为用户标识,用于区分用户的聊天记录

@RestController
public class ChatController {
    /**
     * 聊天对话
     *
     * @param user
     * @param msg
     * @return
     */
    @GetMapping("/{user}/chat")
    public Object chat(@PathVariable String user, String msg) {
        return chatClient.prompt().user(msg)
                .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, user))
                .call().content();
    }
}

启动成功之后,我们可以在h2-console中看到新增了一个表 SPRING_AI_CHAT_MEMORY

然后进行多轮对话,看看效果,表现和我们预期一致,聊天记录被保存在数据库中

二、小结

本文介绍的是如何借助 spring-ai-starter-model-chat-memory-repository-jdbc 来实现自定义的对话持久化,通过实现h2的Dialect,我们可以轻松实现自定义的持久化逻辑;若希望了解持久化的更多实现细节,可以查看上篇 使用MySql持久化对话历史

这里实现的是基于数据库来进行持久化,那么如果我不是用数据库,比如希望用文件或者redis来实现,又可以怎么做呢?

文中所有涉及到的代码,可以到项目中获取 https://github.com/liuyueyi/spring-ai-demoopen in new window

Loading...