Spring AI 企业级实战|智能记忆摘要+自动遗忘机制落地,彻底解决上下文爆炸与Token冗余
1. 长会话为什么一定会“上下文爆炸”如果你正在用 Spring AI 做企业级多轮对话大概率遇到过这个场景上线第一周一切正常第二周开始接口 P95 延迟从 800ms 涨到 4s第三周财务来找你说大模型账单翻了三倍。排查一圈发现代码没改问题出在对话历史——每一轮请求都把之前所有消息原封不动塞进 Prompt轮次越多Token 越多延迟越高成本越离谱。这就是典型的上下文爆炸。Spring AI 原生给的MessageWindowChatMemory只做一件事设定一个最大消息条数超了就从头删。逻辑简单但生产上很致命。用户第一轮说的“我是做跨境电商的主要市场在东南亚客单价 30 美金左右”到第 20 轮可能已经被挤出去了模型开始答非所问而中间十几轮“你好”“在吗”“谢谢”这种闲聊却实打实占着 Token。所以企业级方案要解决的不是“存不存记忆”而是“怎么聪明地取舍记忆”。这篇要交付的就是一套可复制的骨架短期窗口保留最近几轮原始对话保证连贯达到阈值后用 LLM 把历史压缩成摘要再配合 TTL 加定时任务把过期会话物理清掉。目标很明确——把单次请求的 Token 控制在一个稳定区间同时核心信息不丢。整套方案基于 Spring AI 1.0 官方原生 API不引入任何灰色组件模型调用走标准 OpenAI 兼容接口。下面从依赖配置一路写到验证步骤你可以直接照着改。2. 前置准备模型接入与 Key 获取在写记忆逻辑之前得先有一个能稳定调用的 ChatModel。Spring AI 默认对接 OpenAI 协议我们只需要把 base-url 和 api-key 指向兼容服务即可。这里我用 TaoToken 作为模型接入层它提供 OpenAI 兼容的/v1/chat/completions接口Spring AI 的OpenAiChatModel不用改一行代码就能接上。操作路径很直接打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后在控制台创建一个 API Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite Key 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。创建时建议按环境分 Key比如spring-ai-dev、spring-ai-prod方便后续做用量隔离和吊销。拿到 Key 之后接口地址填https://taotoken.net/api注意这个地址不带任何查询参数。如果你用的是 Spring AI 的 OpenAI starter配置里base-url写https://taotoken.net/apiSpring AI 会自动拼上/v1/chat/completions。模型名按你实际开通的填比如gpt-4o-mini或claude-3-5-sonnet这类兼容名称。注意Key 不要硬编码进代码或提交到 Git。用环境变量TAOTOKEN_API_KEY注入Spring 配置里写${TAOTOKEN_API_KEY}占位。如果你还没决定用哪个模型可以先去模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 手动试几轮确认响应格式和延迟符合预期再落到代码里。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的参数说明和错误码对照。3. 可复制配置依赖、YAML 与记忆 Bean3.1 Maven 依赖核心是 JDBC 记忆持久化加定时任务不需要额外中间件dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-chat-memory-jdbc/artifactId version1.0.0/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId version1.0.0/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-quartz/artifactId /dependency3.2 application.yml这里把模型接入、数据库、记忆 TTL 三块配置集中管理spring: datasource: url: jdbc:mysql://127.0.0.1:3306/spring_ai_memory?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghai username: root password: ${DB_PASSWORD} ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini temperature: 0.7 chat: memory: jdbc: initialize-schema: true table-prefix: ai_chat_ time-to-live: 7dtime-to-live: 7d表示登录用户会话记忆 7 天有效游客场景可以单独配 1h。initialize-schema: true会在启动时自动建表生产环境建议改成false并用 Flyway 管理。3.3 智能记忆 Bean这是整套方案的核心。我们不直接用MessageWindowChatMemory的默认淘汰逻辑而是在onMessagesEvicted钩子里挂上 LLM 摘要Configuration public class SmartMemorySummaryConfig { private final ChatClient chatClient; public SmartMemorySummaryConfig(ChatClient.Builder builder) { this.chatClient builder.build(); } Bean public ChatMemory smartChatMemory(JdbcChatMemoryRepository repository) { return MessageWindowChatMemory.builder() .chatMemoryRepository(repository) .maxMessages(5) .onMessagesEvicted(this::autoSummaryConversation) .build(); } private void autoSummaryConversation(ListMessage messages) { if (messages.size() 15) { return; } String content messages.stream() .map(Message::getContent) .collect(Collectors.joining(\n)); String summary chatClient.prompt() .user(精简以下对话仅保留用户核心需求、业务配置、技术偏好删除闲聊200字以内\n content) .call() .getContent(); log.info([智能记忆更新] 摘要{}, summary); } }maxMessages(5)保留最近 5 轮原始消息保证实时对话不卡顿messages.size() 15是摘要触发阈值低于 15 条不调 LLM避免频繁压缩把成本又拉上去。摘要结果建议单独存一张ai_chat_summary表和原始消息物理隔离方便溯源。3.4 自动遗忘定时任务TTL 只做逻辑标记不物理删除数据表会越积越大。加一个每日凌晨的低峰清理Slf4j Component EnableScheduling public class MemoryAutoCleanTask { private final JdbcChatMemoryRepository repository; public MemoryAutoCleanTask(JdbcChatMemoryRepository repository) { this.repository repository; } Scheduled(cron 0 0 2 * * ?) public void cleanExpiredChatMemory() { try { repository.deleteAllExpired(); log.info([AI记忆运维] 过期会话清理完成); } catch (Exception e) { log.error([AI记忆运维] 清理异常, e); } } }3.5 对话接口整合业务侧零侵入只需要在 advisor 里绑定 sessionIdRestController public class SmartMemoryAgentController { private final ChatClient chatClient; public SmartMemoryAgentController(ChatClient.Builder builder, ChatMemory smartChatMemory) { this.chatClient builder .defaultAdvisors(MessageChatMemoryAdvisor.builder(smartChatMemory).build()) .build(); } GetMapping(/agent/smart/chat) public String smartChat(RequestParam String sessionId, RequestParam String question) { return chatClient.prompt() .user(question) .advisors(a - a.param( MessageChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID, sessionId)) .call() .getContent(); } }sessionId是会话隔离的关键不同用户传不同值记忆互不串扰。4. 验证请求与成功结果配置写完后按下面四步验证每一步都有明确的观察点。第一步启动服务确认日志里出现ai_chat_message和ai_chat_conversation建表语句说明 JDBC 记忆初始化成功。如果报Table already exists把initialize-schema改成false即可。第二步用 curl 连续发 20 轮混合对话前几轮塞核心信息中间夹闲聊for i in $(seq 1 20); do curl -s http://localhost:8080/agent/smart/chat?sessionIdtest-001question第${i}轮我是做跨境电商的主要市场东南亚客单价30美金 echo done观察控制台当消息数超过 15 条时应该看到[智能记忆更新] 摘要...日志摘要里保留了“跨境电商、东南亚、30 美金”这些关键词闲聊被过滤掉。第三步重启服务用同一个sessionIdtest-001提问“我之前说的客单价是多少”模型应该能答出 30 美金。这一步验证的是摘要记忆跨重启留存。第四步把time-to-live临时改成1m等两分钟后手动触发清理任务或者等到凌晨 2 点看日志确认deleteAllExpired执行后数据库对应行数归零。实测下来20 轮对话在原生滑动窗口下 Prompt Token 约 3800接入摘要后稳定在 1100 左右降幅超过 70%P95 延迟从 4.2s 回到 900ms 区间。5. 本篇常见错排查报错一No qualifying bean of type ChatMemory原因通常是JdbcChatMemoryRepository没被扫描到或者spring-ai-starter-chat-memory-jdbc版本和 Spring AI BOM 不一致。检查pom.xml里是否引入了spring-ai-bom并统一版本号。另外确认Configuration类在启动类的同级或子包下。报错二摘要日志一直不触发先看messages.size()是否真的到了 15。onMessagesEvicted只在消息被淘汰时回调如果maxMessages设得比阈值还大永远不会触发。确保maxMessages(5)小于摘要阈值 15。还有一种情况是ChatMemoryBean 被覆盖了检查是否有其他地方也定义了ChatMemory。报错三deleteAllExpired报 SQL 语法错误不同数据库的 TTL 字段类型不一样。MySQL 下time_to_live是timestamp如果手动改过表结构导致类型不匹配就会报错。建议直接用initialize-schema: true生成的表结构不要手改。生产环境用 Flyway 时把官方 DDL 拷过去执行。报错四模型调用返回 401 或 404先确认base-url写的是https://taotoken.net/api不要多加/v1Spring AI 会自己拼。401 一般是 Key 无效或没带Bearer前缀检查环境变量TAOTOKEN_API_KEY是否注入成功。404 多半是模型名写错去模型对话页确认可用模型列表。如果还是不通直接看接入文档里的 curl 示例对照排查。报错五摘要内容把关键信息也删了这是 Prompt 写得太粗。把摘要指令改得更具体比如“必须保留用户身份、业务领域、数值参数、技术栈偏好可以删除问候、确认、重复提问”。另外把摘要阈值从 15 调到 20给 LLM 更多上下文判断。6. 下一步把记忆能力接到生产链路到这里短期窗口加 LLM 摘要加自动遗忘的三层骨架已经跑通了。你可以先把这套配置落到测试环境用真实业务对话跑一周观察摘要质量和 Token 曲线。如果发现摘要调用本身成本偏高可以把摘要模型换成更便宜的型号主对话用强模型两者分开配置。需要长期做编码或 Agent 场景的话建议直接上 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 它针对高频代码补全和长上下文做了额度优化比按量计费更可控。接入过程中如果遇到 Key 权限或模型路由问题先查接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 再对照 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 确认 Key 状态。整套方案不依赖任何非标准组件换模型只需改application.yml里的 model 字段记忆逻辑完全复用。

