Spring AI 系列之四 - 聊天记忆之入门

发布于:2025-07-11 ⋅ 阅读:(24) ⋅ 点赞:(0)

之前做个几个大模型的应用,都是使用Python语言,后来有一个项目使用了Java,并使用了Spring AI框架。随着Spring AI不断地完善,最近它发布了1.0正式版,意味着它已经能很好的作为企业级生产环境的使用。对于Java开发者来说真是一个福音,其功能已经能满足基于大模型开发企业级应用。借着这次机会,给大家分享一下Spring AI框架。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 Spring AI-1.0.0,JDK版本使用的是19
代码参考: https://github.com/forever1986/springai-study

通过上几章基本上入门了Spring AI的使用方法,但是前面的示例还跟用户在使用web聊天的时候有些不一样,这个不一样的点就是聊天记忆。你会发现每次聊天都是没有记忆的,比如第一次提问:给我推荐10部电影;第二次提问:在里面挑出你认为最好的一部。大模型会直接回答你:没有提供任何选项或内容供我选择。这就是没有记忆,而常见的网页版的聊天大模型,基本上都有记忆的。Spring AI提供了简便的聊天记忆框架,让用户只需要简单配置即可实现,下面从一个简单示例入手,在慢慢展开Spring AI的聊天记忆功能。

1 入门示例

代码参考lesson04

1.1 新建子模块

1)在springai-study父项目中,新建lesson04子模块,其pom引入如下:

<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>
</dependencies>

2)在application.properties配置智谱大模型

# 聊天模型
spring.ai.zhipuai.api-key=你的智谱模型的API KEY
spring.ai.zhipuai.chat.options.model=GLM-4-Flash-250414
spring.ai.zhipuai.chat.options.temperature=0.7

3)新建启动类Lesson04Application :

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Lesson04Application {

    public static void main(String[] args) {
        SpringApplication.run(Lesson04Application.class, args);
    }

}

1.2 设置聊天记忆

1)配置controller

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MemoryController {

    private ChatClient chatClient;

    public MemoryController(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory) {
        this.chatClient = chatClientBuilder
                // 通过Advisors设置聊天记忆模式,关于Advisors后续会细讲
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) // 通过不同角色Message方式传递聊天记忆
                .build();
    }

    /**
     * @param message 问题
     * @param conversationId 聊天记忆的id
     */
    @GetMapping("/ai/memory")
    public String memory(@RequestParam(value = "message", required = true) String message
            , @RequestParam(value = "conversationId", required = true) Integer conversationId) {
        return this.chatClient.prompt()
                .user(message)
                .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
                .call()
                .content();
    }

}

说明:配置聊天记录步骤
1)在创建ChatClient时,设置聊天记忆的类型为:MessageChatMemoryAdvisor
2)在call之前,使用advisors将聊天记录的id传入。这样Spring AI会自动将聊天结果存入内存,并再下一次调用时,传入给大模型

1.3 演示结果

1)第一次请求

http://localhost:8080/ai/memory?message=给我推荐10部电影&conversationId=1

在这里插入图片描述
2)第二次请求

http://localhost:8080/ai/memory?message=在里面挑出你认为最好的一部&conversationId=1

在这里插入图片描述

3)第三次请求

http://localhost:8080/ai/memory?message=在里面挑出你认为最好的一部&conversationId=2

在这里插入图片描述

说明:从上图可以看出如果将conversationId设置为2,那么等于开启一个新的对话,因此没有上一次对话的记忆。

在上面创建ChatClient时,如下代码,有2个点需要注意

	.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())

说明:有2个点需要注意
1)有一个MessageChatMemoryAdvisor,这个是记忆的类型,Spring AI 实现不同方式将聊天记录传递给大模型
2)有一个ChatMemory,这是记忆存储类型,Spring AI实现可扩展式存储聊天记忆
接下来会细说这两个点

2 记忆类型

