SpringAI快速接入对话记忆,告别手动拼历史
假设你做了一个客服 AI。用户第一轮问线上服务怎么申请扩容模型回答完以后用户第二轮接着问我刚才问的是什么如果这时模型说“不知道”不是它记性差。而是大模型本身是无状态的。第二次调用时你没有把上一轮对话带进去它当然接不上前文。很多 Java 开发者会在 Service 里手动处理text查历史消息→ 拼到 prompt→ 调模型→ 保存本轮问题和回答能跑但项目一大就麻烦。客服助手要记忆知识库问答要记忆日志分析 Agent 也要记住上下文。每个入口都手写一遍最后业务代码会变成“对话记忆处理中心”。Spring AI 里的MessageChatMemoryAdvisor就是为了解决这个问题。它不是让模型真的拥有长期记忆而是在每次调用前后帮你维护当前会话需要的上下文。一、先别手动拼历史消息最常见的手写方式大概是这样javaListMessage history chatHistoryRepository.findRecentMessages(userId, 10);ListMessage messages new ArrayList();messages.addAll(history);messages.add(new UserMessage(question));Prompt prompt new Prompt(messages);ChatResponse response chatModel.call(prompt);chatHistoryRepository.save(userId, question, response);这段代码的问题不是不能跑而是不适合长期维护。第一容易重复。每个 AI 入口都要查历史、拼消息、保存回复。第二容易漏。有的接口只查了历史忘了保存本轮回复有的只按userId查用户开多个会话就串了。第三策略不好统一。今天保留最近 5 轮明天改成 10 轮后天想做摘要压缩。如果逻辑散在各个 Service 里改起来很累。更合理的做法是业务代码只负责提问对话记忆交给统一的 Advisor 处理。二、Spring AI 怎么拆这件事Spring AI 的对话记忆不是一个类包办而是几层分工textMessageChatMemoryAdvisor→ 在 ChatClient 调用前后介入ChatMemory→ 决定给模型带哪些历史消息MessageWindowChatMemory→ 按窗口保留最近消息ChatMemoryRepository→ 负责存储和读取消息这里最容易混的是ChatMemory和ChatMemoryRepository。ChatMemory管的是“给模型看的上下文”。它关心的是下一次调用模型时要带哪些历史消息ChatMemoryRepository管的是消息存储。Spring AI 1.1.7 默认会自动配置textMessageWindowChatMemory InMemoryChatMemoryRepositoryMessageWindowChatMemory默认最多保留 20 条消息。注意是 20 条消息不是 20 轮对话。一轮对话通常包含一条用户消息和一条助手消息所以 20 条消息大概就是最近 10 轮左右。超过窗口后较早的消息会被移出但 system message 会保留。InMemoryChatMemoryRepository是内存存储适合 Demo。生产环境别直接依赖它。应用一重启历史就没了多实例部署时每个实例也各存各的。三、最小接入方式如果你的项目已经能正常注入ChatModel接入对话记忆主要三步。1. 准备 ChatMemory只跑 Demo可以先用内存版javaConfigurationpublic class ChatMemoryConfig {Beanpublic ChatMemory chatMemory() {return MessageWindowChatMemory.builder().maxMessages(20).chatMemoryRepository(new InMemoryChatMemoryRepository()).build();}}如果你不声明自己的ChatMemorySpring AI 也会按默认规则自动配置一套。这里显式写出来是为了看清两个配置maxMessages(20)控制窗口大小chatMemoryRepository(...)控制消息存在哪里。2. 配置 MessageChatMemoryAdvisor接着把MessageChatMemoryAdvisor配到ChatClientjavaConfigurationpublic class ChatClientConfig {Beanpublic ChatClient chatClient(ChatModel chatModel, ChatMemory chatMemory) {return ChatClient.builder(chatModel).defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).build();}}配置完成后每次通过这个ChatClient调用模型Advisor 都会参与。它会在调用前读取历史消息把历史作为Message注入请求同时记录本轮用户消息调用后再把模型回复写回记忆。这点很重要MessageChatMemoryAdvisor不是把历史拼成一大段字符串而是把历史作为消息列表交给模型。3. 调用时传 conversationId业务代码可以保持很干净javaServicepublic class ChatService {private final ChatClient chatClient;public ChatService(ChatClient chatClient) {this.chatClient chatClient;}public String chat(String conversationId, String question) {return chatClient.prompt().user(question).advisors(a - a.param(ChatMemory.CONVERSATION_ID, conversationId)).call().content();}}重点是这一行java.advisors(a - a.param(ChatMemory.CONVERSATION_ID, conversationId))在 Spring AI 1.1.7 里内置记忆 Advisor 必须传ChatMemory.CONVERSATION_ID。不传会抛IllegalArgumentException。原因很简单Advisor 必须知道这次调用属于哪个会话才能读取和维护对应的历史消息。四、两轮对话时发生了什么第一次调用javachatService.chat(conv-001, 线上服务怎么申请扩容);这时conv-001还没有历史。Advisor 会把当前用户问题发给模型并把这条用户消息记下来。模型返回后再把助手回复写入同一个会话。第二次调用javachatService.chat(conv-001, 我刚才问的是什么);这次 Advisor 会先取出conv-001的历史消息。模型看到的就不只是当前问题而是text上一轮用户问题上一轮模型回复当前用户问题所以它才能回答你刚才问的是线上服务怎么申请扩容。业务代码没有手动查历史也没有手动拼 prompt。这些都交给 Advisor 处理了。五、conversationId 别乱传conversationId是对话记忆里最容易踩坑的点。不建议直接用userId。因为一个用户可能同时有多个会话。比如他在客服助手里问扩容在知识库助手里问报销又在日志分析 Agent 里查异常。如果都用同一个userId历史就会混在一起。更合适的做法是给每段连续对话一个稳定 IDWeb 场景chatId或sessionIdApp 场景threadId或conversationUUID多 Agent 场景userId agentType chatId也不要每次请求都重新生成一个新的conversationId。那样每次都是新会话模型当然接不上前文。记住一句话同一段连续对话里conversationId 必须稳定不同会话之间conversationId 必须隔离。六、生产环境注意两件事1. 换掉内存存储InMemoryChatMemoryRepository适合本地开发不适合生产。它有三个问题应用重启后历史消息丢失多实例部署时每个实例各存各的不方便统一排查和运维。Spring AI 提供了多种ChatMemoryRepository实现比如 JDBC、MongoDB、Neo4j、Cassandra、Cosmos DB。如果你们公司已经有统一存储也可以自己实现ChatMemoryRepository。2. 不要把 ChatMemory 当完整聊天记录表ChatMemory管的是“给模型看的上下文”。它不是完整聊天记录库。如果你需要用户查看历史、后台审计、客服质检、数据分析建议单独设计业务聊天记录表。可以这样分工textChatMemory→ 给模型看的短期上下文业务聊天记录表→ 给用户、后台、审计和分析看的完整记录这两个东西不要混在一起。七、排查问题先看这三点如果第二轮还是“记不住”先查三件事两轮调用的conversationId是否一致ChatClient有没有配置MessageChatMemoryAdvisor是否用了内存存储并且应用重启或部署了多个实例。另外maxMessages20不是 20 轮对话而是 20 条消息。记忆窗口也不是越大越好。历史越多上下文越长成本越高也更容易把模型带偏。一般先从默认窗口跑通再根据实际效果调整。写在最后对话记忆的本质很简单每次调用前把当前会话需要的历史消息带进去。Spring AI 把这件事拆成了几层textChatMemory→ 管理记忆窗口ChatMemoryRepository→ 存储和读取消息MessageChatMemoryAdvisor→ 调用前后维护记忆conversationId→ 区分不同会话业务代码不用在每个 Service 里查历史、拼 prompt、保存回复。把记忆交给MessageChatMemoryAdvisor。把会话隔离交给conversationId。把生产存储换成持久化ChatMemoryRepository。这套链路理清以后Spring AI 的对话记忆就不难了。

