Agent Memory 进阶教程:从认知科学到 2025 年最佳实践

📌 TL;DR(直接给结论)
  • 现代 Agent Memory 已从"把对话历史塞进 Context Window"演化为分层、自编辑、可演化的系统。CoALA(Sumers et al., 2023, arXiv:2309.02427)与认知科学的工作记忆 / 情景记忆 / 语义记忆 / 程序性记忆分类是当下所有设计的理论起点。
  • 七大代表性工作各自代表一种范式:MemGPT(虚拟内存分页)、A-MEM(Zettelkasten 链接+演化)、Mem0/Mem0g(事实抽取+知识图)、Generative Agents(反思+记忆流)、Reflexion(口头强化)、MemoryBank(艾宾浩斯遗忘曲线)、Zep/Graphiti(双时态知识图谱)。
  • LoCoMoLongMemEval(ICLR 2025)是评测黄金标准:Mem0 在 LoCoMo 上 LLM-as-Judge=66.88%、p95 延迟 1.44s(相比 full-context 17.12s,降低 ~92%);Zep 在 DMR 上 94.8%(GPT-4-turbo)超过 MemGPT 的 93.4%;但人类 ceiling F1=87.9 vs GPT-4 baseline 32.1,记忆系统离"解决"还差得远。

本章面向进阶开发者与研究者。我们假设读者已熟悉 LLM Agent 基本概念(ReAct、tool calling、向量检索),关注的是架构权衡2024–2025 最新论文进展。全文配 SVG 图解、可折叠深入阅读、可切换代码 Tab、对比表与可运行示例。

第 1 章 · 理论基础与分类体系

1.1 Agent Memory 在 LLM Agent 系统中的位置

LLM 本质上是无状态(stateless)函数:response = f(prompt)。但一个真正的 Agent 必须跨调用保存状态、跨会话学习、跨任务复用经验。Zhang et al., 2024 在《A Survey on the Memory Mechanism of Large Language Model based Agents》(arXiv:2404.13501)中将这种能力定义为 Agent 的 self-evolving capability——这是 LLM 与 Agent 的本质区别:

"Compared with original LLMs, LLM-based agents are featured in their self-evolving capability, which is the basis for solving real-world problems that need long-term and complex agent-environment interactions. The key component to support agent-environment interactions is the memory of the agents." — Zhang et al., 2024
环境 / 用户 输入 / 反馈 LLM(Reasoning Core) prompt → action / thought Memory 子系统 读 / 写 / 演化 / 遗忘 工具 / 动作 外部世界

图 1.1 · Memory 位于 LLM 与环境之间的核心位置;每一轮决策都包含 memory 的读、写与演化。

1.2 借鉴认知科学:CoALA 的四类记忆

CoALA(Cognitive Architectures for Language Agents,Sumers et al., 2023, arXiv:2309.02427, TMLR 2024)直接借鉴 Soar 与 ACT-R 等经典认知架构,将 Agent 形式化为元组:

A = (Mw, Mlt, 𝒜i, 𝒜e, D)

其中 M_w 是工作记忆,M_lt 是长期记忆(三类),𝒜_i/𝒜_e 是内部/外部动作,D 是决策过程。CoALA 还把 LLM 重新定位为"probabilistic production systems"——这是与传统符号 AI 桥接的关键概念跨度。

类型认知科学定义Agent 实现典型存储
Working Memory有限容量的活跃缓冲当前 Context Window 中的对话、scratch、partial plansPrompt 本身
Episodic过去事件的具体经历"我上次尝试 X 时发生了…"向量库 + 时间戳
Semantic世界事实知识"水在 100°C 沸腾"、用户偏好KG / 向量库 / 文本
Procedural技能与过程性知识工具定义、Voyager 的可执行代码、prompt 模板代码仓库 / Skills lib
💡 深入:CoALA 对 Action Space 的拆分

CoALA 把内部动作进一步分解为:Reasoning(用 LLM 更新 Working Memory)、Retrieval(从 Long-term 读)、Learning(写入 Long-term)。MemGPT 的 archival_memory_search 是 Retrieval,archival_memory_insert 是 Learning,core_memory_append 同时跨越两者。这种正交分解让我们能清晰地评估每个工具的影响。

1.3 上下文窗口 vs 外部记忆:本质区别

维度Context Window外部 Memory
容量模型限定(GPT-4o 128k,Claude 200k,Gemini 1M+)理论无限
访问全 attention O(n²) 算力检索 O(log n) + 嵌入开销
持久化单次推理后丢失跨会话持久
成本与 token 数线性($/1M tokens)主要在嵌入 + 向量存储
控制粒度静态构建,模型自行 attend可编程读写、可审计、可删除
典型失效"Lost in the middle"检索失败、抽取不全
⚠ 长上下文不能替代记忆系统(实证)
Wu et al., 2024(LongMemEval, arXiv:2410.10813)显示 GPT-4o 在 oracle 设置下准确率 0.870,放入 ~115k token 的 LongMemEvalS 后跌至 0.606(30.3% 下降);Llama 3.1-70B 跌 55.1%;Phi-3-128k-14B 跌 45.9%。长上下文 ≠ 长期记忆

