Agent 记忆系统详解:从"金鱼脑"到"过目不忘"的进化之路

85 阅读12分钟

一、为什么 Agent 需要记忆?

1.1 从一个尴尬的对话说起

想象你有一个 AI 助手,对话是这样的:

你:我叫小明,是一名后端工程师,最近在学 Agent 开发。
AI:你好小明!很高兴认识你。
(—— 第二天 ——)
你:帮我推荐一些适合我的学习资料。
AI:请问您是做什么工作的呢?想学习什么方向?

是不是很崩溃?这就是没有记忆的 Agent —— 每次对话都像初次见面,用户体验极差。

1.2 LLM 的本质缺陷:无状态(Stateless)

大语言模型(LLM)本身是无状态的:它就是一个"输入文本 → 输出文本"的函数,不会自动保存任何对话历史。

graph LR
    A[User Input] --> B[LLM]
    B --> C[Output]
    C -.->|previous context lost| B

我们平时用 ChatGPT 觉得它"记得"上文,其实是应用层每次都把完整的历史对话重新拼进 Prompt 塞给模型。这就引出了记忆系统要解决的三个核心问题:

问题说明
上下文窗口有限模型一次能"看"的文本有上限(如 128K token),对话太长塞不下
成本随长度暴涨每轮都传全部历史,token 消耗是 O(n²) 级增长
跨会话失忆关掉窗口重新打开,之前聊的全没了

记忆系统的本质:在有限的上下文窗口内,让 Agent 在正确的时机"想起"正确的信息。


二、记忆的分类:借鉴人类认知科学

Agent 记忆的设计大量借鉴了认知心理学,先建立一个总体框架:

graph TB
    ROOT[Agent Memory] --> STM[Short-term Memory]
    ROOT --> LTM[Long-term Memory]
    STM --> BUF[Conversation Buffer]
    STM --> WM[Working Memory / Scratchpad]
    LTM --> EP[Episodic Memory]
    LTM --> SEM[Semantic Memory]
    LTM --> PROC[Procedural Memory]
    EP --> EP1[Historical conversations]
    EP --> EP2[Task execution traces]
    SEM --> SEM1[User profile / preferences]
    SEM --> SEM2[Domain knowledge]
    PROC --> PROC1[Skills / SOP]
    PROC --> PROC2[Rules in Prompt]

2.1 短期记忆(Short-term Memory)

是什么:当前会话内的上下文,直接放在 Prompt 里传给模型。

  • 对话缓冲区(Conversation Buffer):最近 N 轮的原始对话

  • 工作记忆(Working Memory / Scratchpad):Agent 执行任务过程中的中间思考、工具调用结果(比如 ReAct 模式里的 Thought/Action/Observation 轨迹)

特点:容量小、精度高、随会话结束而消失。

2.2 长期记忆(Long-term Memory)

是什么:持久化存储在外部(数据库/文件),跨会话存在,需要时被"检索"回来。

按内容性质细分为三类(这个分类非常重要,生产系统基本都按这个思路设计):

类型存储内容类比人类举例
情景记忆 (Episodic)发生过的具体事件"我记得上周二和他吃过饭""用户 3 月 5 日咨询过退款流程,最终选择了换货"
语义记忆 (Semantic)提炼出的事实与结论"我知道巴黎是法国首都""用户是后端工程师,偏好 Java,讨厌啰嗦的回答"
程序性记忆 (Procedural)做事的方法和技能"我会骑自行车""处理报销问题的标准流程是:先查发票→再核金额→最后提交"

一个直观的对照图:

graph TB
    subgraph ShortTerm
        BUF[Conversation Buffer]
        WM[Working Memory]
    end

    subgraph LongTerm
        EP[Episodic Memory]
        SEM[Semantic Memory]
        PROC[Procedural Memory]
    end

    ShortTerm -->|settle down| LongTerm
    LongTerm -->|retrieve and inject| ShortTerm

💡 记忆系统的核心循环就是这张图:短期记忆用完即弃,有价值的部分沉淀为长期记忆;长期记忆在合适的时机被检索回短期记忆(Prompt)中使用。


三、通用技术方案:从简单到复杂

下面按由浅入深的顺序介绍主流技术方案,每种都说明原理、优缺点和适用场景。

3.1 方案一:全量缓冲(Full Buffer)

原理:把所有历史对话原封不动拼进 Prompt。

System: 你是一个助手
User: 你好,我叫小李
Assistant: 你好小李!
User: 我想学 Agent 开发       ← 每轮都带上前面所有内容
  • ✅ 实现最简单,信息零丢失
  • ❌ 对话一长就爆上下文窗口;token 成本高
  • 适用场景:短对话场景(客服快问快答、单次任务型对话)、Demo 原型

