Spring AI 聊天记忆功能实战(一):从接口设计到生产实践
在构建AI对话应用时,聊天记忆管理及存储是实现连贯上下文交互的关键组件。而大模型(LLM)本质上是无状态的,这意味着它们不会保留历史交互信息。当需要跨多轮交互保持上下文时,这一特性会带来局限。为此,Spring AI 提供了聊天记忆功能,支持在 LLM 交互过程中存储和检索上下文数据。
入门理解
Spring AI 框架通过模块化设计提供了灵活的聊天记忆解决方案,其核心在于ChatMemoryRepository
与ChatMemory
的协同工作机制。
ChatMemoryRepository
接口提供了各种存储方式实现的统一抽象,增加了聊天记忆功能的灵活性及扩展性,目前 Spring AI(1.0.0 版本)框架提供了基于 内存(默认)、JDBC、Cassandra、Neo4j 四种存储方式的实现。
java
public interface ChatMemoryRepository {
// 获取所有会话ID
List<String> findConversationIds();
// 获取指定会话ID的聊天消息
List<Message> findByConversationId(String conversationId);
// 存储整个会话ID的历史消息(替换式更新)
void saveAll(String conversationId, List<Message> messages);
// 清理指定会话ID中的聊天消息
void deleteByConversationId(String conversationId);
}
ChatMemory
抽象层支持实现多种记忆类型以满足不同场景需求。消息的底层存储由 ChatMemoryRepository
处理,其唯一职责是存储和检索消息。ChatMemory
实现类可自主决定消息保留策略 ------ 例如保留最近 N 条消息、按时间周期保留或基于 Token 总量限制保留。
java
public interface ChatMemory {
// 从聊天记忆的上下文检索会话ID
String CONVERSATION_ID = "chat_memory_conversation_id";
// 将聊天消息保存到指定会话ID的存储中
void add(String conversationId, List<Message> messages);
// 获取指定会话ID中的聊天消息
List<Message> get(String conversationId);
// 清理指定会话ID中的聊天消息
void clear(String conversationId);
}
快速使用
Spring AI 自动配置 ChatMemory
Bean 供直接使用。默认采用内存存储(InMemoryChatMemoryRepository
)及 MessageWindowChatMemory
实现管理会话历史。若已配置其他 Repository(如 Cassandra / JDBC / Neo4j ),则自动切换至对应实现。
记忆类型:MessageWindowChatMemory
维护固定容量的消息窗口(默认 20 条)。当消息超限时,自动移除较早的对话消息(始终保留系统消息)。
java
// 自动注入
@Autowired
ChatMemory chatMemory;
// 手动创建
MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
.maxMessages(10)
.build();
记忆存储:InMemoryChatMemoryRepository
内存存储为默认的聊天记忆存储实现。同样地,Spring AI 提供了统一的自动配置,可直接自动注入使用。
java
// 自动注入
@Autowired
ChatMemoryRepository chatMemoryRepository;
// 手动创建
ChatMemoryRepository repository = new InMemoryChatMemoryRepository();
自动配置在默认情况下,Spring AI 注入了如下 Bean 对象:
java
@Bean
ChatMemoryRepository chatMemoryRepository() {
return new InMemoryChatMemoryRepository();
}
@Bean
ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {
return MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).build();
}
原理实现
聊天记忆存储的实现主要依靠 ChatMemoryRepository
接口 及 ChatMemory
接口,它们的默认实现类分别为 InMemoryChatMemoryRepository
及 MessageWindowChatMemory
。
InMemoryChatMemoryRepository
实现类:
java
public final class InMemoryChatMemoryRepository implements ChatMemoryRepository {
Map<String, List<Message>> chatMemoryStore = new ConcurrentHashMap<>();
// 方法实现...
}
InMemoryChatMemoryRepository 使用并发安全的 ConcurrentHashMap 实现聊天记录的增删改操作,存储实现依赖 Map 的 get、put、remove 操作。需要注意的是,这里 saveAll(写入记录)方法实现是替换旧数据的更新逻辑,若对应到外部存储的写入方式应该先删除后插入数据,而限制聊天对话历史长度的逻辑在 MessageWindowChatMemory 类实现。
MessageWindowChatMemory
实现类:
java
public final class MessageWindowChatMemory implements ChatMemory {
private final ChatMemoryRepository chatMemoryRepository;
private final int maxMessages;
// 方法实现...
private List<Message> process(List<Message> memoryMessages, List<Message> newMessages) {
// 根据最大消息数处理消息窗口
}
}
处理消息窗口容量的主要逻辑为:
- 识别新增的
SystemMessage
,当有新系统消息时,清除所有旧系统消息、所有的新SystemMessage
不受容量限制; - 保留非系统消息历史+新增消息,按添加顺序移除最早的非系统消息,确保 最终消息数 ==
maxMessages
、返回处理后的新消息;
消息窗口的聊天记忆管理与数据存储交互的 UML 类图 如下:
实战案例
接下来我们使用MessageWindowChatMemory
+JdbcChatMemoryRepository
的方式实现一个AI聊天助手的功能。
JdbcChatMemoryRepository
是内置的 JDBC 实现,支持多种关系型数据库,适用于需要持久化存储聊天记忆的场景。JDBC 实现是基于 spring-jdbc 模块,我们可通过 JdbcTemplate
来配置任一数据源。
1、导入模块
首先,在 spring-boot 项目中添加以下依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
2、配置参数
新建 application.yml,添加配置 spring.ai
和JdbcTemplate
相关参数:
yaml
spring:
application:
name: AI Assistant
ai:
openai:
api-key: ${OPENAI_API_KEY:NONE}
base-url: ${OPENAI_BASE_URL:NONE}
chat:
options:
model: DeepSeek-V3
completions-path: /v1/chat/completions
chat:
memory:
repository:
jdbc:
initialize-schema: always # Always initialize
datasource:
url: jdbc:postgresql://localhost:5432/test
username: root
password: 123456
driver-class-name: org.postgresql.Driver
3、创建 Bean 实例
Spring AI 为 JdbcChatMemoryRepository
提供了自动配置,可直接在应用中使用 (默认使用 hsqldb 嵌入式数据库),也可手动创建 Bean 实例。
java
@Configuration
public class GeneralChatClientConfig {
private final JdbcChatMemoryRepository jdbcChatMemoryRepository;
public GeneralChatClientConfig(JdbcChatMemoryRepository jdbcChatMemoryRepository) {
this.jdbcChatMemoryRepository = jdbcChatMemoryRepository;
}
@Bean(name = "messageWindowChatMemoryWithJdbc")
public MessageWindowChatMemory messageWindowChatMemoryWithJdbc() {
int maxMessages = 20;
return MessageWindowChatMemory.builder()
.chatMemoryRepository(jdbcChatMemoryRepository) // default: new InMemoryChatMemoryRepository()
.maxMessages(maxMessages)
.build();
}
}
目前 Spring AI 支持的数据库与方言抽象层:
- PostgreSQL
- MySQL / MariaDB
- SQL Server
- HSQLDB
使用 JdbcChatMemoryRepositoryDialect.from(DataSource)
时可基于 JDBC URL 自动识别正确方言。通过实现 JdbcChatMemoryRepositoryDialect
接口可扩展其他数据库方言支持。
4、聊天记忆客户端
创建使用 ChatClient
API 时,可通过注入 ChatMemory
实现来维护跨多轮交互的会话上下文。
Spring AI 提供多种内置 Advisor,用于按需配置 ChatClient
的记忆行为。
MessageChatMemoryAdvisor
:通过指定ChatMemory
实现管理会话记忆。每次交互时从记忆库检索历史消息,并将其作为消息集合注入提示词。PromptChatMemoryAdvisor
:基于指定ChatMemory
实现管理会话记忆。每次交互时从记忆库检索历史对话,并以纯文本形式追加至系统(system)提示词。VectorStoreChatMemoryAdvisor
:通过指定VectorStore
实现管理会话记忆。每次交互时从向量存储检索历史对话,并以纯文本形式追加至系统(system)消息。
例如,若需结合 MessageWindowChatMemory
与 PromptChatMemoryAdvisor
,可按如下方式配置:
java
@Bean(name = "deepseekV3ClientWithJdbc")
public ChatClient deepseekV3ClientWithJdbc(
@Value("${spring.ai.openai.base-url}") String baseUrl,
@Value("${spring.ai.openai.chat.options.model}") String modelName,
@Value("${spring.ai.openai.api-key}") String apiKey,
@Qualifier("messageWindowChatMemoryWithJdbc") MessageWindowChatMemory messageWindowChatMemoryWithJdbc) {
OpenAiApi build = OpenAiApi.builder().apiKey(apiKey).baseUrl(baseUrl).build();
OpenAiChatModel openAiChatModel =
OpenAiChatModel.builder()
.openAiApi(build)
.defaultOptions(OpenAiChatOptions.builder().model(modelName).build())
.build();
return ChatClient.builder(openAiChatModel)
.defaultAdvisors(PromptChatMemoryAdvisor.builder(messageWindowChatMemoryWithJdbc).build())
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
}
调用 ChatClient
时,ChatMemoryAdvisor
将自动管理记忆存储。系统会根据指定的会话 ID 从记忆库检索历史对话。
我们新建一个 Controller ,注入配置好的 ChatClient,定义一个api实现大模型的 chat 调用,代码如下:
java
@RestController
@RequestMapping("/ai/v3/chat/")
@Slf4j
public class GeneralChatController {
private final ChatClient jdbcChatClient;
public GeneralChatController(@Qualifier("deepseekV3ClientWithJdbc") ChatClient jdbcChatClient) {
this.jdbcChatClient = jdbcChatClient;
}
@PostMapping(value = "/t1", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
@ResponseBody
public Object chatWithJdbc(@RequestBody String body) {
JSONObject entries = JSONUtil.parseObj(body);
String text = entries.getStr("text");
Boolean stream = entries.getBool("stream", false);
String conversationId = entries.getStr("conversationId");
log.info("开始对话聊天,会话ID:{}", conversationId);
var request = jdbcChatClient
.prompt()
.system("你是乐观小王,回答问题简练精要。")
.advisors(advisor -> advisor.param(CONVERSATION_ID, conversationId))
.user(text);
try {
log.info("开始生成回答,是否流式输出:{}", stream);
return stream ? request.stream().content() : request.call().content();
} catch (Exception e) {
log.error("对话聊天发生异常,会话ID:{}", conversationId, e);
throw e;
}
}
}
5、测试AI聊天功能
通过上述的简单配置和代码编写,我们已经实现了一个通用的带有记忆功能的AI聊天助手。
接下来让我们测试一下这个聊天助手的使用效果,设置几条 USER 的提问内容,具体内容如下:
http
# Openai Chat API
### 我的名字叫小明,你叫什么名字?
### 我是谁?
### 我们之间的第一句问话是什么?
POST http://localhost:10001/ai/v3/chat/t1
Content-Type: application/json
{
"text": "我的名字叫小明,你叫什么名字?",
"stream": false,
"conversationId": "bnA9f525-l7ae-5c66-ae21-vh53547c96cf"
}
聊天消息记录会被存储到 PostgreSQL 数据库中,http顺序请求后的大模型返回结果 如图所示:

小总结
通过上述测试结果可以清晰看到,基于 Spring AI 搭建的聊天助手凭借聊天记忆存储功能,能够准确关联上下文信息,针对连续提问给出符合对话逻辑的回答。无论是识别用户身份,还是追溯对话起始内容,系统都能有效利用历史消息,实现连贯且智能的交互体验,充分利用聊天记忆存储机制可以更好的维护对话上下文及提高模型回答的准确性。
目前 Spring AI (1.0.0 版本) 官方还没有提供 Redis 的聊天记忆外部存储实现,那么,下一篇文章我们将聚焦于 自定义 Redis 聊天记忆的外部存储实现,通过 自定义一个外部存储方式,自己实现一个聊天记忆存储功能,来进一步提升聊天助手的扩展性与数据持久性,让AI聊天助手在高并发、大规模对话场景中稳定运行。敬请期待接下来的深度技术解析!