第 2 章 · 核心论文精读

2.1 MemGPT / Letta:LLM 即操作系统

arXiv:2310.08560Packer, Wooders, Lin, Fang, Patil, Gonzalez (UC Berkeley)2023

核心洞察:Context Window 就是 RAM,外部存储就是磁盘,LLM 应通过 function calling 自主"分页"——这正是 OS 虚拟内存的隐喻。

Context Window(主存 / RAM) System Instructions Core Memory(persona+human) FIFO Conv. Queue Recall Memory (对话历史 / 旧消息索引) conversation_search() Archival Memory (向量库 / 无限文档) archival_memory_insert/search() ↕ Function Calls(Self-editing) core_memory_append · core_memory_replace · archival_memory_insert · …

图 2.1 · MemGPT 三层记忆:Core(RAM)— Recall(SSD)— Archival(冷存储)。

自编辑工具(原始 paper):core_memory_appendcore_memory_replacearchival_memory_insertarchival_memory_searchconversation_searchconversation_search_date

Letta(产品化):MemGPT 项目已并入 Letta(Packer 等创办的公司)。最关键的产品抽象是 Memory Block:可命名、可共享、可只读的上下文片段——它把"持久身份"从隐式 prompt 提升为 first-class object。

🔍 关键创新点回顾
  • Self-editing memory:LLM 自己用工具改自己的 context,而非外部框架被动塞。
  • Heartbeat / Inner Thought:agent 在工具调用之间维护连续推理。
  • Sleeptime agent(Letta 2024+):后台 agent 异步整理 memory blocks——与 Generative Agents 的"反思"思想殊途同归。

2.2 A-MEM:Zettelkasten 启发的 Agentic Memory

arXiv:2502.12110Xu, Liang, Mei, Gao, Tan, Y. Zhang(Rutgers + AIOS Foundation)2025-02

核心洞察:静态向量库不够——记忆应该像 Niklas Luhmann 的 Zettelkasten 卡片盒那样,自组织、互链接、可演化

2.2.1 Memo 节点的数学定义

每条记忆 mi 是一个原子笔记,包含:

mi = (ci, ti, Ki, Gi, Xi, ei, Li)
  • c_i:原始内容 / t_i:时间戳
  • K_i:LLM 生成的关键词集合 / G_i:tags / X_i:contextual summary
  • e_i = encode(c_i ⊕ K_i ⊕ G_i ⊕ X_i):稠密向量
  • L_i:指向其他笔记的链接集合

2.2.2 两个核心机制

  1. Link Generation:新笔记 mn 入库时,检索 top-s(默认 s=10)相似历史笔记,让 LLM 判断是否建立链接。"box" 概念允许同一笔记属于多个语义簇(突破传统目录的单层归属)。
  2. Memory Evolution:新笔记可触发对旧笔记的 K_j, G_j, X_j 的覆盖式更新。这是论文最反直觉的设计——旧记忆的"理解"会随新经验加深。

2.2.3 LoCoMo 实验结果(GPT-4o-mini,F1 / BLEU-1)

方法Multi-HopTemporalSingle-HopAvg Tokens
MemoryBank5.00 / 4.779.68 / 6.996.61 / 5.16432
MemGPT26.65 / 17.7225.52 / 19.4441.04 / 34.3416,977
A-MEM27.02 / 20.0945.85 / 36.6744.65 / 37.062,520

A-MEM 在 ~85-93% token 削减下,在 Temporal 类问题上比 MemGPT 高近 20 F1 点;每次操作约 1,200 token、< $0.0003、5.4s(GPT-4o-mini)。测了 6 个 foundation 模型:GPT-4o-mini、GPT-4o、Qwen2.5-1.5B/3B、Llama 3.2-1B/3B。

⚖ 注意:Mem0 论文中 A-MEM 跑分较低(J=48.38)是 Mem0 团队自行复现的结果,与 A-MEM 原论文表 1 不直接可比——这是跨论文 LLM-as-Judge 的固有陷阱。

2.3 Mem0 / Mem0g:可生产部署的事实抽取记忆

arXiv:2504.19413Chhikara, Khant, Aryan, Singh, Yadav (Mem0 Inc.)2025-04

两阶段架构:

  1. Extraction Phase:LLM 从最近 m 条消息(默认 m=10)抽取候选事实
  2. Update Phase:对每条候选,LLM 判定四选一操作 → ADD / UPDATE / DELETE / NOOP

Mem0g(图增强变体):用 LLM 抽取实体-关系三元组,构建有向标记图 G=(V, E, L)。冲突时不删除旧边,而是标记为 invalid——保留时序推理能力,这与 Zep 的双时态思想一致。

