Spring AI AutoMemoryTools实战:从失忆到记住一切的Session API

2026-06-01阅读 0热度 0
session
好的,请查收。这是按照您的要求,对原文进行深度润色后的版本。它消除了AI腔调,保留了所有核心信息、结构和图片,并严格清理了推广内容,更接近一位资深人类专家的技术分享风格。 ---

前段时间团队内部搭了一个 AI 助手,技术选型是 Spring AI,用 ChatClient 挂上了 MessageWindowChatMemory,对话历史通过 Redis 持久化。跑起来感觉一切正常,直到收到用户反馈:「我上周告诉过它,我不喜欢代码里有 magic number,这周它又给我生成了一堆。」

查了一圈,发现问题根源既不在 Redis,也不在配置——而是对 Spring AI 记忆体系的理解从一开始就存在偏差。想当然地以为加上一个 ChatMemory 就相当于给 Agent 装上了「记性」,但实际并非如此。Spring AI 的记忆分两层,而当时只接上了其中一层。

这篇文章是那次排查之后的系统梳理。如果正在用 Spring AI 做 Agent 项目,或者正在规划,这两层记忆的区别,确实是绕不过去的关键点。

先说清楚:Spring AI 记忆的两层架构

大多数人最先接触的是 ChatMemory,它负责保存对话历史,让 LLM 知道当前上下文说了什么。这属于短期记忆,解决的是「这一次会话里说过什么」的问题。

到了 Spring AI 1.1 版本之后,引入了 Session API,进一步强化了这一层,增加了事件溯源模型和上下文压缩能力。

但另外一层——长期记忆——依赖的完全是另一套机制:AutoMemoryTools。它解决的是「跨会话、跨重启,Agent 需要记住的那些事」。

两层各司其职,缺一不可:

维度短期记忆(Session API / ChatMemory)长期记忆(AutoMemoryTools)
生命周期当前会话永久持久化
存储位置内存 / JDBC / Redis文件系统(Markdown 文件)
内容完整对话历史精选事实、偏好、决策
谁来管理Spring AI 框架自动管理LLM 自主决定写入/读取
适合场景让 LLM 记住上下文让 Agent 记住用户偏好和项目决策

当时的架构只接了短期记忆这一层,所以用户的代码风格偏好在下次会话时自然会消失——根本没有人把这个事实写进长期记忆里。

图:Spring AI Agent 两层记忆体系架构,蓝色为 AutoMemoryTools 长期记忆层,紫色为 Session API 短期记忆层

AutoMemoryTools:让 LLM 自己决定记什么

AutoMemoryTools 是 spring-ai-agent-utils 这个社区库提供的工具集,设计灵感直接来自 Anthropic Claude Code 的记忆系统。核心思路很简单:给 Agent 6 个文件操作工具,让它自行判断哪些事情值得记下来。

6 个工具覆盖完整的记忆生命周期

工具作用
MemoryView读文件内容(带行号)或列目录
MemoryCreate创建带 frontmatter 的记忆文件
MemoryStrReplace精确替换文件中的某段内容
MemoryInsert在指定行之后插入内容
MemoryDelete删除文件或目录
MemoryRename移动/重命名文件(自动更新索引)

这 6 个工具和文件系统工具很像,但有一个关键限制:所有操作都被沙箱化在 memoriesDir 目录内。绝对路径会被拒绝,路径穿越也会被检测到,不用担心 Agent 会跑去写 /etc/hosts

记忆文件的格式

每一条长期记忆是一个 Markdown 文件,带 YAML frontmatter:

---name: code-style-preferencedescription: 用户代码风格偏好type: feedback---用户不希望代码里出现 magic number,变量命名倾向于语义化英文而非拼音缩写。**Why:** 用户在 2026-04-28 的对话中明确纠正了生成的代码。**How to apply:** 生成任何代码时,常量抽取为 static final,变量名用完整英文单词。

