Spring AI 学习指南(四)ChatMemory内存记忆实战|官方标准架构实现多轮对话
大模型是无状态的。每一次HTTP请求都是独立会话,模型不会主动保存任何历史对话。比如我们先问“你是挂号助手”,再问“我刚刚说了什么”,AI会完全无法应答,这也是原生LLM的“健忘”特性。想要实现类似ChatGPT的连续多轮对话,必须手动维护对话上下文。Spring AI 提供了整套ChatMemory对话记忆体系,彻底解决无状态痛点,让AI拥有上下文记忆能力。本篇作为记忆系列第一篇,我们先从最简单
统一环境:IDEA2026.1.1、JDK21、SpringBoot3.5.14、SpringAI1.1.6、智谱glm-4-flash
前置阅读:已掌握 ChatModel 底层原理、ChatClient 链式写法、三大消息体系
一、前言:为什么AI需要记忆?
在前三期的实战中,我们实现了AI基础问答、角色对话、流式输出等功能,但所有接口都存在一个核心问题:大模型是无状态的。
每一次HTTP请求都是独立会话,模型不会主动保存任何历史对话。比如我们先问“你是挂号助手”,再问“我刚刚说了什么”,AI会完全无法应答,这也是原生LLM的“健忘”特性。
想要实现类似ChatGPT的连续多轮对话,必须手动维护对话上下文。Spring AI 提供了整套ChatMemory对话记忆体系,彻底解决无状态痛点,让AI拥有上下文记忆能力。
本篇作为记忆系列第一篇,我们先从最简单、零依赖的内存记忆入手,吃透 Spring AI 官方标准架构,为后续 JDBC 数据库持久化、Redis 分布式高性能记忆打好基础。
二、核心概念:彻底分清 Memory 与 History
学习记忆功能前,必须厘清官方明确区分的两个核心概念,避免后续开发踩坑。
2.1 Chat Memory(对话记忆)
专门供给大模型推理使用的上下文消息,是裁剪后的窗口化消息,只保留近期有效对话,避免上下文无限膨胀,控制Token消耗和响应速度。
2.2 Chat History(对话历史)
完整的、未经裁剪的全量对话记录,主要用于业务归档、日志审计、数据复盘,不建议全部传给大模型。
核心避坑:不要把完整对话历史全部传入模型,会导致Token成本飙升、响应延迟增高、历史冗余污染当前提问,降低回答质量。
三、Spring AI 记忆架构(核心重点)
Spring AI 1.1.x 采用策略与存储解耦的分层架构,扩展性极强,更换存储方式无需改动核心业务逻辑。
3.1 两层核心架构
-
ChatMemory(记忆策略层):负责管理上下文规则,控制消息窗口大小、裁剪过期消息、维护对话边界,不负责数据存储。核心实现:
MessageWindowChatMemory(滑动窗口记忆,官方默认) -
ChatMemoryRepository(存储层):只负责消息的增删改查,纯粹做数据持久化,不参与记忆规则处理。核心实现:内存、JDBC、Redis等
3.2 核心接口职责
ChatMemory 核心能力:新增消息、获取会话上下文、清空会话记忆
ChatMemoryRepository 核心能力:存取消息、查询会话、删除会话数据
3.3 Advisor 自动装配机制
Spring AI 通过 MessageChatMemoryAdvisor 组件,将记忆能力自动植入对话流程:
-
请求前:根据会话ID读取历史消息,拼接进Prompt
-
响应后:自动保存本轮用户提问、AI回复到记忆存储中
全程无需手动拼接消息、无需手动存历史,全自动实现多轮对话。
四、内存存储方案详解(In-Memory)
内存存储是 Spring AI 默认的记忆方案,底层基于 InMemoryChatMemoryRepository 实现,依靠 ConcurrentHashMap 存储会话数据,Key为会话ID,Value为消息列表。
4.1 适用场景
-
本地开发、功能测试、学习Demo
-
单机临时对话场景
4.2 优缺点
优点:零依赖、零配置、开箱即用、开发效率高
致命缺点:服务重启记忆全部丢失、不支持集群多实例共享、生产环境禁止使用
五、实战:官方标准内存记忆多轮对话
我们基于 MessageWindowChatMemory + 内存Repository + Advisor 官方标准架构,实现带窗口裁剪、多会话隔离的多轮对话。
5.1 编写记忆配置类
统一配置记忆窗口大小、内存存储、自动顾问组件,全局生效
package demo.ai.conf;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatMemoryConfig {
/**
* 1. 注册内存存储仓库(默认存储方案)
*/
@Bean
public InMemoryChatMemoryRepository chatMemoryRepository() {
return new InMemoryChatMemoryRepository();
}
/**
* 2. 注册滑动窗口记忆策略
* maxMessages:最大保留消息条数,超出自动裁剪旧消息,保留系统消息
*/
@Bean
public MessageWindowChatMemory chatMemory(InMemoryChatMemoryRepository repository) {
return MessageWindowChatMemory.builder()
.chatMemoryRepository(repository)
.maxMessages(10) //最多保留10条对话消息
.build();
}
/**
* 3. 构建自带记忆能力的ChatClient
* 自动装配记忆顾问,实现上下文自动拼接、自动存储
*/
@Bean
public ChatClient chatClient(ChatClient.Builder builder, MessageWindowChatMemory chatMemory) {
return builder
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
}
}
由于ChatMemoryConfig构建了ChatClient,那么上次教程在ChatClientConfiguration构建的ChatClient需要注释掉,否则启动会报错
package demo.ai.conf;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@Configuration
public class ChatClientConfiguration {
@Bean
public ChatClient chatClient(ChatClient.Builder chatClientBuilder) {
return chatClientBuilder.build();
}
}
5.2 编写记忆对话控制器
package demo.ai.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
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;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/memory")
public class ChatMemoryController {
@Resource
private ChatClient chatClient;
@Resource
private ChatMemory chatMemory;
/**
* 带内存记忆的普通多轮对话
* @param sessionId 会话ID,实现多用户隔离
* @param msg 用户提问
* @return AI连贯回复
*/
@GetMapping("/chat")
public String memoryChat(@RequestParam String sessionId,
@RequestParam String msg) {
return chatClient.prompt()
// 传入会话ID,隔离不同用户对话
.advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, sessionId))
.system("你是专业的医院挂号咨询助手,回答简洁、易懂、专业")
.user(msg)
.call()
.content();
}
/**
* 带内存记忆的流式多轮对话
*/
@GetMapping("/stream")
public Flux<String> memoryStreamChat(@RequestParam String sessionId,
@RequestParam String msg) {
return chatClient.prompt()
.advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, sessionId))
.system("你是专业的医院挂号咨询助手,分段清晰、简洁回答问题")
.user(msg)
.stream()
.content();
}
/**
* 清空指定会话记忆
*/
@GetMapping("/clear")
public String clearMemory(@RequestParam String sessionId) {
chatMemory.clear(sessionId);
return "会话【" + sessionId + "】记忆已清空";
}
}
pom.xml、application.yml 与上次教程一样,不再列出。
六、核心代码解析
6.1 滑动窗口记忆
我们设置 maxMessages(10),代表单个会话最多保留10条对话消息,超出后自动删除最旧的用户/AI消息,永久保留系统角色消息,既保证上下文连贯,又避免消息无限堆积。
6.2 会话隔离机制
通过 CONVERSATION_ID 参数区分不同用户、不同对话窗口:
-
相同 sessionId:复用历史对话,上下文连贯
-
不同 sessionId:全新空白对话,完全隔离不串台
6.3 手动清空记忆
官方提供 clear() 方法,可手动清空指定会话的所有历史记录,适配“重置对话”业务场景。
七、接口功能测试
启动项目,按顺序测试多轮对话,验证记忆生效
第一次提问:http://localhost:8080/memory/chat?sessionId=user001&msg=我今天想挂骨科的号
第二次提问(依赖上下文):http://localhost:8080/memory/chat?sessionId=user001&msg=我刚刚想挂什么科室的号?
测试结果:AI精准记住上一轮对话内容,上下文记忆完全生效。
切换会话测试:使用 sessionId=user002 提问,AI无任何历史记忆,实现多用户隔离。
清空记忆测试:访问 http://localhost:8080/memory/clear?sessionId=user001,再次提问历史相关问题,AI记忆清空。
八、内存记忆优缺点与适用场景
8.1 优势
-
架构标准,完全遵循 Spring AI 1.1.x 官方设计
-
零中间件依赖,开箱即用,开发测试成本极低
-
自带消息窗口裁剪,避免上下文无限膨胀
-
支持多会话隔离,适配多用户对话场景
8.2 缺陷
-
基于 JVM 内存存储,项目重启记忆全部丢失
-
单机存储,集群部署无法共享对话数据
-
长期运行会存在内存堆积风险
九、本期踩坑总结
-
坑1:记忆不生效:未配置 MessageChatMemoryAdvisor,记忆无法自动注入对话流程
-
坑2:对话串台:未传递 sessionId,所有会话共用同一记忆
-
坑3:手动new创建Memory:MessageWindowChatMemory 必须使用 Builder 构建,构造私有
-
坑4:上下文无限膨胀:未设置 maxMessages,消息持续堆积,Token消耗越来越高
十、本篇学习总结
本篇彻底摒弃旧的写法,掌握了 Spring AI 官方标准记忆架构,核心收获:
-
厘清 ChatMemory 与 ChatHistory 的核心区别,规避行业通用误区
-
吃透 分层架构:记忆策略层 + 存储层 + 自动Advisor
-
掌握 MessageWindowChatMemory 滑动窗口裁剪机制
-
实现内存级多轮对话、流式记忆对话、会话隔离、清空记忆功能
-
明确内存记忆的优缺点,区分测试与生产环境使用边界
十一、结语
真正的AI对话能力,始于记忆。Spring AI 分层解耦的记忆架构,让我们可以按需切换存储方案,从简单内存到数据库、Redis高性能集群,无缝迭代升级。
打好本篇官方架构基础,后续的持久化、分布式记忆学习将会事半功倍!
更多推荐




所有评论(0)