2.3.1 LoCoMo 上的关键数据(GPT-4o-mini)

方法J 分数(LLM-as-Judge)p95 延迟内存大小
Full-context72.90 ± 0.19%17.117s26k tokens
Mem0g68.44 ± 0.17%2.590s14k tokens
Mem066.88 ± 0.15%1.440s7k tokens
Zep65.99 ± 0.16%2.926s~600k tokens
LangMem58.10 ± 0.21%60.40s
OpenAI(内置 memory)52.90 ± 0.14%0.889s
A-Mem*(Mem0 复现)48.38 ± 0.15%4.374s

Mem0 论文的标题性结论:

"Mem0 attains a 91% lower p95 latency and saves more than 90% token cost" — Chhikara et al., 2025
"Our methods deliver 5%, 11%, and 7% relative improvements in single-hop, temporal, and multi-hop reasoning question types over best performing methods" — Mem0 §5

2.4 Generative Agents:反思(Reflection)与记忆流

arXiv:2304.03442Park, O'Brien, Cai, Morris, Liang, Bernstein(Stanford/Google)UIST 2023

Memory Stream:每条记忆 = (自然语言描述, creation_time, last_access_time)。

检索得分公式(三项归一化到 [0,1] 加权):

score = αr·Recency + αi·Importance + αe·Relevance
  • Recency:指数衰减 0.99Δt(以小时为单位,自上次访问起)
  • Importance:让 LLM 输出 1–10 整数分(prompt 提示"区分平凡如刷牙与重要如分手")
  • Relevance:query embedding 与记忆 embedding 的 cosine similarity

Reflection 触发:当最近事件 importance 总和超过阈值 150 时触发,论文中代理每天反思 2-3 次。引用原文(Park et al., 2023, arXiv:2304.03442):

"Periodic Trigger: Reflection occurs when the importance score of recent observations exceeds a set threshold (150)."

反思过程:从最近 100 条记忆中让 LLM 提出 3 个高层问题 → 对每个问题再做检索 → 让 LLM 综合出 5 条更抽象的 insight → 写回 Memory Stream(可被再检索)。

2.5 Reflexion:把"反思"当作可学习的 Episodic Memory

arXiv:2303.11366Shinn, Cassano, Berman, Gopinath, Narasimhan, YaoNeurIPS 2023

不更新权重,而把环境反馈转成自然语言"自我反思",写入 episodic memory buffer,下一轮作为 context——作者称之为 verbal reinforcement learning。三个 LLM 角色:

  • Actor M_a:执行任务(可以是 ReAct、CoT)
  • Evaluator M_e:scalar 或自然语言打分
  • Self-Reflection M_sr:把失败痕迹转为可操作的改进文本

原文报道的关键成绩(arXiv:2303.11366):

"Reflexion achieves a 91% pass@1 accuracy on the HumanEval coding benchmark, surpassing the previous state-of-the-art GPT-4 that achieves 80%."

2.6 MemoryBank:艾宾浩斯遗忘曲线

arXiv:2305.10250Zhong, Guo, Tang, Wang, Wang(Sun Yat-sen)AAAI 2024

三大模块:(1) memory storage(对话 + 事件总结 + 用户画像);(2) memory retriever(相似度);(3) memory updater。后者是论文核心创新:基于艾宾浩斯遗忘曲线

R = e-t/S

其中 R 是保留率,t 是时间,S 是 memory strength。每次成功召回会增加 S(模拟"复习"),低 R 的记忆会被遗忘或弱化。整套思路被植入 SiliconFriend——一个长期 AI 陪伴 agent。

2.7 Zep / Graphiti:双时态(Bi-temporal)知识图谱

arXiv:2501.13956Rasmussen, Paliychuk, Chalef, Rodriguez, Kucherawy(Zep AI)2025-01

Zep 的核心引擎 Graphiti 实现 bi-temporal model:每条边显式记录两个时间区间——

  • (t_valid_start, t_valid_end):事实在真实世界有效的区间
  • (t_ingested, t_invalidated):系统知道这个事实的区间

当新信息与旧事实冲突,旧边不会被删除,而是被打上 t_invalidated 时间戳。这使得"我去年的工作是什么"(时间旅行查询)与"用户当前的工作"都能精准回答。

Episode Subgraph(原始消息 / 业务数据) 每条对话或文档作为一个 episode 节点 Semantic Entity Subgraph(实体 + 关系 + 双时态) LLM 抽取出 Alice—works_at→Acme[valid: 2023-01..2024-08, invalid: 2024-08] Community Subgraph(社区 / 摘要) 类似 GraphRAG 的层次社区摘要,用于全局问答

图 2.2 · Graphiti 的三层子图架构。

2.7.1 DMR 基准结果(MemGPT 团队设立)

DMR 数据集:恰好 500 条多会话对话,每条含 5 个 chat session、每 session 最多 12 条消息(per Rasmussen et al., 2025, arXiv:2501.13956)。