记忆类型有 4 种:

  • user:角色、目标、专业背景、沟通偏好
  • feedback:用户验证过的纠正和确认过的方法
  • project:正在推进的工作、决策、截止日期
  • reference:外部系统的指针(看板、仪表盘地址)

所有记忆文件的入口是 MEMORY.md,这是一个索引文件。Agent 在每次会话开始时,会先读这个文件,决定要加载哪些相关的记忆:

# Memory Index- [code-style-preference.md](code-style-preference.md) — 用户代码风格偏好:不要 magic number- [project-deadline.md](project-deadline.md) — 当前项目 Q2 上线计划

这个「索引优先」的设计很关键:即使长期记忆库积累了几十个文件,Agent 每次也不必将所有文件全塞进上下文,而是查看索引摘要,按需精准加载。

最简接入方式:AutoMemoryToolsAdvisor

// 依赖:spring-ai-agent-utilsChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(// 1. AutoMemory Advisor:注入系统提示词 + 注册 6 个工具AutoMemoryToolsAdvisor.builder().memoriesDir("/home/user/.agent/memories").build(),// 2. 短期记忆:保留最近 100 条消息MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().maxMessages(100).build()).build(),// 3. 工具调用执行器ToolCallAdvisor.builder().disableInternalConversationHistory().build()).build();

三个 Advisor 叠加,就完成了两层记忆的完整接入。AutoMemoryToolsAdvisor 会自动将系统提示词注入进去,LLM 就知道什么时候该读记忆、什么时候该写。

什么情况下 LLM 会写记忆?

AutoMemoryTools 配套的系统提示词会指引 LLM 在以下场景触发写入:

  • 用户明确纠正了它的某个行为(触发 feedback 类型)
  • 用户给出了关于自己的新信息(触发 user 类型)
  • 项目状态有变化(触发 project 类型)

值得关注的是,LLM 自己决定写什么,而不是由框架强制写。这意味着记忆质量和所用模型的能力直接相关——Claude Sonnet 能写出很精准的条目,弱模型则可能漏写,或写得太宽泛。

另外还有一个叫做 memoryConsolidationTrigger 的机制,可以配置每隔 N 轮对话,或每 5% 的概率,触发一次记忆整理,防止积累过多冗余信息。

踩坑:为什么不要把代码模式存进长期记忆

官方文档里有一段容易被忽略的警告:代码模式、git 历史、调试方法,这些内容不要存进 AutoMemoryTools。它们应该存放在代码库本身(注释、CLAUDE.md、README)里,而不是 Agent 的个人记忆。

原因很直接:这类内容会随代码变化而变更,但长期记忆文件不会自动同步,很快就会过时,变成噪音。

Session API:短期记忆的「工业级」升级

在 Spring AI 1.1 之前,短期记忆的主要实现是 MessageWindowChatMemory——维护一个固定大小的消息窗口。简单,但有明显的局限性:

  • 按消息数量截断,不按 token 数量——实际上下文利用率低
  • 截断时可能切断一半的工具调用 + 工具结果,LLM 看到孤立的 tool result 可能会困惑
  • 没有持久化,重启即丢失

Spring AI 的 Session API(Agentic Patterns 系列第 7 篇)是对这一层的彻底重新设计,引入了事件溯源模型。

核心概念:Turn(轮次)是原子单位

Session API 最大的创新点在于,把「一轮对话」定义为原子单位:一条 UserMessage + 之后所有 AssistantMessage、ToolCall、ToolResult,直到下一条 UserMessage 出现。

压缩时保证完整轮次要么全保留,要么全丢弃,不会出现「保留了工具调用但丢掉了对应的工具结果」这种情况。这解决了 MessageWindowChatMemory 最令人头疼的问题。

每个 SessionEvent 包装了一条 Message,附带的信息包括:

  • UUID 和 sessionId
  • 时间戳
  • branch label(用于多 Agent 并行的分支隔离)
  • METADATA_SYNTHETIC 标志(标记这是 LLM 生成的摘要,而非真实消息)

4 种压缩策略怎么选