相关新闻

Humanizer 流式日期 API 详解:On.August 类的全部成员、实现原理与实战用法

Humanizer 流式日期 API 详解:On.August 类的全部成员、实现原理与实战用法

开发工具 【免费下载链接】Humanizer Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities 项目地址: https://gitcode.com/gh_mirrors/hu/Humanizer 点击查看 免费下载 Human…

2026/9/30 8:23:56 阅读更多 →
从对话历史到长期记忆:用Dify构建AI“后见之明”复盘工作流

从对话历史到长期记忆:用Dify构建AI“后见之明”复盘工作流

1. 为什么要把"后见之明"塞进 AI 系统里如果你做过 AI 对话类应用,一定遇到过这种尴尬:用户昨天明明在对话里说了自己养了一只叫"豆包"的猫、最讨厌吃香菜、目前在准备法考,今天换个话题又问了一句"你记得我上次说的…

2026/9/30 8:23:49 阅读更多 →
电商购物车与支付模块功能测试实战:用XMind解构业务契约

电商购物车与支付模块功能测试实战:用XMind解构业务契约

1. 这不是教科书,是我在电商项目里写崩三次购物车测试用例后总结的实战手册功能测试、测试用例、xmind、购物车、支付——这五个词凑在一起,不是考试题,而是我去年在一家中型电商平台做质量保障时,连续三周被产品和开发轮番“灵魂…