方法Model准确率
Recursive Summarizationgpt-4-turbo35.3%
MemGPTgpt-4-turbo93.4%
Full-conversationgpt-4-turbo94.4%
Zepgpt-4-turbo94.8%
Zepgpt-4o-mini98.2%

2.7.2 LongMemEval 上的关键数据(gpt-4o)

Zep 将延迟从 28.9s 降至 2.58s(约 91% 降幅),准确率从 60.2% 提升至 71.2%(+11pp,原文宣称综合改善 18.5pp)。引用原文:

"accuracy improvements of up to 18.5% while simultaneously reducing response latency by 90% compared to baseline implementations." — Rasmussen et al., 2025

第 3 章 · 架构设计权衡(深度讨论)

3.1 存储后端

后端优势劣势代表系统
向量数据库语义检索强,易水平扩展弱关系建模,无显式时序Mem0、A-MEM、Letta archival
知识图谱多跳推理,显式时态,可审计抽取成本高,Schema 蔓延,延迟更高Zep/Graphiti、Mem0g
关系数据库ACID、易调试、易备份语义检索差,需要外挂 pgvectorLangGraph PostgresSaver/Store
键值 + TTL极低延迟,自动遗忘无结构化查询LangGraph RedisSaver/MongoDB TTL
混合各取所长复杂度高,需要多套一致性策略LangGraph+pgvector+Mem0g
📊 真实尺寸权衡:Mem0 论文报告 Zep 的内存图谱在 LoCoMo 上占用 ~600k tokens,Mem0 仅 7k tokens,Mem0g 14k tokens,full-context ~26k tokens——存储成本差异 ~85×。但 Zep 在 open-domain 类别上的 J 分数最高(76.60)。没有免费午餐:更丰富的图谱 = 更高的写入成本 + 更长的检索路径。

3.2 检索策略

3.3 记忆写入策略

写入是产品决策,不是默认行为。决定:

  1. 何时写:① 会话结束(Letta sleeptime agent);② token 阈值触发(LlamaIndex chat_history_token_ratio);③ LLM 主动决定(MemGPT function calling);④ 每轮强制(Mem0 默认)
  2. 写什么:原始消息(Zep)、抽取的事实(Mem0)、抽象笔记(A-MEM)、用户画像总结(MemoryBank)
  3. 如何去重 / 冲突:见 3.4

3.4 记忆更新与冲突解决

策略代表系统权衡
覆盖(LLM 决定 UPDATE/DELETE)Mem0、A-MEM(对旧笔记的 Xj)简单,但丢失审计能力
标记失效(invalidated_at)Zep、Mem0g可时间旅行,但存储增长
强化(基于召回频次)MemoryBank仿生,但易"过拟合"
不更新,只追加Generative Agents、Reflexion极简,但需更聪明的检索

3.5 压缩、摘要、遗忘机制

3.6 Context Window / Token Budget 管理

LlamaIndex 的新 Memory 类(2025)是当前最精细的实现:

3.7 一致性与幻觉控制

3.8 多 Agent:共享 vs 私有记忆

Letta 的 shared memory blocks 是典型设计——多个 agent 通过 block_ids 引用同一块,写入即时对所有 agent 可见。这把 memory block 提升为 multi-agent 协调的 primitive,而非单纯存储。例:supervisor + worker 共享 organization block,但各自有独立 persona

第 4 章 · 主流框架实战代码

4.1 LangChain / LangGraph Memory(2025 最新)

LangGraph 把记忆明确分为两层:

  • Checkpointer(thread 内,自动):InMemorySaverPostgresSaverMongoDBSaverRedisSaverDynamoDBSaver(AWS 2025 新增)、AgentCoreMemorySaver(Bedrock 2025 新增)
  • Store(跨 thread 长期,显式):InMemoryStorePostgresStoreMongoDBStore(2025-08 GA)、RedisStore——以 namespace + key + JSON value 组织,支持向量搜索与 TTL
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.store.postgres import PostgresStore
from langgraph.graph import StateGraph, MessagesState, START
from langchain.chat_models import init_chat_model
import uuid

DB_URI = "postgresql://user:pass@localhost:5432/lg"
model = init_chat_model("openai:gpt-4o-mini")

def call_model(state: MessagesState, *, store):
    user_ns = ("memories", "user-123")
    # 检索相关长期记忆
    items = store.search(user_ns, query=state["messages"][-1].content, limit=3)
    ctx = "\n".join(f"- {item.value['data']}" for item in items)
    sys = f"You are a helpful assistant. User info:\n{ctx}"
    resp = model.invoke([{"role": "system", "content": sys}, *state["messages"]])
    # 写入新记忆(此处简化为关键词触发,生产中用 LLM 抽取)
    last = state["messages"][-1].content
    if "remember" in last.lower():
        store.put(user_ns, str(uuid.uuid4()), {"data": last})
    return {"messages": resp}

