侧边栏壁纸
博主头像
牧云

怀璧慎显,博识谨言。

  • 累计撰写 208 篇文章
  • 累计创建 20 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

AI Agent 的记忆机制:从原理到工程实践

秋之牧云
2026-06-26 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

本文深入解析 AI Agent 记忆机制的设计原理与工程实现,涵盖短期记忆、长期记忆、业界前沿框架以及生产环境实践经验,助你构建具备持续学习能力的智能 Agent。

一、面试考察点

在考察 Agent 记忆机制时,面试官通常会从以下四个维度进行评估:

概念分层:你是否了解业界演进出的多维分类体系?短期 / 长期 + 语义 / 情景 / 程序记忆,每种记忆的存储方式、使用时机能否讲清楚?

工程落地:能否独立设计可扩展的记忆模块?存储选型(关系库 / Redis / 向量库)、上下文窗口管理(滑动窗口、Token 截断、摘要压缩)、多会话隔离等关键点是否心中有数?

框架熟练度:Spring AI 的 ChatMemory + ChatMemoryRepository、LangChain4j 的 MessageWindowChatMemory / TokenWindowChatMemory 等主流 Java 方案,是否真正实践过?

前沿意识:是否了解 mem0、Letta(前身 MemGPT)、Zep 等专门做 Agent 记忆的框架?它们解决的核心问题是什么?

二、核心答案

AI Agent 的记忆机制,本质上是在模仿人类大脑的记忆系统,让 Agent 在多轮交互、跨会话、跨用户场景下保持上下文连贯,并记住用户身份与偏好。

2.1 业界主流分类

业界从两个维度对记忆进行分类:

维度分类作用典型存储
按时效短期记忆(Short-Term / Working Memory)当前对话的上下文窗口LLM Context、Redis
长期记忆(Long-Term Memory)跨会话的持久化信息向量库、关系库、图数据库
按认知类型语义记忆(Semantic)事实、概念、用户画像结构化存储 / 向量库
情景记忆(Episodic)过去的交互事件向量库
程序记忆(Procedural)技能、SOP、工具用法系统提示词、规则库

2.2 设计思路

实际开发中设计记忆模块,核心思路可概括为九个字:分层存储、动态召回、容量治理

  • 短期记忆:管好"当前这轮对话"
  • 长期记忆:通过检索将"相关的历史信息"拉回到上下文
  • 容量治理:配合摘要压缩和遗忘机制,控制 Token 成本

一句话总结:Agent 的记忆就是把人的"工作记忆 + 长期记忆"搬进工程里,在 LLM 有限的上下文窗口和无限的对话历史之间,架一套"分层缓存 + 按需换入换出"的调度系统。

三、深度解析

3.1 Agent 记忆的整体架构

Agent 记忆的完整流转遵循双向流动机制:

  • 短期 → 长期:对话过程中,将重要信息(用户偏好、关键决策、未完成任务)沉淀到长期记忆,称为 Memory Consolidation(记忆巩固)
  • 长期 → 短期:新一轮对话开始时,根据当前问题从长期记忆中召回相关信息,塞进 LLM 上下文,本质是一次 RAG 检索

理解这个双向流动,Agent 记忆的设计就通了一大半,剩下的都是存储选型和工程细节。

3.2 短期记忆:管好当前这轮对话

短期记忆是 LLM 的"工作台",即当前上下文窗口中的内容。但 LLM 上下文窗口有上限,因此短期记忆的核心问题是:如何在有限窗口里留住最有价值的信息?

3.2.1 三种主流策略

策略做法优点缺点
滑动窗口只保留最近 N 条消息实现简单、稳定早期对话信息丢失
Token 窗口保留不超过 Token 上限的消息精确控制成本同上,且需要 Tokenizer
摘要压缩定期把旧消息压缩成摘要保留长程语义实现复杂、有信息损耗

