6-ChatMemory

1 核心概念和作用

背景:LLM(大语言模型)无状态,无法保留历史交互信息,ChatMemory 用于存储和检索跨交互的上下文,维持对话连续性。

核心区别:

  • Chat Memory:模型用于维持对话上下文的相关信息(非完整历史)。
  • Chat History:用户与模型交互的完整消息记录(需用其他方式存储,如 Spring Data)。

抽象设计:

  • ChatMemory:管理对话上下文的核心接口,决定保留哪些消息。
  • ChatMemoryRepository:负责消息的底层存储(如内存、数据库)。

2 快速开始与默认配置

自动配置:Spring AI 自动配置 ChatMemory bean,默认使用:

  • 存储: InMemoryChatMemoryRepository(内存存储)。
  • 实现: MessageWindowChatMemory(窗口大小 20 条消息)。

直接使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Autowired
private ChatMemory chatMemory;
@Autowired
private OpenAiChatModel model;
@Test
void testMemery() {
ChatClient client = ChatClient.builder(model)
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
.build();
// 顾问会自动将历史消息添加到 Prompt 中
String response = client.prompt().user("北京暴雨,长沙大太阳,内蒙古天气很凉爽").call().content();
System.out.println(response);
String content = client.prompt().user("前面的三个地方最近适合去哪里旅游呢?").call().content();
System.out.println(content);
}

手动创建示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Autowired
private OpenAiChatModel model;
@Test
void testMemery() {
// 创建窗口大小为 10 的内存存储对话记忆
ChatMemory memory = MessageWindowChatMemory.builder()
.maxMessages(10)
.build();
ChatClient client = ChatClient.builder(model)
.defaultAdvisors(new MessageChatMemoryAdvisor(memory))
.build();
// 顾问会自动将历史消息添加到 Prompt 中
String response = client.prompt().user("北京暴雨,长沙大太阳,内蒙古天气很凉爽").call().content();
System.out.println(response);
String content = client.prompt().user("前面的三个地方最近适合去哪里旅游呢?").call().content();
System.out.println(content);
}

3 存储实现与配置

MessageWindowChatMemory默认的方式,使用 ConcurrentHashMap 在内存中存储消息。

JdbcChatMemoryRepository基于关系型数据库来存储

1
2
3
4
5
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
<version>1.1.0-SNAPSHOT</version>
</dependency>

这个依赖需要从官方仓库下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<repositories>
<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>

支持数据库:PostgreSQL、MySQL/MariaDB、SQL Server、HSQLDB。

添加下数据库的配置

1
2
3
4
5
spring.datasource.url=jdbc:mysql://localhost:3306/ai?
useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void testMemery() {
ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder()
.jdbcTemplate(jdbcTemplate)
.dialect(new MysqlChatMemoryRepositoryDialect())
.build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
ChatClient client = ChatClient.builder(model)
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
.build();
// 顾问会自动将历史消息添加到 Prompt 中
String response = client.prompt().user("北京暴雨,长沙大太阳,内蒙古天气很凉爽").call().content();
System.out.println(response);
String content = client.prompt().user("前面的三个地方最近适合去哪里旅游呢?").call().content();
System.out.println(content);
}

其他的方式可以自行扩展和结合官网来实现

4 与 ChatClient 集成

MessageChatMemoryAdvisor: 行为:从记忆中获取历史消息,以消息集合形式添加到 Prompt。

1
2
3
4
ChatMemory memory = MessageWindowChatMemory.builder().build();
ChatClient client = ChatClient.builder(model)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(memory).build())
.build();

PromptChatMemoryAdvisor: 行为:将历史消息作为纯文本追加到系统提示中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Test
void testMemery() {
ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder()
.jdbcTemplate(jdbcTemplate)
.dialect(new MysqlChatMemoryRepositoryDialect())
.build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
PromptChatMemoryAdvisor advisor = PromptChatMemoryAdvisor.builder(chatMemory).build();
ChatClient client = ChatClient.builder(model)
.defaultAdvisors(advisor)
.build();
// 顾问会自动将历史消息添加到 Prompt 中
ChatClient.CallResponseSpec call = client.prompt()
.user("推荐适合新手的相机")
.advisors(a -> a.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, "dpb1")
.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 5))
.call();
System.out.println("推荐的内容"+call.chatResponse());
System.out.println("------------");
ChatClient.CallResponseSpec call1 = client.prompt().user("按照价格排序下")
.advisors(a -> a.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, "dpb1")
.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 5))
.call();
System.out.println(call1.chatClientResponse());
}

VectorStoreChatMemoryAdvisor:从向量存储中检索历史消息,追加到系统提示。

5 与 ChatModel 直接集成

1
2
3
4
5
6
7
8
9
10
11
12
// 1. 创建记忆实例
ChatMemory memory = MessageWindowChatMemory.builder().build();
String conversationId = "007";
// 2. 第一次交互
UserMessage msg1 = new UserMessage("My name is James Bond");
memory.add(conversationId, msg1);
ChatResponse res1 = chatModel.call(new Prompt(memory.get(conversationId)));
memory.add(conversationId, res1.getResult().getOutput());
// 3. 第二次交互
UserMessage msg2 = new UserMessage("What is my name?");memory.add(conversationId, msg2);
ChatResponse res2 = chatModel.call(new Prompt(memory.get(conversationId)));
// res2 应包含 "James Bond

6-ChatMemory
http://www.zivjie.cn/2025/11/22/spring框架/springAI/SpringAi框架/6-ChatMemory/
作者
Francis
发布于
2025年11月22日
许可协议