一、简介
大模型是没有记忆的,Spring AI提供了聊天记录的持久化织入器,Spring AI 提供了多种持久化方式,支持内存(默认InMemoryChatMemoryRepository)、Redis、MongoDB、ES、其它数据库等。
二、ChatMemory
所谓记忆就是将历史之前的所有提示出和大模型返回的结果都作为下次的输入。
java
ChatMemory chatMemory = MessageWindowChatMemory.builder().build();
String conversationId = "xs001"; // 当前对话唯一标识
// 第一次对话(将请求和响应添加到chatMemory中)
UserMessage userMessage1 = new UserMessage("我叫张三");
chatMemory.add(conversationId, userMessage1);
ChatResponse response1 = chatModel.call(new Prompt(chatMemory.get(conversationId)));
chatMemory.add(conversationId, response1.getResult().getOutput());
// 第二次对话
UserMessage userMessage2 = new UserMessage("我是谁?");
chatMemory.add(conversationId, userMessage2);
ChatResponse response2 = chatModel.call(new Prompt(chatMemory.get(conversationId)));
chatMemory.add(conversationId, response2.getResult().getOutput());
System.out.println(response2.getResult().getOutput().getText());
InMemoryChatMemoryRepository
默认存到 Map<String, List<Message>> chatMemoryStore = new ConcurrentHashMap<>(); 中,Map的key表示conversationId用于区分用户的sessionId(conversationId如果没有听默认为default),当数据多的时候会出现内存溢出OOM,只适合简单Demo一下。
MessageWindowChatMemory
每个大模型的上下文长度都是有最大限制的,窗口式会话内存,保存对话历史,可以设置最大消息条数(默认20),超过就丢弃最早消息。
RedisChatMemoryRepository
Redis相比Jdbc会更快。
xml
<properties>
<jedis.version>5.2.0</jedis.version>
</properties>
<!-- Spring AI Alibaba Redis聊天记忆starter -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Jedis Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
yaml
spring:
ai:
memory:
redis:
host: 127.0.0.1
port: 6379
password: ""
timeout: 2000
# key前缀,redis里面的key = spring:ai:memory:{sessionId}
key-prefix: spring:ai:memory
java
@Bean
ChatMemory chatMemory(RedisChatMemoryRepository redisChatMemoryRepository) {
return MessageWindowChatMemory.builder()
.maxMessages(10) // 窗口大小,保留最近10条消息
.chatMemoryRepository(redisChatMemoryRepository)
.build();
}
JdbcChatMemoryRepository
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
yaml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/ai_chat?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 你的密码
driver-class-name: com.mysql.cj.jdbc.Driver
默认使用schema‑mysql.sql会创建该表。
sql
CREATE TABLE IF NOT EXISTS SPRING_AI_CHAT_MEMORY (
`conversation_id` VARCHAR(36) NOT NULL,
`content` TEXT NOT NULL,
`type` VARCHAR(10) NOT NULL,
`timestamp` TIMESTAMP NOT NULL,
CONSTRAINT SPRING_AI_CHAT_MEMORY_TYPE_CHECK CHECK (type IN ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL'))
);
CREATE INDEX IF NOT EXISTS SPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDX
ON SPRING_AI_CHAT_MEMORY (conversation_id, `timestamp`);
ElasticsearchChatMemoryRepository
bash
<!-- spring‑ai‑alibaba ES chat memory 官方starter -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-elasticsearch</artifactId>
<version>1.0.0.2</version>
</dependency>
<!-- Spring Data Elasticsearch 底层驱动 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
</dependency>
yaml
spring:
elasticsearch:
uris: http://127.0.0.1:9200
#username: elastic
#password: xxx
ai:
chat:
memory:
repository:
elasticsearch:
index-name: spring-ai-alibaba-chat-memory # ES索引名称,自动创建
java
@Bean
public ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {
return MessageWindowChatMemory.builder()
.maxMessages(10)
.chatMemoryRepository(chatMemoryRepository)
.build();
}
@Bean
public RedisChatMemoryRepository chatMemoryRepository(RedisTemplate<String, Object> redisTemplate) {
return RedisChatMemoryRepository.builder()
.redisTemplate(redisTemplate)
.build();
}
@Bean
ChatMemory chatMemory(JdbcChatMemoryRepository chatMemoryRepository) {
return MessageWindowChatMemory.builder()
.maxMessages(10)
.chatMemoryRepository(chatMemoryRepository)
.build();
}
/**
* 直接注入alibaba官方ES ChatMemoryRepository,自动读取yml配置
*/
@Bean
public ChatMemory chatMemory(ElasticsearchChatMemoryRepository esChatMemoryRepository) {
return MessageWindowChatMemory.builder()
.chatMemoryRepository(esChatMemoryRepository)
.maxMessages(20) //内存窗口上限,ES中完整保存全部历史消息
.build();
}
三、代码
java
@Configuration
public class SpringAiConfig {
@Bean
public ChatClient chatClient(DeepSeekChatModel deepSeekChatModel, ChatMemory chatMemory) {
return ChatClient.builder(deepSeekChatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build()
)
.build();
}
}
java
@RestController
public class SpringAIController {
@Autowired
private ChatClient chatClient;
@GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chat(@RequestParam("message") String message) {
Flux<String> content = chatClient.prompt()
.user(message)
// 消息持久化需要一个user_id
.advasors(a -> a.param(ChatMemory.CONVERSATION_ID, "zhangsan"))
.stream()
.content()
.withConcat(Flux.just("[complete]")); // 自定义一个结束标记,前端解析到就不会再请求,表示本轮会话全部结束
return content;
}
@GetMapping("/history")
public List<Message> getHistory(@RequestParam String sid) {
return chatMemory.get(sid);
}
@GetMapping("/clear")
public void clear(@RequestParam String sid) {
chatMemory.clear(sid);
}
}
先告诉大模型我叫什么。

再问大模型我叫什么

AI多层次记忆架构(模仿人类记忆)
整体分为近期记忆、中期记忆、长期记忆三层,正好对应Spring AI里面不同组件。
1. 近期记忆(Short‑term)
保留上下文窗口最近N轮对话,每轮对话结束立刻存储,对应
ChatMemory
- 实现:
MessageWindowChatMemory,底层存储Redis/MySQL(JdbcChatMemoryRepository / RedisChatMemoryRepository) - 特点:
- 直接放在prompt上下文传给大模型;
- 有窗口上限(maxMessages,例如10条),超过就丢弃最早消息;
- 只能记住最近几轮,老对话直接被裁剪掉。
- 局限:会话轮次一多,早期历史会丢失。
2. 中期记忆(Middle‑term)
RAG向量检索历史对话,解决"近期记忆窗口不够"的痛点
- 流程:每轮对话结束后,异步把本轮对话文本转向量,存入向量数据库。
- 推理阶段:用户提问时,把用户问题向量化,去向量库检索相似的旧对话,把检索出来的历史拼入prompt。
- 特点:
- 不受LLM上下文窗口限制,可以检索很久之前对话;
- 缺点:是相似度召回,不一定能命中真正需要的内容;
- 存储:向量数据库(Milvus、DashScope向量库等)。
对比:近期记忆是全部塞进prompt ;中期记忆是检索挑选一部分塞进prompt。
3. 长期记忆(Long‑term)
提炼固化关键事实、用户偏好,不是原始聊天记录,是高度摘要信息。
不存完整对话,只存结构化要点:比如用户年龄、喜好、习惯、重要事实。
两种实现方案:
方式① 定时批处理
- 定时任务(每日/每周)批量读取该用户全部对话;
- 调用LLM做总结,提取关键信息、用户偏好;
- 写入数据库作为长期记忆;
- 优点:计算集中、成本低,适合大量用户;
- 缺点:不能实时感知用户刚说的新信息,有延迟。
方式② 关键点实时处理(写入触发器)
- 每一轮对话,额外调用一次LLM,识别当前消息是否包含关键信息:
用户个人信息、偏好、永久性设置; - 如果识别到,立刻提取、更新长期记忆库;
- 优点:实时生效,说完立刻记住;
- 缺点:每轮多一次LLM调用,增加token开销。
三层在请求链路中的执行顺序
- 用户提问;
- 从长期记忆读出用户关键偏好,放到System Prompt;
- 用用户问题去向量库检索中期记忆(历史相关对话片段),加入prompt;
- 取出近期记忆(最近N轮完整对话),拼入消息列表;
- 合并全部内容发给大模型;
- 模型返回结果;
- 写回:保存本轮对话到近期记忆;异步写入向量库(中期记忆);触发长期记忆更新逻辑(批处理/实时触发器)。
三者对比总结
| 记忆层级 | 存储内容 | 存储介质 | SpringAI对应组件 |
|---|---|---|---|
| 近期记忆 | 原始最近N轮消息 | Redis/MySQL | ChatMemory、MessageWindowChatMemory |
| 中期记忆 | 全部历史对话向量 | 向量数据库 | RAG向量检索 |
| 长期记忆 | 结构化摘要、用户偏好 | MySQL/Redis | 自己开发(SpringAI无内置组件) |
重点:Spring AI只原生提供近期记忆 ;中期记忆靠RAG;长期记忆需要自己开发,没有现成starter。
落地选型建议
- 简单对话机器人:只用近期记忆(Redis ChatMemory),够用;
- 需要记住几千轮历史:加中期记忆RAG向量库;
- 需要记住用户永久偏好(记住用户姓名、喜好):再实现一层长期记忆。