with (PostgresStore.from_conn_string(DB_URI) as store,
      PostgresSaver.from_conn_string(DB_URI) as ck):
    store.setup(); ck.setup()
    builder = StateGraph(MessagesState)
    builder.add_node(call_model)
    builder.add_edge(START, "call_model")
    graph = builder.compile(checkpointer=ck, store=store)

    config = {"configurable": {"thread_id": "t1", "user_id": "user-123"}}
    graph.invoke({"messages": [{"role": "user",
                  "content": "Remember: my favorite IDE is Cursor."}]}, config)
📌 LangChain 旧 API → LangGraph 迁移:ConversationBufferMemoryConversationSummaryMemoryVectorStoreRetrieverMemory 已被官方建议迁移到 LangGraph 的 checkpointer + store 组合(LangChain 1.0 起为推荐方式)。

4.2 LlamaIndex Memory(Memory Block 新抽象)

LlamaIndex 在 2025 推出新的 Memory 类,核心抽象是 Memory Block——可插拔的长期记忆模块。三种预置:

  • StaticMemoryBlock:不变的核心信息(persona)
  • FactExtractionMemoryBlock:LLM 抽取事实,带 max_facts 自动摘要
  • VectorMemoryBlock:把 flushed 对话写入向量库(Qdrant/Chroma/Weaviate/Milvus)
from llama_index.core.memory import (
    Memory, StaticMemoryBlock, FactExtractionMemoryBlock, VectorMemoryBlock)
from llama_index.llms.openai import OpenAI
from llama_index.vector_stores.qdrant import QdrantVectorStore
from llama_index.embeddings.openai import OpenAIEmbedding

llm = OpenAI(model="gpt-4o-mini")
emb = OpenAIEmbedding(model="text-embedding-3-small")
qdrant = QdrantVectorStore(client=client, collection_name="agent_mem")

blocks = [
    StaticMemoryBlock(name="core",
        static_content="User: Alice, PM at Acme. Prefers concise replies.",
        priority=0),  # 永不被截断
    FactExtractionMemoryBlock(name="facts", llm=llm, max_facts=50, priority=1),
    VectorMemoryBlock(name="vec", vector_store=qdrant, embed_model=emb,
                      similarity_top_k=3, priority=2),
]

memory = Memory.from_defaults(
    session_id="alice_session_1",
    token_limit=40000,
    chat_history_token_ratio=0.7,   # 28k 短期 / 12k 长期
    token_flush_size=3000,
    memory_blocks=blocks,
    insert_method="system",
)

# 在 FunctionAgent 中使用
from llama_index.core.agent.workflow import FunctionAgent
agent = FunctionAgent(tools=[...], llm=llm, memory=memory)
await agent.run("我上次提到的项目截止日期是?")

4.3 Mem0

Mem0 提供两种部署:Platform(MemoryClient,托管)OSS(Memory,自托管)。OSS 默认 LLM 为 gpt-5-mini,默认 embedding 为 text-embedding-3-small

from openai import OpenAI
from mem0 import Memory

memory = Memory()  # 默认 ChromaDB + OpenAI
client = OpenAI()

def chat(msg, user_id="alice"):
    rel = memory.search(query=msg, filters={"user_id": user_id}, top_k=3)
    ctx = "\n".join(f"- {r['memory']}" for r in rel["results"])
    messages = [
        {"role": "system",
         "content": f"You are a helpful AI.\nUser Memories:\n{ctx}"},
        {"role": "user", "content": msg},
    ]
    resp = client.chat.completions.create(model="gpt-5-mini", messages=messages)
    out = resp.choices[0].message.content
    messages.append({"role": "assistant", "content": out})
    memory.add(messages, user_id=user_id)  # LLM 自动抽取事实并 ADD/UPDATE/DELETE/NOOP
    return out
from agents import Agent, Runner, function_tool, RunContextWrapper
from mem0 import MemoryClient

mem0 = MemoryClient()  # Platform 模式

@function_tool
def save_memory(ctx: RunContextWrapper, fact: str) -> str:
    mem0.add([{"role":"user","content":fact}], user_id=ctx.user_id)
    return "saved"

@function_tool
def recall_memory(ctx: RunContextWrapper, query: str) -> str:
    res = mem0.search(query=query, user_id=ctx.user_id, top_k=5)
    return "\n".join(r["memory"] for r in res["results"])

agent = Agent(name="learning_companion",
              instructions="Use save_memory/recall_memory when needed.",
              tools=[save_memory, recall_memory])
from mem0 import Memory
from anthropic import Anthropic

cfg = {"llm": {"provider": "anthropic",
               "config": {"model": "claude-3-5-sonnet-latest"}}}
memory = Memory.from_config(cfg)
claude = Anthropic()

# add / search 用法相同
memory.add([{"role":"user","content":"我吃素,坚果过敏"}], user_id="alice")
# Mem0 会自动拆成两个事实:vegetarian / allergic to nuts