策略是否需要 LLM适用场景
SlidingWindow成本敏感,短期上下文
TurnWindow对话结构清晰,N 轮之前的内容不重要
TokenCount严格的 token 上限控制
RecursiveSummarization长对话,历史信息需保留但要压缩

RecursiveSummarization 是最智能也最贵的方案:它不会从零开始总结,而是维护一个滚动压缩历史,每次把新增的「要被淘汰的内容」追加进去重新摘要,避免每次都重算。总结结果会被标记为 METADATA_SYNTHETIC,用于持续压缩。

实际选型建议:

  • 聊天机器人、单轮问答 → SlidingWindowTurnWindow,够用且无需额外成本
  • 复杂任务 Agent,工具调用链很长 → TurnWindow(保证原子性)
  • 长期工作 Agent,需要保留全局上下文 → RecursiveSummarization,但要记得算上 LLM 的调用费用
// Session API 接入示例SessionMemoryAdvisor advisor = SessionMemoryAdvisor.builder(sessionService).defaultUserId("user-alice")// 20 轮之后触发压缩.compactionTrigger(new TurnCountTrigger(20))// 压缩策略:保留最近 10 个 event,其余滑走.compactionStrategy(SlidingWindowCompactionStrategy.builder().maxEvents(10).build()).build();

隐藏能力:Recall Storage

即便上下文已经被压缩掉了,Session API 仍保留了完整的原始事件日志,并提供了一个 conversation_search 工具。Agent 可以用关键词搜索历史对话。

举个例子,Agent 在第 80 轮突然需要查找「第 5 轮说过的某个 API 地址」,可以直接调用工具检索,而不必在上下文里一直保留第 5 轮的内容。这个设计参考了 MemGPT 的 Recall Storage 模式。

图:Session API 四种压缩策略的选择决策流程,以及 Recall Storage 的保障机制

JDBC 持久化:生产环境必须做

Session API 默认的 spring-ai-session-jdbc 用两张表存储:

-- AI_SESSION:会话元数据-- AI_SESSION_EVENT:append-only 事件日志

支持 PostgreSQL、MySQL、MariaDB、H2。对话历史可以跨重启保留,这才是生产级的短期记忆。

向量库 vs Redis vs 文件系统:长期记忆存储选型

除了 AutoMemoryTools 的文件系统方案,社区里还有另一套思路:用 Redis 向量库做语义记忆检索。

Spring AI + Redis 向量存储的架构

这套方案来自 Redis 官方博客,核心是两种记忆类型:

  • EPISODIC(情节记忆):个人经历、用户偏好,按时间顺序,精确检索
  • SEMANTIC(语义记忆):通用知识、事实,按语义相似度检索

存储使用 RedisVectorStore

// Redis 向量索引配置RedisVectorStore.RedisVectorStoreConfig config = RedisVectorStore.RedisVectorStoreConfig.builder().withIndexName("longTermMemoryIdx").withVectorAlgorithm(Algorithm.HSNW)// 近似最近邻.withContentFieldName("content").withEmbeddingFieldName("embedding").addMetadataField(MetadataField.tag("memoryType")).addMetadataField(MetadataField.tag("userId")).build();

向量维度是 384 维 FLOAT32,使用 COSINE 距离。Redis 8 号称可以支持 10 亿向量而不降低延迟,在规模上不是瓶颈。

两个关键的 Advisor:

// Retrieval Advisor:调用 LLM 之前,向量搜索最相关记忆并注入 system prompt// Recorder Advisor:LLM 响应之后,提取原子事实并去重存入向量库

两种方案的对比

维度AutoMemoryTools(文件系统)Redis 向量库
搜索方式精确匹配(LLM 自行判断相关性)语义向量相似度
记忆管理LLM 自主决策Advisor 自动提取
运维复杂度低(文件读写)中(Redis + 向量索引维护)
记忆可读性高(Markdown 文件,人可直接读)低(向量 + JSON,不直观)
适合规模小到中(百条级别)中到大(万条级别)
冷启动LLM 读 MEMORY.md 索引每次请求自动语义检索