3.2 方案二:滑动窗口(Sliding Window)

原理:只保留最近 N 轮对话,更早的直接丢弃。

graph LR
    A[Round 1] --- B[Round 2] --- C[Round 3] --- D[Round 4] --- E[Round 5]
    A -.->|discard| X[Trash]
    B -.->|discard| X

保留窗口 N=3,即只保留 Round 3/4/5,更早的丢弃。

  • ✅ 成本可控、实现简单
  • ❌ 早期关键信息会"断片"(用户开头说了姓名,10 轮后 Agent 就忘了)
  • 适用场景:话题连续性弱的闲聊、对早期信息不敏感的场景

3.3 方案三:摘要压缩(Summarization)

原理:老对话不丢弃,而是用 LLM 压缩成摘要,摘要 + 最近几轮原文一起放进 Prompt。

graph LR
    H1[Old conversations about 8000 tokens] -->|LLM compress| S[Summary about 300 tokens]
    S --> P[Final Prompt]
    R[Recent 5 rounds] --> P
    Q[Current question] --> P

常见变体:

  • 递归摘要:每次窗口快满时,把"旧摘要 + 新溢出的对话"再压缩一次
  • 分层摘要:会话级摘要 → 天级摘要 → 用户级摘要,逐层抽象
  • ✅ 兼顾成本与信息保留;对话可以"无限长"
  • ❌ 摘要有信息损耗,细节(数字、专有名词)容易丢;每次压缩多一次 LLM 调用
  • 适用场景:长对话助手、陪伴类应用、需要"大致记得聊过什么"的场景

3.4 方案四:向量检索记忆(Vector Retrieval Memory)

原理:把每条记忆做成向量(Embedding)存入向量数据库;需要时用当前问题做语义检索,只把最相关的几条记忆注入 Prompt。这是目前长期记忆的主流方案。

sequenceDiagram
    participant U as User
    participant A as Agent
    participant E as Embedding
    participant V as VectorDB

    Note over U,V: Write Phase
    U->>A: I am allergic to seafood
    A->>E: vectorize this info
    E->>V: store vector + text

    Note over U,V: Read Phase days later
    U->>A: recommend a restaurant
    A->>E: vectorize query
    E->>V: semantic search Top-K
    V-->>A: hit - user allergic to seafood
    A-->>U: recommend non-seafood restaurant
  • ✅ 记忆容量近乎无限;按需精准取用,token 高效
  • ❌ 检索质量依赖 Embedding 效果;"相关"不等于"重要";时间顺序信息弱
  • 适用场景:跨会话个性化助手、需要记住大量零散事实的场景

⚠️ 常见误区:向量检索按"语义相似度"排序,但有时最相关的记忆并不是语义最像的。生产系统通常用复合打分:得分 = 语义相似度 × 时间衰减因子 × 重要性权重(这正是斯坦福著名的 Generative Agents 小镇论文的做法)。

3.5 方案五:结构化记忆(实体/画像记忆)

原理:不存原文,而是用 LLM 从对话中抽取结构化信息,维护成一份"用户档案"或实体知识卡。

{
  "user_profile": {
    "name": "小李",
    "job": "后端工程师",
    "skills": ["Java", "Spring"],
    "learning": "Agent 开发",
    "preferences": ["回答简洁", "喜欢有代码示例"],
    "allergies": ["海鲜"]
  }
}
  • ✅ 精确、紧凑、可直接注入 System Prompt;便于人工审查和修改
  • ❌ 需要设计 Schema;抽取有出错风险;只适合"可结构化"的信息
  • 适用场景:用户画像、CRM 场景、需要稳定注入的核心事实

3.6 方案六:知识图谱记忆(Graph Memory)

原理:把记忆存成"实体—关系—实体"的图结构,能表达向量检索难以表达的关联关系。

graph LR
    XL[XiaoLi] -->|job| BE[Backend Engineer]
    XL -->|learning| AD[Agent Dev]
    XL -->|colleague| LW[LaoWang]
    LW -->|in charge of| PS[Payment System]
    AD -->|requires| LG[LangGraph]
    XL -->|allergic to| SF[Seafood]

当用户问"我同事负责的系统最近有什么问题",向量检索可能找不到,但图谱可以沿着 小李→同事→老王→负责→支付系统 的路径多跳推理。

  • ✅ 支持多跳推理、关系查询;记忆之间有结构
  • ❌ 构建和维护成本高;实体消歧困难
  • 适用场景:复杂关系场景(企业组织、人物关系)、需要推理链的记忆

3.7 方案对比总结