生产环境通常采用滑动窗口 + 摘要压缩的混合策略:保留最近 20 条原始消息,再带上前 N 条的摘要,兼顾短期细节和长程语义。

3.2.2 Java 生态实践

1. LangChain4j 的 ChatMemory

LangChain4j 提供了两种主流实现:

  • MessageWindowChatMemory:基于消息条数的滑动窗口
  • TokenWindowChatMemory:基于 Token 数的滑动窗口
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.model.openai.OpenAiChatModel;

// 方式一:基于消息条数的滑动窗口(保留最近 20 条消息)
ChatMemory messageWindow = MessageWindowChatMemory.builder()
        .maxMessages(20)
        .id("user-001-session-1")  // 通过 @MemoryId 实现多用户/多会话隔离
        .build();

// 方式二:基于 Token 数的滑动窗口(更精确控制成本)
ChatMemory tokenWindow = TokenWindowChatMemory.builder()
        .maxTokens(4000, new OpenAiTokenizer("gpt-4o"))
        .id("user-001-session-1")
        .build();

// 配合 @AiService 声明式使用,框架自动管理记忆
interface Assistant {
    String chat(@MemoryId String sessionId, @UserMessage String userMessage);
}

Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(OpenAiChatModel.withApiKey("${API_KEY}"))
        .chatMemoryProvider(sessionId -> MessageWindowChatMemory.builder()
                .maxMessages(20)
                .id(sessionId)
                .build())
        .build();

关键点

  • @MemoryId多会话隔离的关键,每个用户、每个会话都有独立的记忆空间
  • chatMemoryProvider 支持按 sessionId 动态创建记忆,生产环境必须使用

2. Spring AI 的 ChatMemory + ChatMemoryRepository

Spring AI 将记忆抽象为两层:

  • ChatMemory:负责记忆的读写逻辑(增删改查消息、窗口管理)
  • ChatMemoryRepository:负责持久化存储(内存、JDBC、Redis 等多种实现)
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.Message;

// 通过 Repository 实现持久化(JDBC / Redis 等开箱即用)
ChatMemoryRepository repository = ChatMemoryRepository.builder()
        .build();  // 默认 InMemory,生产环境换 JdbcChatMemoryRepository / RedisChatMemoryRepository

// 构建 ChatMemory,指定对话窗口
ChatMemory chatMemory = MessageWindowChatMemory.builder()
        .maxMessages(20)
        .chatMemoryRepository(repository)
        .build();

// Spring AI 1.0.x 提供的官方 Starter:
// - spring-ai-starter-model-chat-memory-repository-jdbc
// - spring-ai-starter-model-chat-memory-repository-redis

Spring AI 的设计更具"Spring 味儿",通过 Starter + 自动装配,将持久化做得相当干净。生产环境推荐 JDBC + Redis 双层缓存 的搭配:Redis 扛高并发读,JDBC 兜底数据可靠性。

3.3 长期记忆:跨会话的"知识沉淀"

短期记忆解决"当前对话",但用户上周的偏好、三个月前的任务,需要长期记忆来存储。

设计长期记忆需想清楚三件事:

  1. 存什么:用户画像、历史对话片段、关键事实、决策结果
  2. 怎么存:向量库为主,关系库 / 图数据库为辅
  3. 怎么召回:向量检索 + 关键词检索(Hybrid Search)+ 重排序

3.3.1 写入侧:记忆提取

对话产生的新记忆不能无脑全存,需要让 LLM 跑一遍"记忆提取"(Memory Extraction),将高价值信息(如"用户是 Java 程序员"、"用户偏好早上 9 点推送")抽出来,结构化存储。

mem0 就是这么做的:从每轮对话里识别显著事实(salient facts),蒸馏成简洁的自然语言记忆条目。

3.3.2 读取侧:混合召回

召回时走 Hybrid Search(向量 + 关键词),再过一道 Rerank,保证塞进上下文的是最相关的记忆。

3.3.3 代码示例

