目录
[二、Spring AI 记忆功能概述](#二、Spring AI 记忆功能概述)
[2.1 Spring AI会话记忆介绍](#2.1 Spring AI会话记忆介绍)
[2.2 常用的会话记忆存储方式](#2.2 常用的会话记忆存储方式)
[2.2.1 集成数据库持久存储会话实现步骤](#2.2.1 集成数据库持久存储会话实现步骤)
[3.1 ChatMemory 介绍](#3.1 ChatMemory 介绍)
[3.2 ChatMemory的几种实现](#3.2 ChatMemory的几种实现)
[3.2.1 InMemoryChatMemory](#3.2.1 InMemoryChatMemory)
[3.2.2 MessageWindowChatMemory](#3.2.2 MessageWindowChatMemory)
[3.2.3 MessageChatMemoryAdvisor](#3.2.3 MessageChatMemoryAdvisor)
[3.3 基于mysql实现会话记忆存储思路](#3.3 基于mysql实现会话记忆存储思路)
[4.1 自定义ChatMemory实现会话记忆存储](#4.1 自定义ChatMemory实现会话记忆存储)
[4.1.1 创建一张表](#4.1.1 创建一张表)
[4.1.2 导入核心依赖](#4.1.2 导入核心依赖)
[4.1.3 增加配置信息](#4.1.3 增加配置信息)
[4.1.4 添加实体类](#4.1.4 添加实体类)
[4.1.5 增加mapper接口](#4.1.5 增加mapper接口)
[4.1.6 自定义ChatMemory](#4.1.6 自定义ChatMemory)
[4.1.7 配置 ChatClient](#4.1.7 配置 ChatClient)
[4.1.8 增加测试接口](#4.1.8 增加测试接口)
[4.1.9 效果验证](#4.1.9 效果验证)
[4.2 基于JdbcTemplate实现会话记忆存储](#4.2 基于JdbcTemplate实现会话记忆存储)
[4.2.1 前置准备](#4.2.1 前置准备)
[4.2.2 导入核心依赖](#4.2.2 导入核心依赖)
[4.2.3 添加配置文件](#4.2.3 添加配置文件)
[4.2.4 自定义配置类](#4.2.4 自定义配置类)
[4.2.5 添加测试接口](#4.2.5 添加测试接口)
[4.2.6 效果验证](#4.2.6 效果验证)
一、前言
我们知道,大型语言模型 (LLM) 是无状态的,这就意味着大模型在对话时不会保存之前的交互信息。当我们希望在一次会话中,模型支持多次交互,那么我们该如何实现呢? 在 Spring AI中提供了ChatMemory功能,它允许我们在与LLM的多次交互中存储与检索信息。
二、Spring AI 记忆功能概述
2.1 Spring AI会话记忆介绍
Spring AI 的会话记忆功能是指让智能体(如AI助手、机器人、虚拟角色等)在多次交互中保持上下文或状态,从而提升交互体验和功能性。这种记忆功能使得智能体能够"记住"用户提供的信息,并在后续对话中参考和使用这些信息,从而提供更加个性化和精准的回复。官方文档:Chat Memory :: Spring AI Reference

2.2 常用的会话记忆存储方式
Spring AI通过 ChatMemory 接口来实现会话记忆功能。常用实现方式有下面几种:
-
内存存储:
- 使用 InMemoryChatMemory 来存储对话历史,这种方式适用于临时会话,但不适合长期存储;
-
数据库存储:
- 集成 MySQL 、 Mongo、Redis 或其他数据库来存储对话历史,以实现长期的会话记忆
2.2.1 集成数据库持久存储会话实现步骤
在实际应用中,一般是将会话数据进行持久化存储,通常的实现步骤如下:
-
集成数据库:
-
选择合适的数据存储组件(如MySQL、Mongo、Redis等),并导入相关依赖。
- 例如,使用MySQL存储对话历史需要导入 spring-ai-starter-model-chat-memory-repository-jdbc 依赖和 mysql-connector-j 依赖。
-
-
配置会话记忆:
-
在Spring配置中定义会话存储方式和会话记忆Advisor。
- 例如,使用 InMemoryChatMemory 并通过 MessageChatMemoryAdvisor 配置会话记忆。
-
-
添加会话ID:
- 每次会话时通过前端区分会话ID,确保同一个会话ID对应多次对话的消息列表,从而实现会话隔离。
三、基于MySql实现会话记忆的实现过程
使用Spring AI 基于MySql实现会话的记忆存储有两种实现方式,一种是基于ChatMemory的实现,另一种是基于JdbcTemplate 的方式实现,下面分别介绍。
3.1 ChatMemory 介绍
实现LLM的会话的记忆存储离不开ChatMemory,ChatMemory 是 Spring AI 中定义聊天记忆行为的核心接口,通过源码点进去查看,可以看到这是一个顶级接口
java
public interface ChatMemory {
default void add(String conversationId, Message message) {
this.add(conversationId, List.of(message));
}
void add(String conversationId, List<Message> messages);
List<Message> get(String conversationId, int lastN);
void clear(String conversationId);
}
可以看到,该接口定义了三个核心操作方法:
-
add()
- 添加消息到记忆
-
get()
- 获取对话历史
-
clear()
- 清除对话记忆
3.2 ChatMemory的几种实现
使用Spring AI过程中,细心的同学通过源码可以看到ChatMemory提供了内置的几种实现,下面分别说明。
3.2.1 InMemoryChatMemory
如果没有引入第三方的会话存储组件,ChatMemory 的默认实现类为InMemoryChatMemory,从源码中可以看到该类对ChatMemory 的几个接口方法进行了实现,开发者可以直接使用。

3.2.2 MessageWindowChatMemory
MessageWindowChatMemory将消息的窗口保持在指定的最大大小。当消息数超过最大值时,在保存系统消息时会删除较旧的消息。默认窗口大小为20个消息。

MessageWindowChatMemory 是 ChatMemory 的主要实现类,具有以下特点:
-
维护一个固定大小的消息窗口
-
自动移除旧消息,保留最新消息
-
默认保留20条消息(可配置)
-
特殊处理系统消息(不会被自动移除)
3.2.3 MessageChatMemoryAdvisor
MessageChatMemoryAdvisor 是 Spring AI 中用于处理会话历史记录的核心类。我们可以创建一个自定义的 MemoryAdvisor,并使用它来存储对话数据。MessageWindowChatMemory 是 ChatMemory 的主要实现类,具有以下特点:
-
维护一个固定大小的消息窗口
-
自动移除旧消息,保留最新消息
-
默认保留20条消息(可配置)
-
特殊处理系统消息(不会被自动移除)
官方文档地址:Chat Memory :: Spring AI Reference

3.3 基于mysql实现会话记忆存储思路
从上面关于ChatMemory的介绍中不难发现,实现会话记忆存储的最重要的组件就是ChatMemory,所以其核心思路如下:
- 创建会话存储数据表;
- 自定义操作会话记忆的类,实现ChatMemory接口,重写里面的相关方法;
- 即对会话的增删改操作改为查询数据库;
- 配置ChatClient 和 ChatMemory ,使用自定义的实现了ChatMemory的类;
四、基于mysql实现会话记忆操作过程
下面介绍两种具体的基于mysql的实现详细过程。
4.1 自定义ChatMemory实现会话记忆存储
4.1.1 创建一张表
使用下面的建表sql创建一个表,该表用于后面存储会话信息
sql
CREATE TABLE `ai_chat_memory` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',
`chat_id` varchar(32) NOT NULL COMMENT '会话id',
`type` varchar(10) NOT NULL DEFAULT 'user' COMMENT '消息类型',
`content` text NOT NULL COMMENT '消息内容',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`is_del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记,0-未删除;1-已删除'
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
注意:
- spring-ai默认生成的会话Id为defalut,不是UUID。
这里选择将单条消息作为数据库的一行数据,而不是单次会话,因此chat_id不是唯一的。
bash
CREATE index idx_chat_id ON ai_chat_memory (chat_id);
4.1.2 导入核心依赖
本例使用mysql进行会话存储,使用mybatis-plus作为orm框架,在pom中导入如下依赖
java
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-ai.version>1.0.0-M6</spring-ai.version>
<spring-ai-alibaba.version>1.0.0-M6.1</spring-ai-alibaba.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-webflux-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.10.1</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version> <!-- 使用适合你的MySQL驱动版本 -->
</dependency>
<!--<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
<version>1.0.0</version>
</dependency>-->
</dependencies>
<repositories>
<repository>
<name>Central Portal Snapshots</name>
<id>central-portal-snapshots</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
4.1.3 增加配置信息
在工程的配置文件中增加如下配置信息
java
spring:
ai:
dashscope:
api-key: 你的百炼平台的apikey
chat:
options:
model: qwen-max
chat:
client:
enabled: false
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://IP:3306/test
username: root
password: 123456
# data:
# redis:
# host: localhost
# port: 6379
# mybatis-plus配置
mybatis-plus:
type-aliases-package: com.congge.domain
configuration:
# 下划线转驼峰
map-underscore-to-camel-case: true
# 全局配置
global-config:
db-config:
# 数据库id配置
id-type: auto
logic-delete-field: is_del # 全局逻辑删除字段名
logic-delete-value: 1 # 逻辑已删除值。可选,默认值为 1
logic-not-delete-value: 0 # 逻辑未删除值。可选,默认值为 0
mapper-locations: classpath:/mapper/**.xml
4.1.4 添加实体类
实体类与数据表映射
java
package com.congge.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName("ai_chat_memory")
public class AiChatMemory {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String chatId;
private String type;
private String content;
private Date createTime;
private Date updateTime;
private Integer isDel;
}
4.1.5 增加mapper接口
java
package com.congge.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.congge.domain.AiChatMemory;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AiChatMemoryMapper extends BaseMapper<AiChatMemory> {
}
4.1.6 自定义ChatMemory
增加一个自定义类,实现ChatMemory,并重写里面的方法
java
package com.congge.config.mysql;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.congge.domain.AiChatMemory;
import com.congge.mapper.AiChatMemoryMapper;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 基于MySQL ChatMemory实现
*/
@Component
public class InMySqlChatMemory implements ChatMemory {
@Resource
private AiChatMemoryMapper aiChatMemoryMapper;
@Override
public void add(String conversationId, List<Message> messages) {
List<AiChatMemory> aiChatMemorieList = new ArrayList<>();
messages.forEach(message -> {
AiChatMemory aiChatMemory = new AiChatMemory();
aiChatMemory.setChatId(conversationId);
aiChatMemory.setType(message.getMessageType().getValue());
aiChatMemory.setContent(message.getText());
aiChatMemorieList.add(aiChatMemory);
});
aiChatMemoryMapper.insertOrUpdate(aiChatMemorieList);
}
@Override
public List<Message> get(String conversationId, int lastN) {
if (lastN >0){
List<AiChatMemory> aiChatMemoryList = aiChatMemoryMapper.selectList(new QueryWrapper<AiChatMemory>()
.eq("chat_id", conversationId)
.orderByDesc("create_time")
.last("limit " + lastN));
if (CollectionUtils.isEmpty(aiChatMemoryList)){
return List.of();
}
return aiChatMemoryList.stream()
.map(aiChatMemory -> {
String type = aiChatMemory.getType();
String content = aiChatMemory.getContent();
Message message;
return switch (type) {
case "system" -> message = new SystemMessage(content);
case "user" -> message = new UserMessage(content);
case "assistant" -> message = new AssistantMessage(content);
default -> throw new IllegalArgumentException("Unknown message type: " + type);
};
})
.toList();
}
return List.of();
}
@Override
public void clear(String conversationId) {
aiChatMemoryMapper.delete(new QueryWrapper<AiChatMemory>()
.eq(conversationId!=null,"chat_id",conversationId));
}
}
4.1.7 配置 ChatClient
增加一个配置类,将ChatClient作为全局bean配置进去
java
package com.congge.config.mysql;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import jakarta.annotation.Resource;
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.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MysqlChatClientConfig {
@Value("${spring.ai.dashscope.api-key}")
public String apiKey;
@Resource
ChatMemory InMySqlChatMemory;
@Bean
public ChatClient qwenPlusInMemoryChatClient(){
if (apiKey == null)
throw new RuntimeException("apiKey is null");
return ChatClient.builder(new DashScopeChatModel(new DashScopeApi(apiKey),
DashScopeChatOptions.builder().withModel("qwen-max").build()
))
//.defaultSystem(LOVE_PROMPT)
.defaultAdvisors(
//自定义持久化记忆advisor
new MessageChatMemoryAdvisor(InMySqlChatMemory)
)
.build();
}
}
4.1.8 增加测试接口
如下,增加两个测试接口,用于观察效果
java
package com.congge.web;
import lombok.extern.slf4j.Slf4j;
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.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/memory/store")
@RestController
@Slf4j
public class MySqlChatStoreController {
@Autowired
private ChatClient chatClient;
@Autowired
private ChatMemory chatMemory;
//localhost:8082/memory/store/chat?userId=1&inputMsg=我叫小王
//localhost:8082/memory/store/chat?userId=1&inputMsg=你知道我是谁吗
@GetMapping(value = "/chat")
public String chat(@RequestParam String userId, @RequestParam String inputMsg) {
String response = chatClient.prompt()
.user(inputMsg)
.advisors(new MessageChatMemoryAdvisor(chatMemory, userId, 10))
.call()
.content();
return response;
}
//localhost:8082/memory/store/chat/v2?message=你是谁呢
@GetMapping("/chat/v2")
public String simpleChat(String message) {
return chatClient.prompt()
.user(message)
.call().content();
}
}
4.1.9 效果验证
启动工程后,分别做下面的测试。
1)第一次调用

2)第二次调用

通过上述的2次调用可以看到,通过上面的方式也能够实现与大模型对话的上下文记忆功能,此时查看数据库,可以看到会话数据存储到了数据表中,由于上面代码中没有设置系统角色,这里显示的是deafult

4.2 基于JdbcTemplate实现会话记忆存储
这种实现方式相对来说要简单一些,不过对Spring AI的版本要求较高,这个在实际整合应用中需要注意,下面看完整的操作过程。
4.2.1 前置准备
去硅基流动网站注获取apikey 硅基流动用户系统,统一登录 SSO

去spring ai官网获取open ai依赖 ,此种实现方式需要依赖最新的版本:Upgrade Notes :: Spring AI Reference

mysql数据库创建一张数据表,用于保存会话信息
java
CREATE TABLE `spring_ai_chat_memory` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
`conversation_id` varchar(255) DEFAULT NULL COMMENT '会话ID',
`content` varchar(10000) DEFAULT NULL COMMENT '内容',
`type` varchar(255) DEFAULT NULL COMMENT '类型',
`timestamp` datetime DEFAULT NULL COMMENT '时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
4.2.2 导入核心依赖
在pom文件中导入如下核心依赖
java
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--<spring-ai.version>1.0.0-M6</spring-ai.version>-->
<spring-ai.version>1.0.0</spring-ai.version>
<spring-ai-alibaba.version>1.0.0-M6.1</spring-ai-alibaba.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.10.1</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version> <!-- 使用适合你的MySQL驱动版本 -->
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<name>Central Portal Snapshots</name>
<id>central-portal-snapshots</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
4.2.3 添加配置文件
在工程的配置文件中添加下面的配置信息
java
server:
port: 8083
spring:
ai:
openai:
api-key: 你的硅基流动apikey
base-url: https://api.siliconflow.cn
chat:
options:
model: deepseek-ai/DeepSeek-R1
chat:
memory:
repository:
jdbc:
initialize-schema: never
#platform: mariadb
#schema: classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-mariadb.sql
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://你的数据库IP:3306/ry?useUnicode=true&characterEncoding=utf8&autoReconnectForPools=true&useSSL=false
username: 用户名
password: 密码
logging:
level:
# 用于支持llm模型输入前和输入后的日志打印
org.springframework.ai.chat.client.advisor: debug
# mybatis-plus配置
#mybatis-plus:
# type-aliases-package: com.congge.domain
# configuration:
# # 下划线转驼峰
# map-underscore-to-camel-case: true
# # 全局配置
# global-config:
# db-config:
# # 数据库id配置
# id-type: auto
# logic-delete-field: is_del # 全局逻辑删除字段名
# logic-delete-value: 1 # 逻辑已删除值。可选,默认值为 1
# logic-not-delete-value: 0 # 逻辑未删除值。可选,默认值为 0
# mapper-locations: classpath:/mapper/**.xml
4.2.4 自定义配置类
自定义ChatClient和ChatMemory全局bean,参考下面的代码
java
package com.congge.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository;
import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepositoryDialect;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Configuration
public class JdbcChatConfig {
@Bean
public JdbcChatMemoryRepository jdbcChatMemoryRepository(JdbcTemplate jdbcTemplate, DataSource dataSource) {
JdbcChatMemoryRepositoryDialect dialect = JdbcChatMemoryRepositoryDialect.from(dataSource);
return JdbcChatMemoryRepository.builder().jdbcTemplate(jdbcTemplate).dialect(dialect).build();
}
@Bean
public ChatMemory chatMemory(ChatMemoryRepository jdbcChatMemoryRepository){
return MessageWindowChatMemory.builder()
.chatMemoryRepository(jdbcChatMemoryRepository)
// 每个会话最多记录20条信息,可以根据实际情况设置
.maxMessages(20)
.build();
}
@Bean
public ChatClient chatClient(OpenAiChatModel openAiChatModel, ChatMemory chatMemory){
// 配置模型 (因为我们使用的是 ollama, 所以此处写的是 OllamaChatModel)
return ChatClient.builder(openAiChatModel)
// 默认系统提示词
//.defaultSystem("你是一个擅长进行情绪管理的AI助手。")
// 添加模型输入前和输入后日志打印
.defaultAdvisors(new SimpleLoggerAdvisor(),
// 配置 chat memory advisor
MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
}
}
4.2.5 添加测试接口
添加一个自定义接口,方便测试看效果,参考下面的代码
java
package com.congge.web;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/memory")
public class ChatController {
@Autowired
private ChatClient chatClient;
//localhost:8083/memory/chat?userId=1&inputMsg=我叫小王
//localhost:8083/memory/chat?userId=1&inputMsg=你知道我是谁吗
@GetMapping(value = "/chat")
public String chat(@RequestParam String userId, @RequestParam String inputMsg) {
String response = chatClient.prompt()
.user(inputMsg)
.advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID, userId))
//.advisors(new MessageChatMemoryAdvisor(chatMemory, userId, 10))
.call()
.content();
return response;
}
}
4.2.6 效果验证
下面分别调用一下接口进行测试。
1)第一次调用
调用接口,向大模型发起提问

2)第二次调用
调用接口,向大模型发起提问,测试会话记忆是否生效

通过上面的两次接口测试,可以看到,会话记忆能够实现,同时检查数据表,对话的数据进行了持久化存储

3)第三次调用
将服务停掉,然后重启服务,再次调用接口2,可以看到,由于历史会话进行了存储,所以当发起与历史会话相关的提问时,大模型仍然保持着会话记忆功能。

五、写在文末
本文通过较大的篇幅详细介绍了基于mysql实现会话记忆的功能,希望对看到的同学有用,本篇到此结束,感谢观看。