【SpringAI 17】MessageChatMemoryAdvisor核心类说明
MessageChatMemoryAdvisor 是 Spring AI 框架中用于实现多轮对话上下文记忆的核心组件。它基于 AOP面向切面编程的 Advisor 机制自动管理聊天历史的存储与检索使无状态的大语言模型LLM能够“记住”之前的对话内容。以下是对其核心功能、工作原理、配置方式及关键注意事项的详细解析。1. 核心功能与作用大模型本质上是无状态的每次请求都是独立的。MessageChatMemoryAdvisor 的作用是在请求发送给模型之前和之后自动拦截处理请求前Before根据当前的 conversationId会话 ID从 ChatMemory 中检索历史消息并将其作为上下文消息插入到当前的 Prompt 中。请求后After接收模型的响应将用户的最新提问和模型的回复保存到 ChatMemory 中以便下一轮对话使用。通过这种方式开发者无需手动维护 List即可实现连贯的多轮对话体验。2. 工作原理与执行流程MessageChatMemoryAdvisor 在 ChatClient 的执行链中运行具体流程如下获取会话 ID从请求上下文中提取 conversationId。如果未指定通常使用默认值如 “default”。加载历史调用 ChatMemory.get(conversationId) 获取该会话的历史消息列表。构建 Prompt将历史消息集合添加到当前请求的消息列表中。注意MessageChatMemoryAdvisor 是将历史消息作为标准的 User/Assistant/System 消息对象添加而不是拼接成纯文本字符串这与 PromptChatMemoryAdvisor 不同。执行模型调用将包含完整上下文的 Prompt 发送给 LLM。保存记忆获取模型返回的 AssistantMessage调用 ChatMemory.add(conversationId, messages) 将本轮的用户消息和助手回复持久化存储。3. 正确配置方式在较新版本的 Spring AI 中MessageChatMemoryAdvisor 的构造函数已私有化必须使用 Builder 模式进行创建。3.1 定义 ChatMemory Bean首先需要一个 ChatMemory 的实现。推荐使用 MessageWindowChatMemory它可以限制保留的消息数量防止 Token 溢出。ConfigurationpublicclassChatMemoryConfig{BeanpublicChatMemorychatMemory(ChatMemoryRepositoryrepository){returnMessageWindowChatMemory.builder().chatMemoryRepository(repository)// 可以是 InMemory, Redis, MongoDB 等实现.maxMessages(20)// 只保留最近20条消息.build();}// 如果使用内存存储Spring AI 通常会自动提供 InMemoryChatMemoryRepository}3.2 集成到 ChatClient在构建 ChatClient 时将 Advisor 注册为默认顾问。ServicepublicclassChatService{privatefinalChatClientchatClient;publicChatService(ChatClient.Builderbuilder,ChatMemorychatMemory){this.chatClientbuilder// 【关键点】使用 Builder 模式创建 Advisor.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).build();}}3.3 调用时传递会话 ID关键为了实现多用户隔离或多会话管理必须在每次调用 prompt() 时动态传入 conversationId。否则所有请求将共享同一个默认会话历史导致数据混乱。publicStringchat(StringconversationId,StringuserMessage){returnchatClient.prompt().user(userMessage)// 【关键点】动态指定当前请求所属的会话 ID.advisors(advisorSpec-advisorSpec.param(ChatMemory.CONVERSATION_ID,conversationId)).call().content();}4. 与其他 Memory Advisor 的区别Spring AI 提供了多种记忆策略MessageChatMemoryAdvisor 是最常用的一种Advisor 类型记忆注入方式适用场景MessageChatMemoryAdvisor将历史消息作为标准的 Message 对象列表加入 Prompt。通用场景。最符合 LLM 的原生交互格式支持角色区分System/User/Assistant。PromptChatMemoryAdvisor将历史消息序列化为纯文本追加到 System Prompt 或用户消息中。某些特定模型对纯文本上下文支持更好或需要严格控制消息结构时。VectorStoreChatMemoryAdvisor结合向量数据库检索与当前问题语义相关的历史片段。长对话场景。当历史记录过长超出上下文窗口时只检索相关片段节省 Token。5. 高级特性与注意事项5.1 与 Tool Calling工具调用的交互在涉及函数调用Function Calling/Tool Use的场景中默认的 MessageChatMemoryAdvisor 不会存储中间的工具调用消息即 ToolExecutionResultMessage 或中间的 Assistant 工具请求。原因大多数 ChatMemoryRepository 实现不支持复杂工具消息类型的序列化且中间过程通常不需要长期记忆。现状它只存储最终的 User 输入和 Assistant 的最终自然语言回复。如果需要记忆工具调用过程需自定义 Advisor 或使用支持该特性的 Repository。执行顺序MessageChatMemoryAdvisor 的默认优先级高于 ToolCallingAdvisor确保工具调用能基于完整的上下文历史进行决策。5.2 生产环境存储建议开发/测试使用 InMemoryChatMemoryRepository默认重启服务后记忆丢失。生产环境务必使用持久化存储如 Redis 或 MongoDB。Redis适合高并发、低延迟场景利用 List 结构存储消息配合 TTL 自动过期冷会话。MongoDB适合需要复杂查询或长期归档对话记录的场景。5.3 线程安全ChatMemory 的实现必须是线程安全的。InMemoryChatMemoryRepository 内部使用 ConcurrentHashMap是线程安全的。如果使用自定义 Repository需确保并发读写的安全性。总结MessageChatMemoryAdvisor 是 Spring AI 实现有状态对话的基石。使用时请牢记三点使用 Builder 模式创建实例。务必在每次请求中动态传递 conversationId 以隔离会话。根据业务规模选择合适的 ChatMemoryRepository内存、Redis 或 MongoDB以实现持久化。