基于 Spring AI 的长期记忆写入 / 检索示例:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.document.Document;
import java.util.List;

@Service
public class AgentLongTermMemoryService {

    private final VectorStore vectorStore;  // Milvus / PgVector / Redis Vector
    private final ChatClient chatClient;

    public AgentLongTermMemoryService(VectorStore vectorStore, ChatClient chatClient) {
        this.vectorStore = vectorStore;
        this.chatClient = chatClient;
    }

    /**
     * 记忆巩固:从一轮对话里提取关键事实,写入长期记忆
     * 建议用成本较低的小模型(如 GPT-4o-mini / Qwen-Turbo)
     */
    public void consolidate(String userId, String userMessage, String assistantReply) {
        String prompt = """
            从以下对话中抽取关于用户的关键事实(偏好、身份、目标、重要决策),
            每条事实一行,没有就输出 EMPTY。

            用户: %s
            助手: %s
            """.formatted(userMessage, assistantReply);

        String facts = chatClient.prompt(prompt).call().content();
        if ("EMPTY".equalsIgnoreCase(facts.trim())) return;

        // 结构化写入向量库,metadata 带上 userId 用于过滤
        Document doc = new Document(facts,
                Map.of("userId", userId, "type", "user_profile", "ts", System.currentTimeMillis()));
        vectorStore.add(List.of(doc));
    }

    /**
     * 记忆召回:根据当前问题检索相关历史记忆
     */
    public String recall(String userId, String question, int topK) {
        List<Document> docs = vectorStore.similaritySearch(
                SearchRequest.builder()
                        .query(question)
                        .topK(topK)
                        .filterExpression("userId == '" + userId + "'")  // 按用户隔离
                        .build());
        return docs.stream().map(Document::getText).collect(Collectors.joining("\n"));
    }
}

这是一个能跑的最小长期记忆闭环:抽取 → 写入 → 召回。生产环境还需补上 Rerank、TTL 过期、去重、冲突检测等治理逻辑。

3.4 业界前沿:Letta / mem0 / Zep

到 2026 年,业界已有成熟的记忆框架可直接使用:

框架核心思路适用场景
Letta(前身 MemGPT)借鉴操作系统虚拟内存 + 分页思想,记忆分层为 core / recall / archival,由 LLM 自己决定换入换出长期伴侣型 Agent、个性化助手
mem0从对话抽取事实蒸馏成简洁记忆条目,支持向量 + 图混合存储,提供 add / search / update / delete API通用记忆层,可嵌入任意 Agent
Zep时序记忆图(Temporal Knowledge Graph),擅长处理时序查询和多跳推理需要理解"上个月"、"之前提到的项目"等时间相关记忆
Cognee基于知识图谱 + 向量的混合方案,强调数据可解释性企业知识库型 Agent

这些框架指向同一趋势:Agent 记忆正从"直接塞进 Prompt"演进成"独立的记忆服务",就像当年数据库从应用内嵌走向独立中间件。

Letta 的分页思想

Letta 将 Agent 记忆类比成操作系统内存管理:

  • Core Memory(核心记忆):相当于 CPU 寄存器,永远在上下文里,存最关键的 user persona 和任务状态
  • Recall Memory(回忆记忆):相当于内存,存完整对话历史,按需检索
  • Archival Memory(归档记忆):相当于硬盘,存大量背景知识,通过向量检索按需召回

Agent 通过 function call 自己决定何时将信息从 archival 换进 core,实现"有限窗口下的无限记忆"。