相关新闻

如何用trunk8实现多场景文本截断?实战案例分享

如何用trunk8实现多场景文本截断?实战案例分享

如何用trunk8实现多场景文本截断?实战案例分享 【免费下载链接】trunk8 jQuery Truncation Plugin -- THIS PROJECT IS NO LONGER MAINTAINED 项目地址: https://gitcode.com/gh_mirrors/tr/trunk8 trunk8是一款轻量级的jQuery文本截断插件,能够帮…

2026/10/18 9:52:00 阅读更多 →
2024最新 Azure Community-Policy 资源大全:模板、工具与最佳实践

2024最新 Azure Community-Policy 资源大全:模板、工具与最佳实践

2024最新 Azure Community-Policy 资源大全:模板、工具与最佳实践 【免费下载链接】Community-Policy This repo is for Microsoft Azure customers and Microsoft teams to collaborate in making custom policies. 项目地址: https://gitcode.com/gh_mirrors/c…

2026/10/18 9:52:45 阅读更多 →
flutter-checkio主题定制指南:3步打造你的个性化习惯追踪界面

flutter-checkio主题定制指南:3步打造你的个性化习惯追踪界面

flutter-checkio主题定制指南:3步打造你的个性化习惯追踪界面 【免费下载链接】flutter-checkio How time flies.一款开源习惯打卡APP,流畅的动画体验,Bloc实现状态管理,主题(颜色)切换,字体切换,数据库管理…