方案实现复杂度成本信息保真度容量典型场景
全量缓冲⭐高100%极小Demo、短对话
滑动窗口⭐低近期100%小弱连续性闲聊
摘要压缩⭐⭐中中中长对话助手
向量检索⭐⭐⭐中高(原文)极大跨会话个性化
结构化画像⭐⭐⭐中高(关键点)中用户画像
知识图谱⭐⭐⭐⭐⭐高高大复杂关系推理

💡 生产系统几乎从不单选一种,而是组合使用:滑动窗口(短期)+ 摘要(中期)+ 向量检索 & 画像(长期)是最常见的"三件套"。


四、生产级解决方案

Demo 和生产的差距,就是"能跑"和"能扛"的差距。这一节讲生产级记忆系统怎么设计。

4.1 生产级记忆系统的完整架构

graph TB
    U[User Message] --> GW[Gateway]

    subgraph ReadPath
        GW --> CTX[Context Builder]
        CTX -->|1 recent chat| REDIS[Redis ShortTerm]
        CTX -->|2 user profile| PG[PostgreSQL]
        CTX -->|3 semantic search| VDB[VectorDB]
        VDB --> RERANK[Reranker]
        RERANK --> CTX
    end

    CTX --> LLM[LLM Inference]
    LLM --> RESP[Response]

    subgraph WritePath
        LLM -.->|async| MQ[Message Queue]
        MQ --> EXT[Memory Extract Worker]
        EXT --> DEDUP[Dedup and Conflict Resolution]
        DEDUP --> PG
        DEDUP --> VDB
        EXT --> SUMM[Session Summary]
        SUMM --> REDIS
    end

    subgraph Governance
        TTL[TTL Cleanup]
        AUDIT[Memory Audit Panel]
        EVAL[Quality Evaluation]
    end
    Governance -.-> PG
    Governance -.-> VDB

几个关键设计决策:

① 读写分离:写记忆必须异步

记忆提取要调 LLM,耗时 1~3 秒。如果同步做,用户每句话都要多等几秒。正确做法:先响应用户,对话内容丢进消息队列,后台 Worker 慢慢提取记忆。

② 记忆写入不是"只增不减":CRUD 决策

新信息进来时,不能无脑追加,否则记忆库会充满矛盾("用户住北京"和"用户住上海"并存)。业界主流做法(Mem0 的核心思路)是让 LLM 对每条新事实做四选一决策:

graph LR
    NEW[New fact: user moved to Shanghai] --> SEARCH[Search similar memory]
    SEARCH --> FOUND[Existing: user lives in Beijing]
    FOUND --> DECIDE{LLM Decision}
    DECIDE -->|brand new| ADD[ADD]
    DECIDE -->|info update| UPDATE[UPDATE]
    DECIDE -->|obsolete| DELETE[DELETE]
    DECIDE -->|duplicate| NOOP[NOOP]

③ 检索不只看相似度:复合打分公式

score = w1 · 语义相似度 + w2 · 时间新近度(指数衰减) + w3 · 重要性评分 + w4 · 访问频次
  • 时间衰减:recency = e^(-λ·Δt),越久远的记忆权重越低
  • 重要性:写入时让 LLM 给记忆打 1~10 分("用户对海鲜过敏"=9 分,"用户今天说了句你好"=1 分)
  • 访问频次:常被用到的记忆更重要(模仿人脑的"越用越牢")

时间衰减

设定参数
  • 当前检索时刻:2024-05-20 14:00
  • 衰减速率 λ:设为 0.1 /小时(意味着半衰期约 6.9 小时,适合日间助理场景)
  • 公式:recency = e^(-0.1 × Δt(小时))
  • e 是自然常数(Euler's number),一个无理数,约等于 2.71828。
四条记忆的得分计算
记忆内容生成时间Δt (小时)计算过程Recency 得分直觉解读
A. "13:50 用户说把3点会议改到4点"13:500.17e^(-0.1×0.17)0.98刚刚发生,几乎满分,必须优先召回
B. "12:00 用户确认了下午2点的评审会"12:002.0e^(-0.1×2.0)0.82两小时前,仍然很新鲜
C. "昨天18:00 用户提到明天有个客户拜访"昨日18:0020.0e^(-0.1×20.0)0.14过了一天,得分骤降,但没归零
D. "上周三用户设置了每周例会提醒"7天前168.0e^(-0.1×168.0)≈ 0.000005极旧记忆,新近度维度几乎无贡献

④ 分层存储选型

层次存储TTL存什么
短期Redis会话级/小时级最近对话、会话摘要
长期-结构化PostgreSQL/MySQL长期用户画像、实体卡片
长期-语义Milvus/Qdrant/PGVector长期+衰减事实记忆向量
长期-关系Neo4j(可选)长期实体关系图
原始归档S3/OSS/数仓永久全量对话原文(合规审计用)

4.2 主流开源/商业方案对比

方案定位核心特点适合谁
Mem0记忆中间件ADD/UPDATE/DELETE 智能记忆管理,混合存储(向量+图+KV),API 简单想快速给 Agent 加上生产级长期记忆
Letta(原 MemGPT)记忆操作系统把上下文窗口当"内存"、外部存储当"磁盘",Agent 自己调用工具做记忆换页研究自主记忆管理、白盒可控
LangGraph Memory框架内置短期记忆=Checkpointer(线程内状态持久化),长期记忆=Store(跨线程 KV+语义检索)已用 LangChain/LangGraph 技术栈
Zep记忆服务时序知识图谱(Graphiti),自动构建实体关系并带时间有效性需要"何时发生了什么"的时序记忆
自研—按上面 4.1 架构搭数据敏感、深度定制需求

Letta / MemGPT 的思路值得单独一讲

它把操作系统的虚拟内存思想搬到了 LLM 上——上下文窗口 = 物理内存(小而快),外部存储 = 磁盘(大而慢),由 Agent 自己决定何时"换页":

graph TB
    subgraph MainContext
        SYS[System Prompt]
        COREMEM[Core Memory Block]
        RECENT[Recent Message Queue]
    end
    subgraph ExternalContext
        RECALL[Recall Storage]
        ARCHIVE[Archival Storage]
    end
    COREMEM -->|core_memory_replace| COREMEM
    RECENT -->|context full swapout| RECALL
    RECALL -->|conversation_search| RECENT
    ARCHIVE -->|archival_memory_search| RECENT

关键洞察:记忆管理本身也可以是 Agent 的工具调用——不是框架被动地帮 Agent 管记忆,而是 Agent 主动"决定记住什么、忘掉什么、想起什么"。

4.3 生产环境的坑与最佳实践

  1. 记忆污染:用户开玩笑说"我是奥特曼",被当成事实存了。→ 提取时加置信度评估,低置信度记忆隔离或标注。

  2. 记忆冲突:不同时间的记忆互相矛盾。→ 记忆带时间戳,冲突时"新者胜",或保留时间线(Zep 的时序图谱思路)。

  3. 隐私与合规:记忆里全是个人信息。→ 必须支持用户查看/删除自己的记忆(GDPR"被遗忘权");敏感字段脱敏存储;多租户严格隔离(记忆表必须带 user_id 分区,检索时强制过滤)。

  4. 成本控制:每轮都做记忆提取太贵。→ 批量提取(会话结束时统一处理)、用小模型做提取、先规则粗筛再 LLM 精提。

  5. 可观测性:记忆系统是黑盒会让排障噩梦。→ 记录每次"检索到了哪些记忆、注入了什么",做成可回放的 trace。

  6. 评估:上线前用 LongMemEval、LOCOMO 等长记忆基准测试;上线后监控"记忆命中率""用户纠正次数"等指标。


五、场景化选型指南

最后给一张"按场景抄作业"的决策图:

graph TD
    START{need cross-session memory?} -->|No| S1{single session long?}
    S1 -->|No| A1[Full Buffer]
    S1 -->|Yes| A2[Sliding Window + Summary]
    START -->|Yes| S2{what type of info?}
    S2 -->|fixed user attributes| A3[Structured Profile Memory]
    S2 -->|scattered facts and events| A4[Vector Retrieval Memory]
    S2 -->|complex entity relations| A5[Knowledge Graph Memory]
    S2 -->|all above + production| A6[Combined Architecture]

一句话总结各典型产品的记忆配方:

  • 智能客服:滑动窗口 + 会话摘要 +(跨会话)工单结构化记录
  • 个人助理/陪伴应用:三件套全上——画像 + 向量记忆 + 摘要,重点做好时间衰减和记忆更新
  • 代码助手:工作记忆(当前任务轨迹)+ 项目级语义记忆(代码规范、架构约定)
  • 多 Agent 系统:额外需要共享记忆(黑板模式)供 Agent 间协作

六、总结

  1. LLM 天生无状态,记忆的本质是"在有限窗口内,正确时机注入正确信息"。

  2. 记忆分短期(缓冲区、工作记忆)与长期(情景/语义/程序性),核心循环是"沉淀 ↔ 检索"。

  3. 技术方案由浅入深:全量缓冲 → 滑动窗口 → 摘要压缩 → 向量检索 → 结构化画像 → 知识图谱,生产上组合使用。

  4. 生产级系统的关键:异步写入、CRUD 式记忆管理、复合打分检索、分层存储、隐私合规、可观测可评估。

  5. 现成方案优先看 Mem0(简单通用)、Letta(自主记忆管理)、LangGraph Memory(框架原生)、Zep(时序图谱)。