Agent 的长短期记忆系统怎么做的?记忆怎么存?粒度是多少?怎么用?


一则或许对你有用的小广告

欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书

  • 《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于 Spring AI + Spring Boot 3.x + JDK 21...查看介绍

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...查看介绍;演示链接:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/

  • 新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍

截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观

面试考察点

  1. 概念深度:看你脑子里的记忆分类是不是还停留在 "短 = 上下文窗口、长 = 向量库" 这种老说法。2026 年业界已经普遍换成 语义 / 情景 / 程序性 的细分类,答得出来说明你一直跟着社区走。

  2. 工程落地:记忆存哪?粒度怎么选?什么时候写入、什么时候淘汰?这些是没真搭过 Agent 的人答不细的。

  3. 框架熟练度:能不能结合 LangChain4jSpring AI 这类 Java AI 框架讲清楚实现机制,而不是含糊地说一句 "用向量库"。

核心答案

先说本质:大模型本身是纯无状态的,所谓 "记忆" 全靠应用层在每次请求时把历史信息塞回 Prompt。Agent 记忆系统干的就是这件事——让 LLM 在无状态的前提下,看起来像 "记得住事" 一样。

记忆系统可以拆成两层:

层次 作用 典型实现 生命周期
短期记忆(Short-Term / Working Memory) 维持当前对话的上下文连贯 消息列表 + 窗口淘汰策略 单会话,重启即失
长期记忆(Long-Term Memory) 跨会话积累用户画像、事件、技能 向量库 + 关系库 + 记忆引擎(如 Mem0 跨会话持久化

长期记忆再往下细分,是借了认知科学的三分法:

  • 语义记忆(Semantic):事实/知识,比如 "用户偏好 Java、家有三只猫"
  • 情景记忆(Episodic):事件/经历,比如 "6 月 3 日用户申请过退款"
  • 程序性记忆(Procedural):技能/工作流,比如 "部署流程:先 build 再 push 到 staging"

深度解析

一、整体架构:先看一张全景图

Agent 长短期记忆系统架构
Agent 长短期记忆系统架构

这张图把 Agent 记忆的流转路径画出来了:

  • 短期记忆是 Agent 的工作台:每次对话的实时上下文都放这里。LLM 上下文窗口有限,即便 Claude 4.6 给到了 1M context,也不能无限往里塞,所以淘汰和压缩是必须的
  • 长期记忆是 Agent 的记忆库:会话结束后,系统从短期记忆里挑出有价值的信息写入长期记忆,下次会话再按需召回
  • 难点不在存,而在 "抽取" 和 "召回" 这两步:存什么?什么时候存?怎么召回相关的?这才是真正费脑筋的地方

二、短期记忆:窗口策略是灵魂

短期记忆看着简单,不就是把消息塞进 List 里吗?但窗口策略直接决定了对话连贯性和 Token 成本。

主流就三种策略:

策略 机制 优点 缺点
固定消息数(Message Window) 保留最近 N 条消息 实现简单 长消息容易爆 Token
固定 Token 数(Token Window) 保留最近 N 个 Token 内的消息 Token 成本可控 短消息可能切太狠
摘要窗口(Summarization) 老消息压缩成摘要 + 保留最近若干条 兼顾上下文与成本 摘要质量依赖模型

LangChain4j 里的 SummarizingTokenWindowChatMemory 就是第三种。老消息超阈值时触发 LLM 生成摘要,比单纯淘汰聪明不少。

三、长期记忆:三分天下

为什么长期记忆要拆三种?因为它们的存储方式、检索方式、更新方式都不一样。

1. 语义记忆 —— 用户画像 / 事实库

  • 存什么:用户的偏好、属性、长期有效的客观事实
  • 粒度:实体级(Entity-level)/ 事实级(Fact-level),一句话或一个 KV
  • 怎么存:向量化后存向量库(MilvusPGVectorRedis Vector),或用专门的记忆引擎如 Mem0
  • 怎么用:当前问题向量化,去检索 Top-K 相关事实,再注入 Prompt

举个例子,用户说 "我家猫又吐毛球了"。语义记忆应该抽出:{entity: "user", attribute: "has_pets", value: "cat"},下次再聊宠物话题就主动召回。

2. 情景记忆 —— 事件流水

  • 存什么:具体发生了什么事、用户做过什么操作
  • 粒度:事件级(Event-level),带时间戳
  • 怎么存:时序数据库 / 关系库(如 PostgreSQL)+ 向量索引做语义检索
  • 怎么用:用户问 "上周我跟你说过什么来着",就按时间和语义双维度召回

3. 程序性记忆 —— 工作流 / SOP

  • 存什么:用户教过 Agent 的操作流程、项目特定的处理规则
  • 粒度:规则级(Rule-level)/ 流程级(Workflow-level)
  • 怎么存:结构化规则库、代码片段、Few-shot 示例
  • 怎么用:用户说 "按上次那个流程来",就召回对应的工作流执行

四、记忆的粒度:从粗到细

面试官问 "粒度是多少",就是想听你把 存储单元的颗粒度 说清楚。下面是从粗到细的对比:

粒度 示例 适用场景 问题
会话级(Session) 整个对话历史 简单客服 信息冗余大,召回精度低
轮次级(Turn) 一问一答对 多轮对话回放 颗粒太细,噪声多
消息级(Message) 单条 ChatMessage 上下文拼接 短期记忆常用粒度
摘要级(Summary) 一段对话压缩后的一句话 长对话归档 可能丢细节
实体/事实级(Entity/Fact) "用户喜欢 Java" 语义记忆首选 抽取质量依赖 LLM
事件级(Event) 带 timestamp 的动作记录 情景记忆 需要时序存储

生产环境的黄金组合:短期记忆用消息级 + 摘要级混合,长期记忆的语义部分用实体/事实级,情景部分用事件级。这也是 Mem0 这类记忆引擎在 2026 年事实上的标准做法。

五、代码示例(LangChain4j 实现)

先用 LangChain4j 看短期记忆怎么搞:

import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.model.openai.OpenAiTokenizer;
import dev.langchain4j.service.AiServices;

// 短期记忆方案一:基于消息条数的滑动窗口
ChatMemory messageWindow = MessageWindowChatMemory.builder()
        .maxMessages(20)                                  // 保留最近 20 条消息
        .id("user-123")                                   // 按用户/会话隔离
        .build();

// 短期记忆方案二:基于 Token 数的滑动窗口(推荐,更可控)
OpenAiTokenizer tokenizer = new OpenAiTokenizer("gpt-4o");
ChatMemory tokenWindow = TokenWindowChatMemory.builder()
        .maxTokens(2000, tokenizer)                       // 控制在 2000 token 以内
        .id("user-123")
        .build();

// 组装成带记忆的 AI Service
Assistant agent = AiServices.builder(Assistant.class)
        .chatLanguageModel(model)
        .chatMemoryProvider(memoryId ->
                TokenWindowChatMemory.builder()
                        .maxTokens(2000, tokenizer)
                        .id(memoryId)
                        .build())
        .build();

关键点有两个:

  • chatMemoryProvider 会按需给每个 memoryId(通常是 userIdsessionId)开独立的记忆空间,多用户隔离就靠它
  • TokenWindowChatMemory 比按消息数更稳,生产环境推荐这种,避免几条长消息就把上下文打爆

长期记忆这块,LangChain4j 没有内置 "记忆抽取" 机制,得自己组合 VectorStore

import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.data.segment.TextSegment;

// 长期记忆:用向量库存放从对话中抽取的事实
EmbeddingStore<TextSegment> longTermMemory = new InMemoryEmbeddingStore<>();

// 每轮对话结束后,调用 LLM 抽取 "值得长期记住的事实"
public void extractAndPersist(String conversation, String userId) {
    List<String> facts = factExtractor.extract(conversation); // 自定义 Prompt 让 LLM 输出事实
    for (String fact : facts) {
        TextSegment seg = TextSegment.from("[" + userId + "] " + fact);
        embeddingStore.add(embeddingModel.embed(seg).content(), seg);
    }
}

// 下次对话开始时,按当前问题召回相关长期记忆
public List<String> recallRelevant(String query, int topK) {
    return embeddingStore.findRelevant(
            embeddingModel.embed(query).content(),
            topK
    ).matches().stream()
            .map(m -> m.embedded().text())
            .toList();
}

六、代码示例(Spring AI 实现)

Spring AI 1.x 的写法略有不同,核心是 ChatMemory + Advisor 机制:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.VectorStoreChatMemoryAdvisor;
import org.springframework.ai.vectorstore.VectorStore;

@Configuration
public class AgentMemoryConfig {

    @Bean
    public ChatMemory chatMemory() {
        // 短期记忆:窗口 20 条
        return MessageWindowChatMemory.builder()
                .maxMessages(20)
                .build();
    }

    @Bean
    public ChatClient agentClient(ChatClient.Builder builder,
                                  ChatMemory chatMemory,
                                  VectorStore vectorStore) {
        return builder
                .defaultAdvisors(
                        // 短期记忆 Advisor:自动注入对话历史
                        MessageChatMemoryAdvisor.builder(chatMemory)
                                .build(),
                        // 长期记忆 Advisor:把记忆写入向量库
                        VectorStoreChatMemoryAdvisor.builder(vectorStore)
                                .build()
                )
                .build();
    }
}

几个要点:

  • MessageChatMemoryAdvisor 负责短期记忆的自动注入和淘汰,靠 conversationId 区分不同会话
  • VectorStoreChatMemoryAdvisor 把消息持久化到向量库,适合长期记忆落地
  • 有个坑:流式响应下 VectorStoreChatMemoryAdvisor 存在已知问题(参见 Spring AI GitHub Issue #3152),生产环境要注意兜底

七、记忆的 "使用时机":别只想着存

很多人答这题只讲 "怎么存",忘了讲 什么时候用。但记忆系统的读写时机才是真正的工程精髓:

Agent 记忆读写流程时序图
Agent 记忆读写流程时序图

整个流程拆解:

  • 召回(Recall):每次回答前,用当前问题去长期记忆里语义检索 Top-K 相关条目。这一步别图省事召回一堆,3~5 条足够,多了反而稀释 Prompt
  • 写入(Write):别把每条消息都写进长期记忆,那样噪声爆炸。正确做法是会话结束或定期触发记忆抽取,让 LLM 总结出有价值的事实再入库
  • 淘汰(Eviction):长期记忆也得定期清理,过时的、错误的、低权重要淘汰。比如用户半年前喜欢的东西现在可能变了,Mem0 这类引擎会基于 "decay score" 自动降权

八、2026 年的前沿:记忆引擎成为独立赛道

最后聊聊行业趋势。2026 年 Agent 记忆领域最大的变化,是专门做记忆的引擎开始崛起,典型代表:

引擎 特点
Mem0 业界事实标准,统一管理语义/情景/程序性记忆,支持 LoCoMoLongMemEval 基准
Zep 基于时序知识图谱,擅长情景记忆
Letta(原 MemGPT) 模仿操作系统虚拟内存的思路,自动分页
Cognee 用知识图谱 + 向量做混合记忆

行业共识:记忆系统已经成了 Agent Stack 的独立一层,跟 LLM、向量库、工具调用并列。很多人把 2026 年叫作 "Agent Memory 元年"。

面试高频追问

  1. 记忆越来越多,召回精度怎么保证?

    三板斧:Rerank 重排(先召回 Top-20,再用 Cross-Encoder 精排到 Top-5)、decay 衰减(按时间和使用频率降权)、记忆合并去重(相似事实自动合并)。

  2. 怎么防止 Agent 记住 "错的事"?

    • 记忆写入前做事实校验,跟已有记忆做一致性检查
    • 提供用户纠正机制,用户说一句 "不对,我其实是..." 就触发记忆覆盖
    • 关键决策不依赖记忆,走 RAG 实时检索
  3. 长期记忆和 RAG 知识库啥区别?

    • RAG 知识库:组织级的、共享的、相对确定的文档知识
    • 长期记忆:个体级的、私有的、动态演化的个人经验
    • 一个像 "公司 Wiki",一个像 "你的私人日记"
  4. 多用户场景下记忆怎么隔离?

    每条记忆都带上 userId / sessionId 元数据,存储和检索时都按这个字段过滤。ChatMemoryProvider 里的 memoryId 就是干这个的。

常见面试变体

  • "ChatGPT 的 Memory 功能是怎么实现的?"
  • "你的 Agent 怎么记住用户的偏好?"
  • "长期记忆存什么?怎么避免噪声?"
  • "多轮对话的上下文怎么管理?爆 Token 怎么办?"
  • "讲讲 Mem0 这类记忆引擎的核心架构"

记忆口诀

短期靠窗口、长期分三类、粒度选实体、读写有时机、Rerank 保精度

一句话解释:短期记忆拼的是窗口和摘要策略,长期记忆拼的是语义/情景/程序性三分法,粒度优先选实体/事实级,写入要克制、召回要重排。

总结

Agent 记忆系统的问题,重点从来不是 "用什么数据库",而是 记忆分类、粒度选择、读写时机 这三件事。面试时按 "短期(窗口策略)→ 长期(三种类型)→ 粒度(实体级黄金组合)→ 落地(LangChain4j / Spring AI 代码)→ 趋势(Mem0 记忆引擎)" 的顺序讲下来,既有深度也有广度。收尾补一句 "记忆引擎已经成为 Agent Stack 独立一层",基本能稳住整场。