Implement Persistent Chat Memory in Spring Boot 3 with Spring AI Advisors
This article demonstrates how to enable conversation memory and history in Spring Boot 3 applications using Spring AI's Advisor API, covering environment setup, Maven dependencies, configuration, code examples for advisors, unique chat IDs, history retrieval, and optional database persistence.
Environment
Spring Boot 3.4.2
1. Introduction
When interacting with Chat models (e.g., Wenxin Yiyan, Tongyi Qianwen, Chat‑DeepSeek), memory and history are essential for recalling past user inputs and topics, enabling more accurate responses. Without memory, each conversation is independent.
With conversation memory enabled, the dialogue becomes continuous.
2. Practical Example
2.1 Environment Preparation
We use Alibaba's Chat model.
<code><dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M6.1</version>
</dependency></code>2.2 Conversation Memory
Spring AI provides a default memory Advisor. Add it when building the ChatClient :
<code>var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
new MyAdvisor(),
...
)
.build();</code>Configure two advisors: one for request logging and one for memory.
<code>@Bean
ChatClient chatClient(ChatClient.Builder ccb, ChatMemory cm) {
List<Advisor> advisors = List.of(
new SimpleLoggerAdvisor(), // request log
new MessageChatMemoryAdvisor(cm) // conversation memory
);
return ccb.defaultAdvisors(advisors).build();
}</code>Define a ChatMemory bean (in‑memory implementation):
<code>@Bean
ChatMemory chatMemory() {
return new InMemoryChatMemory();
}</code>2.3 Unique Conversation IDs
To avoid sharing the same context across users, pass a unique chatId for each request:
<code>@GetMapping("/{chatId}")
public String chat(String prompt, @PathVariable String chatId) {
String result = this.chatClient.prompt(prompt)
.advisors(a -> a
.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
.call()
.content();
return result;
}</code>Now each conversation is isolated.
2.4 Conversation History
Retrieve past messages via ChatMemory :
<code>@RestController
@RequestMapping("/history")
public class ChatHistoryController {
private final ChatMemory chatMemory;
public ChatHistoryController(ChatMemory chatMemory) { this.chatMemory = chatMemory; }
@GetMapping("/{chatId}")
public ResponseEntity<?> queryChatId(@PathVariable String chatId) {
List<MessageVO> result = this.chatMemory.get(chatId, 10).stream()
.map(message -> new MessageVO(parseMessageType(message.getMessageType()), message.getText()))
.collect(Collectors.toList());
return ResponseEntity.ok(result);
}
public static String parseMessageType(MessageType type) {
return switch (type) {
case USER -> "user";
case ASSISTANT -> "assistant";
default -> throw new IllegalArgumentException("Unexpected value: " + type);
};
}
}
</code>2.5 Persistence to Database
If you need to store chat history, add the JDBC memory starter:
<code><dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-jdbc</artifactId>
</dependency></code>Note: This feature is available from version 1.0.0‑M7.
For the full article, see the accompanying PDF with 116 Spring Boot practical cases.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.