4.4 Letta(原 MemGPT)

from letta_client import Letta
import os

client = Letta(api_key=os.getenv("LETTA_API_KEY"))

# 创建 Stateful Agent
agent_state = client.agents.create(
    model="openai/gpt-4o-mini",
    memory_blocks=[
        {"label": "human", "value": "Name: Alice. Role: PM."},
        {"label": "persona",
         "value": "I am a precise, helpful product assistant."},
    ],
    tools=["web_search"],          # 自定义工具
    include_base_tools=True,        # 启用 core_memory_*、archival_memory_*
)
print(agent_state.id)

# 发送消息(agent 内部自动调 core_memory_append / archival_memory_insert)
resp = client.agents.messages.create(
    agent_id=agent_state.id,
    messages=[{"role": "user",
               "content": "记一下:我最喜欢的 IDE 是 Cursor,讨厌 toast 通知。"}]
)
for m in resp.messages: print(m)

# 取出 human block 看 agent 学到什么
human = client.agents.blocks.retrieve(agent_id=agent_state.id, block_label="human")
print(human.value)
# → "Name: Alice. Role: PM. Favorite IDE: Cursor. Dislikes toast notifications."

# 共享块(multi-agent 协调原语)
org = client.blocks.create(label="organization", value="Acme Inc, PM tooling team")
supervisor = client.agents.create(
    model="openai/gpt-4o-mini",
    memory_blocks=[{"label":"persona","value":"I am supervisor"}],
    block_ids=[org.id])
worker = client.agents.create(
    model="openai/gpt-4o-mini",
    memory_blocks=[{"label":"persona","value":"I am worker"}],
    block_ids=[org.id])
# 一方写入 org block,另一方立刻可见

4.5 Zep

from zep_cloud.client import Zep
import os

zep = Zep(api_key=os.getenv("ZEP_API_KEY"))

# 1. 用户与会话
zep.user.add(user_id="alice", first_name="Alice", email="alice@acme.com")
zep.memory.add_session(session_id="s1", user_id="alice")

# 2. 追加消息(Graphiti 异步抽取实体、关系、时态)
zep.memory.add(session_id="s1", messages=[
    {"role_type": "user",
     "content": "I'm allergic to peanuts and changed jobs to Acme last month."},
    {"role_type": "assistant",
     "content": "Noted your peanut allergy and new role at Acme."},
])

# 3. 检索:语义 + BM25 + 图遍历融合,典型 < 100ms(不含 embedding API)
memory = zep.memory.get(session_id="s1")
print(memory.context)
# memory.context 包含:
#   - 最近 N 条原始消息
#   - 抽取的 facts(带 valid_at / invalid_at)
#   - 相关 entity summaries
#   - 时态推理所需的 episode 引用

# 4. 跨会话事实检索
facts = zep.memory.search_sessions(
    user_id="alice",
    text="peanut allergy",
    search_scope="facts")
for f in facts.facts:
    print(f.fact, f.valid_at, f.invalid_at)

4.6 框架对比表

框架抽象层后端长期记忆机制易用性性能适用场景
LangGraphCheckpointer + StorePG / Redis / Mongo / DynamoDB / AgentCore显式 put/get + 向量 + TTL通用 workflow,生产化最完备
LlamaIndexMemory + BlocksSQLite/SQL + 任意 VectorStore自动 flush + Block + priority 截断RAG-heavy 应用、复合知识库
Mem0Memory layerQdrant/Chroma/PG + 可选 GraphLLM 抽取事实 + ADD/UPDATE/DELETE极高聊天机器人、个性化
LettaStateful AgentPG + 向量Memory Blocks + Archival + Sleeptime持久 agent 身份、multi-agent 协调
ZepMemory ServiceNeo4j(Graphiti)双时态知识图谱 + 图+语义+BM25 融合企业知识、合规、审计、时态推理

第 5 章 · 完整实战:三层记忆客服 Agent

下面构建一个"完整记忆架构"的客服助手,演示 工作记忆 + 情景记忆 + 语义记忆 + 程序性记忆 的协同。技术选型:

① 工作记忆:LangGraph MessagesState + PostgresSaver(thread 内) ② 情景记忆:Zep 对话历史 + 双时态事实图 zep.memory.get(session_id) ③ 语义记忆:Mem0 跨会话用户偏好 mem0.search(filters={user_id:...}) ④ 程序性记忆:工具集 retrieve_order / issue_refund / escalate LLM Reasoning Core(GPT-4o-mini)

图 5.1 · 四层协同的客服 Agent 架构。

"""
三层记忆客服 Agent · 完整可运行示例
依赖:langgraph, mem0ai, zep-cloud, openai, psycopg2-binary
"""
import os, uuid
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.checkpoint.postgres import PostgresSaver
from langchain.chat_models import init_chat_model
from langchain_core.tools import tool
from mem0 import Memory
from zep_cloud.client import Zep