2026/10/18 9:52:52 阅读更多 →

最新新闻

一文读懂Qwen3.6-35B-A3B-Quark-INT4-G128:MoE大模型INT4量化的完整入门指南

一文读懂Qwen3.6-35B-A3B-Quark-INT4-G128:MoE大模型INT4量化的完整入门指南

【免费下载链接】Qwen3.6-35B-A3B-Quark-INT4-G128 项目地址: https://ai.gitcode.com/hf_mirrors/amd/Qwen3.6-35B-A3B-Quark-INT4-G128 点击查看 免费下载 Qwen3.6-35B-A3B-Quark-INT4-G128 是用 Quark INT4 W4A16 方案对 Qwen3.6-35B-A3B 这个 MoE 多模态大模型…

2026/10/19 6:53:02 阅读更多 →
Rust+Go跨语言微VM沙箱架构指南:SPACE核心服务、gRPC协议与shim协作模式解析

Rust+Go跨语言微VM沙箱架构指南:SPACE核心服务、gRPC协议与shim协作模式解析

【免费下载链接】SPACE Sandboxed Platform for Agentic Code Execution: pluggable-runtime sandboxes for running agent and user code in isolation. 项目地址: https://gitcode.com/gh_mirrors/space34/SPACE 点击查看 免费下载 当你需要在服务器上安全运行 A…

2026/10/19 6:53:02 阅读更多 →
SpringBoot+Vue选课系统毕设实战:从数据库设计到并发控制

SpringBoot+Vue选课系统毕设实战:从数据库设计到并发控制

选课系统这个题目,在Java毕设里属于典型的“看着简单,做起来全是坑”的项目。很多同学拿到“SpringBootVue大学生选修选课系统”这类题目后,第一反应是到处找源码,找到后却不知道怎么跑起来,更不知道怎么在答辩时把系统…

2026/10/19 6:53:02 阅读更多 →
Flutter插件鸿蒙化适配:azure_app_config云配置接入与实时刷新

Flutter插件鸿蒙化适配:azure_app_config云配置接入与实时刷新

azure_app_config这个Flutter插件,一句话概括:把Azure App Configuration(一个云端的配置管理服务)的能力接进Flutter应用,让配置不再写死在App里,而是从云端下发、实时监听变更、按标签隔离环境。我们团队…

2026/10/19 6:53:02 阅读更多 →
RDPWrap 多用户远程桌面完整上手:安装、验证、更新修复全流程详解

RDPWrap 多用户远程桌面完整上手:安装、验证、更新修复全流程详解

RDPWrap 多用户远程桌面完整上手:安装、验证、更新修复全流程详解 【免费下载链接】rdpwrap.ini RDPWrap.ini for RDP Wrapper Library by StasM 项目地址: https://gitcode.com/GitHub_Trending/rd/rdpwrap.ini 两台设备想同时连回同一台 Windows 桌面&…

2026/10/19 6:53:02 阅读更多 →
如何快速部署Qwen3-VL-32B-Heretic-MiniMax-H3-NVFP4:ComfyUI中5分钟替换CLIPLoader的完整流程

如何快速部署Qwen3-VL-32B-Heretic-MiniMax-H3-NVFP4:ComfyUI中5分钟替换CLIPLoader的完整流程

【免费下载链接】Qwen3-VL-32B-Heretic-MiniMax-H3-NVFP4 项目地址: https://ai.gitcode.com/hf_mirrors/Momoking/Qwen3-VL-32B-Heretic-MiniMax-H3-NVFP4 点击查看 免费下载 Qwen3-VL-32B-Heretic-MiniMax-H3-NVFP4 是面向 MiniMax-H3 视频生成的 NVFP4 量化文本…

2026/10/19 6:52:01 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →