Spring AI Alibaba 学习记录(记忆功能实现)
·
1. “记忆”到底是什么
大语言模型本身通常是“无状态”的:每次请求只看得到你这一次发给它的内容。
之所以看起来“记得之前说过什么”,本质是应用在每次请求时,把一段历史对话一起带给模型。
一个直观例子:
- 第 1 轮
- 问:10 个苹果分给 2 个人,每人多少个?
- 模型看到:
10 个苹果分给 2 个人,每人多少个? - 模型答:5 个
- 第 2 轮
- 问:如果有 5 个人呢?
- 模型看到:
10 个苹果分给 2 个人... + 模型答 5 个 + 如果有 5 个人呢? - 模型答:2 个
所以:把所有问题都塞在同一个对话里,历史越长,token 消耗越快,成本也越高。
2. Spring AI 的“记忆”怎么做
Spring AI 通常把“记忆”拆成三件事:
- 存放聊天记录的地方:内存 / 数据库 / 其他存储
- 控制取多少历史:常见是“只取最近 N 条”
- 自动读写历史:每次调用模型前取历史、调用后把新消息写回去
需要特别记住一个概念:会话 ID(conversationId)
- 这是用来区分“这一段对话属于谁/属于哪个聊天窗口”的标识
- 每次请求都必须传同一个 conversationId,才能续上上一轮的历史
3. 存到内存(适合学习 / 开发)
3.1 手动管理(更直观,但不够优雅)
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
public class MemoryDemo {
private final ChatModel chatModel;
public MemoryDemo(ChatModel chatModel) {
this.chatModel = chatModel;
}
public void run() {
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(10)
.build();
String conversationId = "007";
chatMemory.add(conversationId, new UserMessage("My name is James Bond"));
ChatResponse res1 = chatModel.call(new Prompt(chatMemory.get(conversationId)));
chatMemory.add(conversationId, res1.getResult().getOutput());
chatMemory.add(conversationId, new UserMessage("What is my name?"));
ChatResponse res2 = chatModel.call(new Prompt(chatMemory.get(conversationId)));
chatMemory.add(conversationId, res2.getResult().getOutput());
}
}
3.2 自动管理(更常用、更优雅)
核心思路:给 ChatClient 加一个“记忆增强器”,让它自动做:
- 调用前:按 conversationId 取历史
- 调用后:把新消息写回去
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.memory.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.model.ChatModel;
public class ChatService {
private final ChatClient chatClient;
private final String conversationId = "007";
public ChatService(ChatModel chatModel) {
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(10)
.build();
this.chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
}
@GetMapping("/ai")
public String chat(String userInput) {
return chatClient.prompt()
.user(userInput)
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.call()
.content();
}
}
4. 存到数据库(JDBC,适合生产)
当你希望“重启不丢”“多实例共享”“可追溯”,就要把聊天记录存到数据库。
4.1 引入依赖
Maven:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
4.2 建表(很关键)
JDBC 方式会用一张表保存聊天记录(默认表名 SPRING_AI_CHAT_MEMORY)。
默认情况下,只有“内嵌数据库”才会自动建表。对于 MySQL / PostgreSQL 这类常见数据库,一般需要显式开启:
spring.ai.chat.memory.repository.jdbc.initialize-schema=always
4.3 配置代码:把“窗口记忆”绑定到“JDBC 存储”
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.memory.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.memory.repository.ChatMemoryRepository;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AiMemoryConfig {
@Bean
public ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {
return MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
}
@Bean
public ChatClient chatClient(ChatModel chatModel, ChatMemory chatMemory) {
return ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
}
}
说明:
ChatMemoryRepository会由 JDBC starter 自动装配成数据库实现MessageWindowChatMemory负责“只拿最近 N 条”,避免 token 失控
4.4 Controller 调用:每次都带 conversationId
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AIController {
private final ChatClient chatClient;
public AIController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/ai")
public String generation(@RequestParam String userInput,
@RequestParam String conversationId) {
return this.chatClient.prompt()
.user(userInput)
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.call()
.content();
}
}
PS:由于本人学习的不够深刻可能会出现错误,请多多包涵
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)