怎么选:

如果 Agent 面向个人用户(每个用户几十到几百条记忆),AutoMemoryTools 的文件方案完全够用,且可读性好,便于调试。

如果 Agent 需要在海量历史记忆中做语义检索(比如企业知识库 Agent),Redis 向量方案更合适,但会带来额外的 embedding 调用开销和 Redis 运维负担。

两种方案并不互斥——可以用 AutoMemoryTools 存「用户偏好」这类精准事实,用 Redis 向量库存「历史交互摘要」这类语义内容。

图:两种长期记忆存储方案的全面对比,以及适用场景分析

Spring AI vs LangChain4j:记忆能力差距在哪里

国内文章比较这两个框架时,常局限于“支不支持某个模型”,而记忆能力这块鲜有人详细展开。

LangChain4j 的记忆体系:LangChain4j 的聊天记忆基于 ChatMemory 接口,有 MessageWindowChatMemoryTokenWindowChatMemory 两种实现。TokenWindowChatMemory 按 token 数量而非消息数量控制窗口,这一点比 Spring AI 默认的实现更实用。

LangChain4j 没有内置类似 AutoMemoryTools 这种跨会话长期记忆方案,需要自己组合 EmbeddingStore(支持向量存储)来实现语义记忆检索,灵活,但需要写更多的样板代码(boilerplate)。

Spring AI 的优势:Spring AI 1.1+ 的 Session API 和 AutoMemoryTools 提供了更高层的抽象,两层记忆体系可以开箱即用,与 Spring Boot Advisor 链深度集成。对于已经在 Spring 生态里的团队,接入成本极低。

AutoMemoryTools 最大的创新点在于,它把记忆管理的决策权交给了 LLM 自己,而不是用代码规则决定“什么该存”。这在长期任务场景下效果明显更好——因为 LLM 能理解语义层面的重要性,这是代码规则做不到的。

LangChain4j 的优势:运行时内存占用更小(Quarkus 下 50-100MB vs Spring Boot 的 150-300MB)。如果 Agent 跑在资源受限的环境,这是个明显的优势。模型提供商的支持面也更广,有些小众或私有部署模型只有 LangChain4j 有适配。

坦白说,到了 2026 年,两个框架都进入了 1.x 阶段,功能差距正在收窄。选型的核心还是生态适配:用 Spring Boot 的就选 Spring AI,用 Quarkus 的就选 LangChain4j,不必强行跨栈。

把两层记忆接在一起:完整 Agent 示例

下面是一个将 Session API 和 AutoMemoryTools 都接上的完整示例,可以直接运行:

// 前置条件:Spring AI 1.1+,spring-ai-agent-utils// 依赖:// spring-ai-starter-model-openai (或其他模型)// spring-ai-session-jdbc// spring-ai-agent-utils (社区库)@Configurationpublic class AgentConfig {@Beanpublic ChatClient agentChatClient(ChatModel chatModel,SessionService sessionService) {return ChatClient.builder(chatModel).defaultSystem("""你是一个有记忆的 AI 助手。你能记住用户的偏好、项目背景和历史交互。在回答问题之前,主动检查是否有相关记忆需要加载。当用户纠正你或透露新的偏好时,主动保存到长期记忆。""").defaultAdvisors(// 长期记忆层:AutoMemoryTools(跨会话持久化)AutoMemoryToolsAdvisor.builder().memoriesDir(System.getProperty("user.home") + "/.agent/memories").build(),// 短期记忆层:Session API(当前会话 + 上下文压缩)SessionMemoryAdvisor.builder(sessionService).defaultUserId("demo-user").compactionTrigger(new TurnCountTrigger(15)).compactionStrategy(RecursiveSummarizationStrategy.builder().summarizationModel(chatModel).build()).build(),// 工具调用执行器ToolCallAdvisor.builder().disableInternalConversationHistory().build()).build();}}@RestController@RequestMapping("/api/agent")public class AgentController {private final ChatClient agentChatClient;@PostMapping("/chat")public String chat(@RequestParam String userId, @RequestParam String message) {return agentChatClient.prompt().user(message)// Session API 通过 AdvisorContext 传递用户 ID.advisorParam(SessionMemoryAdvisor.USER_ID_PARAM, userId).call().content();}}

关键点说明:

  1. AutoMemoryToolsAdvisor 必须放在 SessionMemoryAdvisor 之前,因为长期记忆的系统提示词需要在短期记忆之前注入。
  2. 使用 disableInternalConversationHistory() 是为了避免 ToolCallAdvisor 自己再维护一份多余的对话历史。
  3. memoriesDir 对不同用户应该做到隔离,实际项目中建议使用 {userId} 来做子目录。

常见问题

Q:AutoMemoryTools 用的是文件系统,部署在多个 Pod 上怎么办?

A:这确实是当前社区版 AutoMemoryTools 的一个限制。在多 Pod 场景下,需要把 memoriesDir 指向一个共享存储(如 NFS、S3 挂载、云文件服务)。或者,考虑用 Redis 向量方案替代,它天然支持多节点共享。后续版本可能会提供基于 JDBC/Redis 的 AutoMemoryTools 实现。

Q:Session API 的 RecursiveSummarization 会不会把重要内容总结丢?

A:确实有这个风险,但 Session API 提供了两道保障:(1) 原始事件日志会永久保留,即使被压缩,也能通过 conversation_search 工具按关键词检索;(2) Synthetic 摘要会被标记 METADATA_SYNTHETIC,方便工程师监控摘要质量。如果业务对信息完整性要求极高,建议只使用 TurnWindow 策略,避免使用 LLM 进行摘要。

Q:AutoMemoryTools 的 6 个工具会占用多少 token?

A:工具定义本身大约需要 500-800 token(具体取决于模型如何编码 JSON schema)。每次对话开始时,还需要加载 MEMORY.md 索引,大约几十到几百 token。整体 overhead 相较于完整的对话历史来说很小,但对于对成本极度敏感的场景,可以考虑 Option B(手动接入),按需只加载特定工具。

Q:Spring AI 的 ChatMemory 和 Session API 可以同时用吗?

A:不建议同时使用。Session API 是对 ChatMemory 的替代,而非补充。两者都接会导致对话历史被保存两份。正确的做法是二选一:简单项目用 MessageWindowChatMemoryMessageChatMemoryAdvisor;生产项目则用 Session API 的 SessionMemoryAdvisor

Q:LangChain4j 有没有类似 AutoMemoryTools 的东西?

A:目前没有开箱即用的等价物。LangChain4j 的 AiServices 可以通过注解注入记忆,但实现长期的跨会话记忆,还需要自行组合 EmbeddingStore 和提取逻辑,代码量会显著增加。

核心判断

「AutoMemoryTools + Session API」这个组合,是目前 Ja va 生态里,Agent 记忆方面最完整的开箱即用方案。短期记忆解决了「这次对话不乱」,长期记忆确保了「下次还记得你」,两层各司其职,不存在替代关系。

在这套方案出现之前,生产环境上跑了好几个月的 Spring AI Agent,记忆层全靠各种临时方案拼凑:把偏好硬编码塞进 system prompt、每次请求先 RAG 一遍历史记录。现在有了这套 API,很多事可以交给框架来处理。

尚未解决的一个问题是 AutoMemoryTools 采用文件系统后端,对云原生多副本部署不够友好。这个可以等社区推出 JDBC 版本,或者先用 Redis 向量方案顶着。

如果身边有同事正面临 Spring AI 的 Agent 落地问题,这篇梳理可以直接分享给他,可以从源头上少走些弯路。

参考资料

  • Spring AI Agentic Patterns (Part 6): AutoMemoryTools
  • Spring AI Agentic Patterns (Part 7): Session API
  • AutoMemoryTools 官方文档
  • Agent Memory with Spring AI & Redis - Foojay
  • Spring AI Chat Memory 官方文档
免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策