# --- 初始化 ---
mem0 = Memory()                                # 语义记忆:用户偏好
zep = Zep(api_key=os.getenv("ZEP_API_KEY"))    # 情景记忆:对话 + 时态事实
llm = init_chat_model("openai:gpt-4o-mini")
DB_URI = os.getenv("PG_URI")

# --- 程序性记忆:工具 ---
@tool
def retrieve_order(order_id: str) -> str:
    """根据订单号查询订单状态"""
    # 实际项目对接订单系统;此处 mock
    return f"Order {order_id}: shipped on 2026-05-10, est. delivery 2026-05-18"

@tool
def issue_refund(order_id: str, reason: str) -> str:
    """发起退款"""
    return f"Refund issued for {order_id}, reason: {reason}"

@tool
def escalate(reason: str) -> str:
    """升级到人工客服"""
    return f"Escalated. Ticket #ESC-{uuid.uuid4().hex[:6]} created. Reason: {reason}"

tools = [retrieve_order, issue_refund, escalate]
llm_with_tools = llm.bind_tools(tools)

# --- 节点 ---
def retrieve_memories(state: MessagesState, *, config):
    """① 检索情景 + 语义记忆,塞进 system message"""
    user_id = config["configurable"]["user_id"]
    session_id = config["configurable"]["thread_id"]
    last_msg = state["messages"][-1].content

    # 情景:Zep 提供本会话上下文 + 双时态相关事实
    zep_mem = zep.memory.get(session_id=session_id)
    episodic = zep_mem.context if zep_mem else ""

    # 语义:Mem0 检索用户长期偏好
    sem = mem0.search(query=last_msg, filters={"user_id": user_id}, top_k=3)
    semantic = "\n".join(f"- {r['memory']}" for r in sem.get("results", []))

    system = (
        "You are an Acme customer-support agent. Use the tools when needed. "
        "Cite memory by tag. Be concise.\n\n"
        f"\n{episodic}\n\n\n"
        f"\n{semantic}\n"
    )
    # 把 system message 注入(每轮重建,保证最新记忆)
    msgs = [m for m in state["messages"] if m.type != "system"]
    return {"messages": [{"role":"system","content":system}, *msgs]}

def call_agent(state: MessagesState):
    """② LLM 推理,可能产生工具调用"""
    resp = llm_with_tools.invoke(state["messages"])
    return {"messages": [resp]}

def write_back(state: MessagesState, *, config):
    """③ 把新一轮对话写入情景 + 语义记忆"""
    user_id = config["configurable"]["user_id"]
    session_id = config["configurable"]["thread_id"]
    # 抓取最后一轮 user + assistant
    last_two = []
    for m in reversed(state["messages"]):
        if m.type in ("human","ai") and len(last_two) < 2:
            last_two.insert(0, {"role": "user" if m.type=="human" else "assistant",
                                "content": str(m.content)})

    # 写 Mem0(会自动抽取 / 去重)
    if last_two:
        mem0.add(last_two, user_id=user_id)

    # 写 Zep(原始消息,Graphiti 异步抽取实体)
    if last_two:
        zep.memory.add(session_id=session_id,
                       messages=[{"role_type": m["role"], "content": m["content"]}
                                 for m in last_two])
    return {}

# --- 路由:有 tool_calls 则去工具节点 ---
from langgraph.prebuilt import ToolNode, tools_condition
tool_node = ToolNode(tools)

g = StateGraph(MessagesState)
g.add_node("retrieve", retrieve_memories)
g.add_node("agent", call_agent)
g.add_node("tools", tool_node)
g.add_node("write", write_back)
g.add_edge(START, "retrieve")
g.add_edge("retrieve", "agent")
g.add_conditional_edges("agent", tools_condition, {"tools":"tools", "__end__":"write"})
g.add_edge("tools", "agent")  # 工具结果回到 agent
g.add_edge("write", END)

with PostgresSaver.from_conn_string(DB_URI) as ck:
    ck.setup()
    app = g.compile(checkpointer=ck)

    # 第 1 次会话
    cfg = {"configurable": {"thread_id": "alice-2026-05-18",
                            "user_id": "alice"}}
    # 先确保 Zep 有这个 session
    try: zep.user.add(user_id="alice")
    except: pass
    try: zep.memory.add_session(session_id="alice-2026-05-18", user_id="alice")
    except: pass

    out = app.invoke({"messages":[{"role":"user",
            "content":"My order #A-9921 hasn't arrived. I always need express shipping."}]}, cfg)
    print(out["messages"][-1].content)

    # 几天后再来,新 thread,但同一 user_id → 仍能记得"always express shipping"
    cfg2 = {"configurable": {"thread_id": "alice-2026-05-25",
                             "user_id": "alice"}}
    zep.memory.add_session(session_id="alice-2026-05-25", user_id="alice")
    out = app.invoke({"messages":[{"role":"user",
            "content":"New order for product B-77, please proceed."}]}, cfg2)
    # agent 会自动检索到 "prefers express shipping" 并主动确认
    print(out["messages"][-1].content)
