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(); 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() { ChatMemory memory = MessageWindowChatMemory.builder() .maxMessages(10) .build(); ChatClient client = ChatClient.builder(model) .defaultAdvisors(new MessageChatMemoryAdvisor(memory)) .build(); 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(); 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(); 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
| ChatMemory memory = MessageWindowChatMemory.builder().build(); String conversationId = "007";
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());
UserMessage msg2 = new UserMessage("What is my name?");memory.add(conversationId, msg2); ChatResponse res2 = chatModel.call(new Prompt(memory.get(conversationId)));
|