在上面可以看到使用一个MessageChatMemoryAdvisor类,其实现了BaseChatMemoryAdvisor接口,如果深追BaseChatMemoryAdvisor代码会发现,Spring AI对于 BaseChatMemoryAdvisor 接口有2个实现类,分别是 MessageChatMemoryAdvisorPromptChatMemoryAdvisor

  • MessageChatMemoryAdvisor:将用户提出的问题和模型的回答添加到历史记录中,从而形成一个上下文记忆的增强机制。它实现的模式是将之前的对话以角色对话的方式传递给大模型。之前在《[系列之二 - 提示词](https://blog.csdn.net/linwu_2006_2006/article/details/149165549#t2》讲过不同角色给与大模型不同作用的提示。但是需要注意一点是并非所有的AI模型都支持这种上下文记忆的存储和管理方式,因此在使用MessageChatMemoryAdvisor时,确保所使用的模型具备此支持是至关重要的。
  • PromptChatMemoryAdvisor:同样是将用户提出的问题和模型的回答添加到历史记录中,从而形成一个上下文记忆的增强机制。但其实现方式与MessageChatMemoryAdvisor不同,PromptChatMemoryAdvisor并不将上下文记录以角色对话的方式传递给大模型,而是巧妙地将其封装到SystemPrompt提示词中。这样使得无论所使用的模型是否支持角色对话,系统都能够有效地增加上下文历史记忆。

如果你将MemoryController代码中修改不同的BaseChatMemoryAdvisor,可以debug到不同效果

在这里插入图片描述

使用 MessageChatMemoryAdvisor 类型下的效果是,将聊天记录作为不同角色Assistant和User的message传递

在这里插入图片描述

使用 PromptChatMemoryAdvisor 类型下的效果是,将聊天记录作为第一个SystemPrompt的提示词

在这里插入图片描述

3 聊天记忆存储类型

在上述中,只是在MemoryController 的构造方法中写入参数ChatMemory ,Spring AI就自动给代码注入一个 ChatMemory ,这是因为Spring AI默认创建 MessageWindowChatMemory 类,也会为其 ChatMemoryRepository 参数创建一个基于内存存储的 InMemoryChatMemoryRepository 。而 ChatMemoryRepository 就是Spring AI 提供了用于存储聊天记忆的抽象接口。本节将讲述 Spring AI 提供的内置存储库及其使用方法,但如果需要,您也可以实现自己的存储库。

下图为目前为止Spring AI实现的 ChatMemoryRepository 接口的存储实现类:

在这里插入图片描述

  • InMemoryChatMemoryRepository:使用ConcurrentHashMap将消息存储在内存中,每次重启服务,聊天记录会丢失,因此一般用于测试使用
  • JdbcChatMemoryRepository:是使用 JDBC 在关系数据库中存储消息的内置实现。它支持多个开箱即用的数据库,适用于需要持久存储聊天内存的应用程序。目前支持:PostgreSQL、MySQL、MariaDB、SQL Server、HSQLDB等内置dialect方言。如果是其它的关系型数据库,用户可以自定义 dialect 传递给存储库构建器
  • CassandraChatMemoryRepository:使用 Apache Cassandra 存储消息。它适用于需要持久存储聊天内存的应用程序,尤其是可用性、持久性、规模以及利用生存时间 (TTL) 功能时。
  • Neo4jChatMemoryRepository:是一个内置实现,它使用 Neo4j 将聊天消息作为节点和关系存储在属性图数据库中。它适用于希望利用 Neo4j 的图形功能实现聊天内存持久性的应用程序。

3.1 基于jdbc的聊天记忆存储类型

代码参考lesson05子模块

本示例基于MySQL数据库存储聊天记忆信息

3.1.1 前提准备

1)准备一个MySQL数据库,并创建springai的数据库

2)在springai-study父项目下,创建lesson05子模块,其pom引入如下

<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>
    <!-- 引入spring ai的jdbc存储的插件-->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
    </dependency>
    <!-- 引入mysql的驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
    </dependency>
</dependencies>

说明:上面需要引入spring ai的jdbc存储的插件以及MySQL的jdbc驱动

3)创建运行类Lesson05Application:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Lesson05Application {

    public static void main(String[] args) {
        SpringApplication.run(Lesson05Application.class, args);
    }

}

3.1.2 编写基于MySQL存储聊天记忆

1)在resources下,配置application.properties信息