📌 生产化要点:
  • thread_id 隔离工作记忆(LangGraph checkpointer),user_id 跨 thread 共享语义记忆(Mem0)
  • Zep session 与 LangGraph thread 一一对应,确保情景记忆与工作记忆对齐
  • 对 PII 字段(姓名、邮箱)启用 Mem0 platform 的 entity_scoped 命名空间,或在 Zep 中用 privacy 标签
  • 每轮写入加 try/except,记忆失败不应阻断响应

第 6 章 · 评估与挑战

6.1 LoCoMo(Maharana et al., 2024)

6.2 LongMemEval(Wu et al., ICLR 2025, arXiv:2410.10813)

6.3 其他重要基准

6.4 当前挑战

  1. 幻觉(Hallucination):即使有正确记忆,模型可能不引用或错引用。LongMemEval 的 Abstention 维度专测此——多数系统 < 40%。
  2. 隐私:用户记忆是 PII。GDPR/CCPA 要求"可删除"(Mem0 的 memory.delete(user_id)、Zep 的级联删除是必备 API)。
  3. 可扩展性:Zep 600k token 图谱 vs Mem0 7k 摘要——更丰富 = 更慢 + 更贵。需要根据 SLA 选择。
  4. 个性化 vs 通用:跨用户共享语义记忆易污染(用户 A 的偏好泄漏给用户 B);严格 namespace 隔离是底线。
  5. 长程一致性:Knowledge Updates 类问题表现普遍较差——LLM 倾向用最近事实而忽略时态。
  6. 评估失真:string-match 与"理解"不对齐;LLM-as-Judge 自身有偏(LoCoMo-Plus, 2026 工作就在专门攻克)。

6.5 未来方向

第 7 章 · 决策建议与 Caveats

7.1 选型决策清单(基于 2025 数据)

场景首选理由触发更换的阈值
消费级聊天机器人 / 个人助手 Mem0 7k token 内存、p95 1.44s、Mem0 论文报告 J 分数比 OpenAI 内置 memory 提升 26% 若需要时态查询审计 → 切 Zep
企业级 / 合规 / 时态推理 Zep + Graphiti 双时态、可审计、DMR 94.8%、LongMemEval +18.5pp 若延迟成为瓶颈 (>3s p95) → 考虑混合 Mem0
需要"持久 agent 身份" Letta Memory Blocks first-class,sleeptime agent 后台整理,multi-agent 共享原语 若纯 RAG-heavy → 切 LlamaIndex
已用 LangGraph 做 workflow LangGraph Store(PG) 原生集成,checkpoint + store 分层清晰 若需自动事实抽取 → 叠加 Mem0
复合 RAG + 对话 LlamaIndex Memory Blocks priority + token budget 控制最细,自然与 LlamaIndex 检索栈衔接 若需跨 agent 共享 → 切 Letta

7.2 通用工程基准(基于实测)

7.3 Caveats(数据与方法学注意)

  • 跨论文 LLM-as-Judge 分数不可直接比较。例:Mem0 论文中 A-Mem 跑分 48.38,与 A-MEM 原论文表 1 不一致——后者由 Mem0 团队复现。
  • Zep 论文承认在 LongMemEval 评测中"无法成功跑通 MemGPT",因此不存在直接 Zep-vs-MemGPT LongMemEval 对比。
  • Generative Agents 的反思机制成本高;生产中常退化为定时摘要,而非论文中那种全文反思。
  • Mem0 默认 LLM 是 gpt-5-mini(2025 起),Mem0 原论文实验用的是 GPT-4o-mini——选型时注意。
  • 所有"减少 90% latency / token"类宣言都相对于 full-context baseline,而非相对于其他记忆系统。

7.4 进阶阅读 · 时间线

  1. 2023-03 · Reflexion(arXiv:2303.11366)
  2. 2023-04 · Generative Agents(arXiv:2304.03442)
  3. 2023-05 · MemoryBank(arXiv:2305.10250)
  4. 2023-09 · CoALA(arXiv:2309.02427,TMLR 2024)
  5. 2023-10 · MemGPT(arXiv:2310.08560)
  6. 2024-04 · Memory Survey(arXiv:2404.13501)
  7. 2024-10 · LongMemEval(arXiv:2410.10813,ICLR 2025)
  8. 2024 · LoCoMo(Maharana et al.)
  9. 2025-01 · Zep / Graphiti(arXiv:2501.13956)
  10. 2025-02 · A-MEM(arXiv:2502.12110)
  11. 2025-04 · Mem0 / Mem0g(arXiv:2504.19413)

本章为进阶 Agent Memory 系统的教学综述。截止 2026-05-18 的研究、API 与基准数据已尽可能更新。
反馈与勘误请通过 Issue / PR 提交。