Agent Memory 进阶教程:从认知科学到 2025 年最佳实践
- 现代 Agent Memory 已从"把对话历史塞进 Context Window"演化为分层、自编辑、可演化的系统。CoALA(Sumers et al., 2023, arXiv:2309.02427)与认知科学的工作记忆 / 情景记忆 / 语义记忆 / 程序性记忆分类是当下所有设计的理论起点。
- 七大代表性工作各自代表一种范式:MemGPT(虚拟内存分页)、A-MEM(Zettelkasten 链接+演化)、Mem0/Mem0g(事实抽取+知识图)、Generative Agents(反思+记忆流)、Reflexion(口头强化)、MemoryBank(艾宾浩斯遗忘曲线)、Zep/Graphiti(双时态知识图谱)。
- LoCoMo 与 LongMemEval(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
图 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 形式化为元组:
其中 M_w 是工作记忆,M_lt 是长期记忆(三类),𝒜_i/𝒜_e 是内部/外部动作,D 是决策过程。CoALA 还把 LLM 重新定位为"probabilistic production systems"——这是与传统符号 AI 桥接的关键概念跨度。
| 类型 | 认知科学定义 | Agent 实现 | 典型存储 |
|---|---|---|---|
| Working Memory | 有限容量的活跃缓冲 | 当前 Context Window 中的对话、scratch、partial plans | Prompt 本身 |
| 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 虚拟内存的隐喻。
图 2.1 · MemGPT 三层记忆:Core(RAM)— Recall(SSD)— Archival(冷存储)。
自编辑工具(原始 paper):core_memory_append、core_memory_replace、archival_memory_insert、archival_memory_search、conversation_search、conversation_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 是一个原子笔记,包含:
c_i:原始内容 /t_i:时间戳K_i:LLM 生成的关键词集合 /G_i:tags /X_i:contextual summarye_i = encode(c_i ⊕ K_i ⊕ G_i ⊕ X_i):稠密向量L_i:指向其他笔记的链接集合
2.2.2 两个核心机制
- Link Generation:新笔记 mn 入库时,检索 top-s(默认 s=10)相似历史笔记,让 LLM 判断是否建立链接。"box" 概念允许同一笔记属于多个语义簇(突破传统目录的单层归属)。
- Memory Evolution:新笔记可触发对旧笔记的
K_j, G_j, X_j的覆盖式更新。这是论文最反直觉的设计——旧记忆的"理解"会随新经验加深。
2.2.3 LoCoMo 实验结果(GPT-4o-mini,F1 / BLEU-1)
| 方法 | Multi-Hop | Temporal | Single-Hop | Avg Tokens |
|---|---|---|---|---|
| MemoryBank | 5.00 / 4.77 | 9.68 / 6.99 | 6.61 / 5.16 | 432 |
| MemGPT | 26.65 / 17.72 | 25.52 / 19.44 | 41.04 / 34.34 | 16,977 |
| A-MEM | 27.02 / 20.09 | 45.85 / 36.67 | 44.65 / 37.06 | 2,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。
2.3 Mem0 / Mem0g:可生产部署的事实抽取记忆
arXiv:2504.19413Chhikara, Khant, Aryan, Singh, Yadav (Mem0 Inc.)2025-04
两阶段架构:
- Extraction Phase:LLM 从最近 m 条消息(默认 m=10)抽取候选事实
- 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-context | 72.90 ± 0.19% | 17.117s | 26k tokens |
| Mem0g | 68.44 ± 0.17% | 2.590s | 14k tokens |
| Mem0 | 66.88 ± 0.15% | 1.440s | 7k tokens |
| Zep | 65.99 ± 0.16% | 2.926s | ~600k tokens |
| LangMem | 58.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] 加权):
- 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 是保留率,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 时间戳。这使得"我去年的工作是什么"(时间旅行查询)与"用户当前的工作"都能精准回答。
图 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 Summarization | gpt-4-turbo | 35.3% |
| MemGPT | gpt-4-turbo | 93.4% |
| Full-conversation | gpt-4-turbo | 94.4% |
| Zep | gpt-4-turbo | 94.8% |
| Zep | gpt-4o-mini | 98.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、易调试、易备份 | 语义检索差,需要外挂 pgvector | LangGraph PostgresSaver/Store |
| 键值 + TTL | 极低延迟,自动遗忘 | 无结构化查询 | LangGraph RedisSaver/MongoDB TTL |
| 混合 | 各取所长 | 复杂度高,需要多套一致性策略 | LangGraph+pgvector+Mem0g |
3.2 检索策略
- 纯语义(cosine + top-k):简单,但忽略时序与重要性。适合知识库。
- 加权混合(Park et al.):Recency + Importance + Relevance。适合个性化助手。
- 图遍历 + 重排(Zep):语义找入口节点 → BFS 邻域 → BM25/embedding 重排融合。适合企业。
- 关键词扩展(A-MEM):LLM 抽取 Ki/Gi/Xi 一同入嵌入,变相做查询扩展。
- Namespace + 语义过滤(LangGraph store):
store.search(namespace=("memories","user-123"), query=...)——隔离与精度兼得。
3.3 记忆写入策略
写入是产品决策,不是默认行为。决定:
- 何时写:① 会话结束(Letta sleeptime agent);② token 阈值触发(LlamaIndex
chat_history_token_ratio);③ LLM 主动决定(MemGPT function calling);④ 每轮强制(Mem0 默认) - 写什么:原始消息(Zep)、抽取的事实(Mem0)、抽象笔记(A-MEM)、用户画像总结(MemoryBank)
- 如何去重 / 冲突:见 3.4
3.4 记忆更新与冲突解决
| 策略 | 代表系统 | 权衡 |
|---|---|---|
| 覆盖(LLM 决定 UPDATE/DELETE) | Mem0、A-MEM(对旧笔记的 Xj) | 简单,但丢失审计能力 |
| 标记失效(invalidated_at) | Zep、Mem0g | 可时间旅行,但存储增长 |
| 强化(基于召回频次) | MemoryBank | 仿生,但易"过拟合" |
| 不更新,只追加 | Generative Agents、Reflexion | 极简,但需更聪明的检索 |
3.5 压缩、摘要、遗忘机制
- 滑动摘要:LangChain
ConversationSummaryMemory/ConversationSummaryBufferMemory - TTL 索引:MongoDB Atlas TTL 与 LangGraph 集成("forgets" obsolete memories efficiently)
- 显式遗忘曲线:MemoryBank R = e-t/S
- 优先级截断:LlamaIndex
priority=0永久保留,priority>0按序截断
3.6 Context Window / Token Budget 管理
LlamaIndex 的新 Memory 类(2025)是当前最精细的实现:
token_limit:短期 + 长期总上限(如 40,000)chat_history_token_ratio:短期占比(默认 0.7 → 28,000)token_flush_size:每次刷出量(如 3,000)- 超限时 → 按 priority 从高到低 truncate Memory Block 内容
3.7 一致性与幻觉控制
- Source attribution:每条 memory 带 episode_id / message_id(Graphiti 强制)
- 结构化输出:Mem0 让 LLM 输出 JSON 操作,避免自由文本歧义
- read-only blocks(Letta):防止 agent 篡改组织级共享知识
- LLM-as-Judge 时强制 grounding:LongMemEval 的 abstention 维度专测"不知道就不说"
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 内,自动):
InMemorySaver、PostgresSaver、MongoDBSaver、RedisSaver、DynamoDBSaver(AWS 2025 新增)、AgentCoreMemorySaver(Bedrock 2025 新增) - Store(跨 thread 长期,显式):
InMemoryStore、PostgresStore、MongoDBStore(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)
ConversationBufferMemory、ConversationSummaryMemory、VectorStoreRetrieverMemory 已被官方建议迁移到 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 框架对比表
| 框架 | 抽象层 | 后端 | 长期记忆机制 | 易用性 | 性能 | 适用场景 |
|---|---|---|---|---|---|---|
| LangGraph | Checkpointer + Store | PG / Redis / Mongo / DynamoDB / AgentCore | 显式 put/get + 向量 + TTL | 中 | 高 | 通用 workflow,生产化最完备 |
| LlamaIndex | Memory + Blocks | SQLite/SQL + 任意 VectorStore | 自动 flush + Block + priority 截断 | 高 | 中 | RAG-heavy 应用、复合知识库 |
| Mem0 | Memory layer | Qdrant/Chroma/PG + 可选 Graph | LLM 抽取事实 + ADD/UPDATE/DELETE | 高 | 极高 | 聊天机器人、个性化 |
| Letta | Stateful Agent | PG + 向量 | Memory Blocks + Archival + Sleeptime | 中 | 中 | 持久 agent 身份、multi-agent 协调 |
| Zep | Memory Service | Neo4j(Graphiti) | 双时态知识图谱 + 图+语义+BM25 融合 | 中 | 高 | 企业知识、合规、审计、时态推理 |
第 5 章 · 完整实战:三层记忆客服 Agent
下面构建一个"完整记忆架构"的客服助手,演示 工作记忆 + 情景记忆 + 语义记忆 + 程序性记忆 的协同。技术选型:
- 工作记忆:LangGraph
MessagesState+PostgresSavercheckpointer - 情景记忆(对话级 / 时态):Zep 会话(每个 user 的对话历史 + 抽取事实 + 双时态)
- 语义记忆(用户偏好 / 产品规则):Mem0 抽取的事实
- 程序性记忆:工具集合(
retrieve_order、issue_refund、escalate)
图 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)
- 数据:50 个对话,平均 9k token,跨越约 35 个 session
- 五类问题:Single-Hop、Multi-Hop、Temporal、Open-Domain、Adversarial
- 指标:F1、BLEU-1、LLM-as-Judge
- 人类 ceiling:F1 = 87.9;GPT-4 baseline F1 = 32.1(差距巨大)
6.2 LongMemEval(Wu et al., ICLR 2025, arXiv:2410.10813)
- 500 道人工题,两个版本:LongMemEvalS(~115k token/题)与 LongMemEvalM(500 sessions,约 1.5M token/题)
- 五项核心能力:
- Information Extraction(IE)— 单点回忆
- Multi-Session Reasoning(MR)— 跨会话聚合
- Temporal Reasoning(TR)— 显式 / 隐式时间
- Knowledge Updates(KU)— 信息变更覆盖
- Abstention(ABS)— 不知道就拒答(防幻觉)
- 关键数据(LongMemEvalS):
- GPT-4o:oracle 0.870 → 0.606(30.3% 跌幅)
- Llama 3.1-70B:0.744 → 0.334(55.1% 跌幅)
- Phi-3-128k-14B:0.702 → 0.380(45.9%)
- Zep(gpt-4o):71.2%,延迟 2.58s(vs full-context 60.2% / 28.9s)
6.3 其他重要基准
- DMR(Deep Memory Retrieval,MemGPT 团队):500 多会话对话
- MemBench(Tan et al., 2025):动态评估,4 项能力
- PerLTQA:1M token 静态,语义/情景分类
- DialSim:剧本派生,~350k token,叙事自然但话题窄
- MEMTRACK(NeurIPS 2025 workshop):跨多平台、多 agent。GPT-5 仅得 60% Correctness——基准压力远未饱和
6.4 当前挑战
- 幻觉(Hallucination):即使有正确记忆,模型可能不引用或错引用。LongMemEval 的 Abstention 维度专测此——多数系统 < 40%。
- 隐私:用户记忆是 PII。GDPR/CCPA 要求"可删除"(Mem0 的
memory.delete(user_id)、Zep 的级联删除是必备 API)。 - 可扩展性:Zep 600k token 图谱 vs Mem0 7k 摘要——更丰富 = 更慢 + 更贵。需要根据 SLA 选择。
- 个性化 vs 通用:跨用户共享语义记忆易污染(用户 A 的偏好泄漏给用户 B);严格 namespace 隔离是底线。
- 长程一致性:Knowledge Updates 类问题表现普遍较差——LLM 倾向用最近事实而忽略时态。
- 评估失真:string-match 与"理解"不对齐;LLM-as-Judge 自身有偏(LoCoMo-Plus, 2026 工作就在专门攻克)。
6.5 未来方向
- 可学习的记忆控制器:用 RL 学"何时写 / 读 / 演化"(目前仍多为 hardcoded)
- 多模态记忆:LoCoMo-VQA、MemLoRA(2025-12)等是先声
- 联邦 / 端侧记忆:Apple Intelligence、Gemini Nano 趋势
- 可解释 / 可审计:Graphiti 双时态 + provenance 是雏形,合规驱动
- 认知架构融合:CoALA + Soar/ACT-R 的复兴可能产生下一波突破
第 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 通用工程基准(基于实测)
- LongMemEvalS 上 GPT-4o + Zep ≥ 0.71 是当前可达的稳健工程目标;低于 0.60 说明记忆策略需要重做(已被 full-context baseline 击败)。
- p95 延迟目标:聊天 < 2s,Agent workflow < 5s。Mem0 1.44s / Zep 2.58s / Mem0g 2.59s 都在可接受范围。
- Token 成本目标:对比 full-context(26k tokens / query),记忆系统应降到 ≤ 15k tokens(节省 ≥ 40%)。
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 进阶阅读 · 时间线
- 2023-03 · Reflexion(arXiv:2303.11366)
- 2023-04 · Generative Agents(arXiv:2304.03442)
- 2023-05 · MemoryBank(arXiv:2305.10250)
- 2023-09 · CoALA(arXiv:2309.02427,TMLR 2024)
- 2023-10 · MemGPT(arXiv:2310.08560)
- 2024-04 · Memory Survey(arXiv:2404.13501)
- 2024-10 · LongMemEval(arXiv:2410.10813,ICLR 2025)
- 2024 · LoCoMo(Maharana et al.)
- 2025-01 · Zep / Graphiti(arXiv:2501.13956)
- 2025-02 · A-MEM(arXiv:2502.12110)
- 2025-04 · Mem0 / Mem0g(arXiv:2504.19413)
本章为进阶 Agent Memory 系统的教学综述。截止 2026-05-18 的研究、API 与基准数据已尽可能更新。
反馈与勘误请通过 Issue / PR 提交。