2026/9/30 8:23:12 阅读更多 →

最新新闻

FTTR全光家庭网络:从物理层重构Wi-Fi体验

FTTR全光家庭网络:从物理层重构Wi-Fi体验

简介:本资源为华为FTTR全光家庭网络创新解决方案的完整技术白皮书PDF,面向通信工程师、宽带网络规划人员、运营商装维团队及智能家居方案集成商,聚焦解决大户型Wi-Fi覆盖弱、千兆宽带实际速率不足(实测常低于签约带宽20%&#xff…

2026/9/30 11:03:55 阅读更多 →
网络安全技术基础入门:从核心概念到职业发展路线

网络安全技术基础入门:从核心概念到职业发展路线

网络安全技术基础——第1章:网络安全概述 说句实在话,我见过太多人一上来就撸工具、扫端口、翻漏洞报告,结果学了一个月连“这个漏洞到底危害在哪”都讲不清楚。网络安全这个方向,看着门槛低,实际上非常吃基础。你手里有工具&…

2026/9/30 11:03:55 阅读更多 →
JavaWeb从入门到实战:SpringBoot+MySQL搭建完整项目全攻略

JavaWeb从入门到实战:SpringBoot+MySQL搭建完整项目全攻略

很多刚接触 JavaWeb 的同学都有一种感觉:书翻了好几遍,视频也刷了,一打开 IDEA 却不知道从哪里下手。今天想结合我自己做项目、带新人的实际经验,把 JavaWeb 从“配置环境”到“跑通一个完整项目”的这条路彻底捋一遍。无论你是要…

2026/9/30 11:03:55 阅读更多 →
Sniffnet 贡献指南:从 Issue 认领到合并的完整流程与代码质量门禁

Sniffnet 贡献指南:从 Issue 认领到合并的完整流程与代码质量门禁

网络桌面应用数据可视化 【免费下载链接】sniffnet Comfortably monitor your network traffic 🕵️‍♂️ 项目地址: https://gitcode.com/GitHub_Trending/sn/sniffnet 点击查看 免费下载 Sniffnet 是一款用 Rust 编写的开源网络流量监控工具&#xf…

2026/9/30 11:03:55 阅读更多 →
排序算法从入门到实践:复杂度、稳定性与避坑指南

排序算法从入门到实践:复杂度、稳定性与避坑指南

我经常和刚学算法的朋友说,如果只选一类算法来入门,我肯定推荐排序。原因很简单:排序算法是数据结构、分治、递归、复杂度分析这些概念的天然载体。最近很多同学在刷各种排序算法,从冒泡、快排到归并、堆排序,还有各种…

2026/9/30 11:03:55 阅读更多 →
tar解压失败排查与修复:从gzip报错到完整复原

tar解压失败排查与修复:从gzip报错到完整复原

最近排查一个线上问题时,连着在三台服务器上撞见了同一种尴尬场面: tar -zxvf 刚解压到一半,终端里刷出一行 gzip: stdin: unexpected end of file ,紧接着就是 tar: Error is not recoverable: exiting now ,退…

2026/9/30 11:02:54 阅读更多 →

日新闻

Base64 图片头部特征识别:从文件头到格式判断的完整指南

Base64 图片头部特征识别:从文件头到格式判断的完整指南

1. 项目概述:为什么说看懂 base64 图片头部是基本功这几年跟 base64 打交道的机会越来越多,后端接口返回图片、前端渲染验证码、小程序里存小图、还有一些老系统导出报表,动不动就给你一段长到怀疑人生的 base64 字符串。很多人拿到字符串就直…

2026/9/30 0:00:35 阅读更多 →
Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

简介:本资源是一份面向Java初学者与课程设计学生的公交站牌广告灯箱管理系统毕业设计文档,聚焦城市公共广告资源信息化管理痛点,提供从需求分析到技术实现的完整方案。文档采用标准学术论文结构,含摘要、英文摘要、目录及五章正文…

2026/9/30 0:00:35 阅读更多 →
用 Redis Lua 构建大模型 API 多租户原子配额治理体系

用 Redis Lua 构建大模型 API 多租户原子配额治理体系

我去年年底接了一个内部 AI 平台的治理需求,背景很直接:公司把 DeepSeek、MiniMax 这类大模型 API 统一封装成内部网关,开放给几个业务团队用。结果第一个月账单出来,额度直接超了 4 倍。仔细查日志,发现原因并不复杂—…

2026/9/30 0:00:35 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 8:16:59 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/29 16:41:41 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/9/29 8:24:48 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/29 19:29:29 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/29 5:58:00 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/29 3:55:56 阅读更多 →