# 聊天模型
spring.ai.zhipuai.api-key=你的智谱模型的API KEY
spring.ai.zhipuai.chat.options.model=GLM-4-Flash-250414
spring.ai.zhipuai.chat.options.temperature=0.7

# 指定数据库连接,不然默认是HSQLDB数据库
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springai
spring.datasource.username=root
spring.datasource.password=root

# 由于默认是没有mysql的初始化语句,这里给spring AI一个mariadb,让其运行schema-mariadb.sql,不然就需要配置下面schema参数
spring.ai.chat.memory.repository.jdbc.platform=mariadb

# 指定创建表语句,只有HSQLDB、mariadb、postgresql和sqlserver是有默认sql语句,不需要指定,其它数据库都需要。如果上面参数不指定,可以自己设置建表语句
#spring.ai.chat.memory.repository.jdbc.schema=classpath:/custom/path/schema-mysql.sql

# 是否初始化建表
spring.ai.chat.memory.repository.jdbc.initialize-schema=always

说明:这里有几个参数需要说明一下:
1)spring.ai.chat.memory.repository.jdbc.schema:这个是配置初始化数据库的建表语句,在Spring AI中提供了默认4种数据库的建表语句
在这里插入图片描述
2)spring.ai.chat.memory.repository.jdbc.platform:指定哪种数据库,默认是能够自动识别的。示例中配置mariadb,只不过是为了让其能够自动获取建表语句。由于mariadb与MySQL的语法基本一样,因此可以配置mariadb,你也可以自己写一个schema-mysql.sql,使用该参数进行指定建表语句
3)spring.ai.chat.memory.repository.jdbc.initialize-schema:启动时,是否执行建表语句。有三种:embeded是内置内存数据库(HSQLDB等支持);always是每次都是监测执行;never是不执行。

2)创建基于JdbcChatMemoryRepository的ChatMemory,使用配置类MemoryConfiguration:

import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MemoryConfiguration {

    @Autowired
    JdbcChatMemoryRepository chatMemoryRepository;

    @Bean
    public ChatMemory chatMemory(){
        ChatMemory chatMemory = MessageWindowChatMemory.builder()
                .chatMemoryRepository(chatMemoryRepository)
                .maxMessages(10)
                .build();
        return chatMemory;
    }
}

3)创建JDBCMemoryController进行演示:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JDBCMemoryController {

    private ChatClient chatClient;

    public JDBCMemoryController(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory) {
        this.chatClient = chatClientBuilder
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) // 通过不同角色Message方式传递聊天记忆
                .build();
    }

    /**
     * @param message 问题
     * @param conversationId 聊天记忆的id
     */
    @GetMapping("/ai/jdbcmemory")
    public String memory(@RequestParam(value = "message", required = true) String message
            , @RequestParam(value = "conversationId", required = true) Integer conversationId) {
        return this.chatClient.prompt()
                .user(message)
                .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
                .call()
                .content();
    }

}

3.1.3 演示结果

1)第一次请求

http://localhost:8080/ai/jdbcmemory?message=给我推荐10部电影&conversationId=1

在这里插入图片描述

在这里插入图片描述

说明:可以看到会将聊天记录存储在MySQL数据库中。

2)第二次请求

http://localhost:8080/ai/jdbcmemory?message=在里面挑出你认为最好的一部&conversationId=1

在这里插入图片描述

在这里插入图片描述

3)这时候可以重启服务器,进行第三次请求

http://localhost:8080/ai/jdbcmemory?message=在里面挑出你认为最差的一部&conversationId=1

在这里插入图片描述

在这里插入图片描述

说明:从上图可以看出,停止服务器之后重启,保持conversationId=1,依然能够使用之前的对话。

结语:本章介绍了Spring AI如何快速的搭建具有聊天记忆的功能,并实现了基于MySQL数据库的聊天记录。在Spring AI自身实现的ChatMemoryRepository中,包括内存、JDBC、Cassandra、Neo4j ,但实际上可存储的还有其它存储类型,比如Redis、mongoDB等等,如果要实现除了Spring AI已经提供的4种类型之外的存储,该如何做呢?下一章揭晓。


网站公告

今日签到

点亮在社区的每一天
去签到