3.5 生产环境设计记忆模块的 7 条经验

  1. 短期记忆用 Redis,长期记忆用向量库 —— 别把一切都塞进 MySQL,也别什么都存向量库
  2. 一定要做记忆巩固(Extraction) —— 无脑把原始对话塞进向量库是新人最容易犯的错
  3. 多会话隔离用 userId + sessionId —— @MemoryId 必须带,别让张三的对话串到李四头上
  4. 加 Rerank —— 和 RAG 一样,记忆召回也强烈建议过一道 Cross-Encoder 重排序
  5. TTL + 遗忘机制 —— 不是所有记忆都要永久保留,设计遗忘策略能让重要记忆更突出
  6. 冲突处理 —— 用户上周说喜欢 Java,这周改口喜欢 Go,要能识别并更新
  7. 记忆也要评估 —— 单独评估记忆召回的 Recall@K、记忆是否被正确更新等指标

3.6 常见踩坑:上下文爆炸

设计记忆模块时若没做好容量治理,碰到话痨用户连聊 200 轮,可能直接把 100K Token 的上下文撑爆,LLM 抛出"context length exceeded"报错。

解决思路三招

  1. 硬性兜底:用 TokenWindowChatMemory 把 Token 上限焊死
  2. 软性优化:旧消息定期做摘要压缩
  3. 分级注入:长期记忆召回的结果不直接进短期记忆,而是按优先级动态拼到 Prompt 里,超出上限就降级

四、面试高频追问

追问一:Agent 的记忆和 RAG 的知识库有什么区别?

维度RAG 知识库Agent 记忆
性质静态的、公共的动态的、个性化的
面向事实(产品手册、法规)交互历史(用户偏好、过往问题)
写入策略批量导入在线持续更新

技术实现高度相似(都是向量检索),但写入策略完全不同

追问二:怎么处理用户偏好的变更?

  • 写入时做冲突检测:新记忆和已有记忆矛盾时,用 LLM 判断是覆盖还是追加
  • 给每条记忆打时间戳和置信度,召回时优先新鲜且高置信度的
  • mem0 内置了 update 和 delete 语义,在这块做得比较到位

追问三:多 Agent 协作时记忆怎么共享?

  • Blackboard 模式:所有 Agent 读写同一份共享记忆
  • Message Passing:Agent 之间通过消息传递上下文
  • 生产环境推荐:共享长期记忆 + 各自独立的短期记忆

追问四:记忆模块怎么评估效果?

  • 端到端:用多轮对话 Benchmark(如 LoCoMo、LongMemEval)评估
  • 记忆层:单独评估记忆召回的 Recall@K、记忆更新的准确率
  • mem0 2026 年报告显示:新算法在时序查询上提升 29.6 分,多跳推理提升 23.1 分

五、常见面试变体

  • 变体一:"你会怎么设计一个能记住用户偏好的智能客服?"(场景化考察)
  • 变体二:"LangChain4j / Spring AI 里 ChatMemory 是怎么实现的?"(框架细节)
  • 变体三:"为什么需要长期记忆?直接把所有历史对话塞进 Prompt 不行吗?"(考察对上下文窗口和成本的理解)
  • 变体四:"了解 MemGPT / Letta 吗?它的核心创新是什么?"(前沿意识)

六、记忆口诀

Agent 记忆设计六字诀:"分层、召回、遗忘"

  • 分层:短期管当前,长期管历史;语义存事实,情景存事件
  • 召回:向量 + 关键词 + Rerank,三件套不能少
  • 遗忘:TTL 衰减 + 冲突覆盖,记忆不是越多越好

再记一个 Letta 的三层:"Core / Recall / Archival",对应"寄存器 / 内存 / 硬盘",往操作系统虚拟内存上一套就通了。

七、总结

Agent 的记忆机制,就是把人脑的记忆模型搬进工程里,在 LLM 有限的上下文窗口和无限的交互历史之间,架一套"分层缓存 + 按需调度"的系统。

实际开发抓住三件事:

  1. 短期记忆:用滑动窗口 + 摘要把住容量关
  2. 长期记忆:用向量库 + Extraction 做个性化沉淀
  3. 召回层:必须加 Rerank

能把 Spring AI / LangChain4j 的代码讲清楚,再顺嘴提一下 mem0 / Letta 的设计思路,这道题基本就稳了。

0

评论区