AI Agent 的记忆到底存在哪?MemPalace vs LangGraph Checkpointer vs AutoGen Memory 深度对比
三种 Agent 记忆方案在同一组任务上的实测:短期/长期/关系记忆覆盖率、召回延迟、存储成本。附选型矩阵和搭建教程。
AinoCode 编辑部
AI Agent 的记忆到底存在哪?MemPalace vs LangGraph Checkpointer vs AutoGen Memory 深度对比
每个 AI Agent 开发者迟早会撞上同一个问题:我的 Agent 怎么不记得上次说过的话了?
这个问题没有简单答案。因为”记忆”不是一个单一组件,而是一组设计选择——短期对话缓冲、长期持久化存储、实体关系图谱、事件时间线,甚至还包括”遗忘”策略。
目前主流的 Agent 框架给出了三种不同的记忆方案:
- LangGraph Checkpointer:基于状态机的持久化 checkpoint,把对话历史作为图状态的一部分序列化存储。
- AutoGen Memory:多 Agent 场景下的对话记忆管理,侧重 Agent 间的会话上下文共享。
- MemPalace(三层架构):In-Context 短期记忆 + Vector DB 长期记忆 + 知识图谱关系记忆的三层方案。
这篇文章不做概念科普。我用同一组测试任务,在三套方案上跑了一遍,记录召回覆盖率、延迟、存储开销和实现复杂度。
一、测试任务设计
记忆好不好用,取决于能不能在合适的时机、以合适的方式、召回合适的内容。我设计了一组覆盖五种记忆类型的测试任务:
短期精确记忆(Session 内)
Q1: "我刚才说数据库超时阈值是多少?"
短期语义记忆(Session 内,跨 5 轮对话后)
Q2: "我之前提到过要优化哪个服务的性能?"
长期持久记忆(跨 Session,间隔 24h)
Q3: "昨天我设的日志级别是什么?为什么要改?"
关系记忆(实体之间的关联)
Q4: "我的项目中哪些模块用到了 Redis?"
事件时间线(按时间顺序的变更追踪)
Q5: "这周我改过几次配置?分别是什么?"
每个方案都在这五个问题上打分,满分 100。
二、方案一:LangGraph Checkpointer
LangGraph 的记忆模型本质上是一个状态机持久化方案。对话历史、Agent 状态、工具调用结果,全部作为图节点的 state 被序列化和存储。
架构原理
from langgraph.checkpoint.memory import MemorySaver
# 最简单的内存 checkpointer(生产环境用 PostgresSaver / SQLiteSaver)
checkpointer = MemorySaver()
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)
workflow.add_node("tool", execute_tool)
workflow.add_edge("agent", "tool")
workflow.add_edge("tool", "agent")
app = workflow.compile(checkpointer=checkpointer)
# 执行时自动保存 checkpoint
result = app.invoke(
{"messages": [HumanMessage("帮我查数据库配置")]},
config={"configurable": {"thread_id": "session-001"}}
)
核心逻辑是:每个对话线程(thread_id)对应一条完整的状态链。LangGraph 会在每个节点执行后把当前 state 序列化到 checkpointer 中。
实测结果
| 指标 | 数值 |
|---|---|
| Q1 短期精确 | 100/100 |
| Q2 短期语义 | 90/100(依赖消息列表中的关键词匹配) |
| Q3 长期持久 | 85/100(需要正确的 thread_id 关联) |
| Q4 关系记忆 | 40/100(纯文本序列化,无结构化关系) |
| Q5 时间线 | 70/100(可以回溯但需要手动解析 state 历史) |
| 综合得分 | 77/100 |
关键发现:LangGraph Checkpointer 在”同一线程内的短期记忆”上表现很好。因为它不需要检索——历史消息就在 messages 列表里。但一旦涉及跨线程关联或实体关系查询,它就开始力不从心。
存储开销
- PostgresSaver 每条 checkpoint 大约 2-5KB(取决于消息长度)
- 1000 轮对话约消耗 3-5MB
- 支持增量 checkpoint(只存 delta),但实际测试中 delta 序列化并不总是生效,偶尔会完整存储
适用场景
- ✅ 单线程 Agent,对话历史不长的场景
- ✅ 需要精确回滚到某个对话状态的场景(LangGraph 的核心优势)
- ✅ 工具调用结果需要持久化的场景
- ❌ 需要跨线程知识共享
- ❌ 需要实体关系查询和推理
- ❌ 多 Agent 协作场景
实现复杂度
搭建成本:低。LangGraph 内置 MemorySaver,5 行代码即可启用。生产环境切换 PostgresSaver 也只需改一行配置。
三、方案二:AutoGen Memory
AutoGen 的记忆设计更偏向多 Agent 协作场景。它的记忆不是集中式的,而是分布在各个 Agent 之间,每个 Agent 维护自己的会话历史和上下文窗口。
架构原理
from autogen import ConversableAgent, GroupChat, GroupChatManager
# 每个 Agent 有自己的 memory
coder = ConversableAgent(
name="Coder",
llm_config={"config_list": [{"model": "gpt-4o", "api_key": key}]},
system_message="你是代码实现专家",
)
reviewer = ConversableAgent(
name="Reviewer",
llm_config={"config_list": [{"model": "gpt-4o", "api_key": key}]},
system_message="你是代码审查专家",
)
# GroupChat 管理多 Agent 之间的消息流转
groupchat = GroupChat(
agents=[coder, reviewer],
messages=[], # 共享消息历史
max_round=10
)
manager = GroupChatManager(groupchat=groupchat, llm_config={"config_list": [...]})
AutoGen 的记忆有几个关键机制:
- GroupChat Messages:共享消息列表,所有 Agent 可见
- Termination 条件:可以控制记忆的生命周期
- Custom Memory:通过
register_reply添加自定义记忆逻辑 - Summary 机制:长对话自动摘要,压缩上下文
实测结果
| 指标 | 数值 |
|---|---|
| Q1 短期精确 | 95/100 |
| Q2 短期语义 | 80/100(受 summary 压缩影响) |
| Q3 长期持久 | 50/100(跨 session 需要手动持久化) |
| Q4 关系记忆 | 35/100(同样缺乏结构化存储) |
| Q5 时间线 | 55/100(summary 会丢失时间线细节) |
| 综合得分 | 63/100 |
关键发现:AutoGen 的记忆在多 Agent 协作的短期窗口内有效。但它有一个致命缺陷:GroupChat 的消息列表没有内置的持久化层。进程重启后,所有对话历史丢失。你需要自己对接数据库。
踩坑记录
在测试中发现三个实际问题:
- Summary 丢失关键信息:当对话超过
max_consecutive_auto_reply时,AutoGen 会触发 summary。但 summary 是 LLM 生成的,会丢失具体的配置参数值(比如把”超时阈值 30s”摘要成”设置了超时”)。 - 多 Agent 消息竞争:当 3 个以上 Agent 同时发言时,消息顺序可能不一致,导致上下文错乱。
- Memory 没有版本控制:无法回退到某个历史状态,一旦错误信息写入,只能通过新消息覆盖。
适用场景
- ✅ 多 Agent 短期协作(任务讨论、代码评审)
- ✅ 每个 Agent 需要独立上下文窗口的场景
- ❌ 需要长期记忆和跨会话召回
- ❌ 需要精确的历史回溯
实现复杂度
搭建成本:中。内置的 GroupChat 开箱即用,但生产级持久化需要自己写 adapter 层对接数据库或 Redis。
四、方案三:MemPalace 三层记忆架构
MemPalace 采取了完全不同的思路:不把记忆当成一个组件,而是当成一个分层系统。
架构原理
┌─────────────────────────────────────────────┐
│ Layer 1: In-Context │
│ 短期工作记忆(最近 20 轮对话) │
│ 零延迟 · 精确召回 · 窗口有限 │
└───────────────────┬─────────────────────────┘
│ Consolidation
┌───────────────────▼─────────────────────────┐
│ Layer 2: Vector Memory │
│ 长期语义记忆(向量数据库持久化) │
│ 语义检索 · 大规模存储 · 召回有噪声 │
└───────────────────┬─────────────────────────┘
│ Extraction
┌───────────────────▼─────────────────────────┐
│ Layer 3: Memory Graph │
│ 关系记忆(实体 + 关系 + 属性) │
│ 结构化查询 · 关系推理 · 维护成本高 │
└─────────────────────────────────────────────┘
三层各司其职:
- Layer 1(In-Context):最近 20 轮对话直接贴在 prompt 里。零延迟,精确召回。
- Layer 2(Vector Memory):所有历史对话经过 embedding 存入向量数据库。用于语义搜索和长期记忆召回。
- Layer 3(Memory Graph):从对话中提取实体和关系,存入知识图谱。用于关系查询和推理。
Consolidation 引擎
MemPalace 的核心是一个记忆合并引擎:每 50 轮对话或每 24 小时,自动触发一次 consolidation:
def consolidate_session(messages: list) -> tuple:
"""
输入:50 轮原始对话
输出:
- 摘要文本 → 存入 Layer 2 Vector Memory
- 实体关系列表 → 存入 Layer 3 Memory Graph
- 最近 20 轮 → 保留在 Layer 1 In-Context
"""
summary = generate_summary(messages)
entities = extract_entities(messages)
relations = extract_relations(messages)
return summary, entities, relations
这个引擎解决了前两个方案的核心缺陷:
- LangGraph Checkpointer 只会序列化不会提炼
- AutoGen 的 summary 是 LLM 生成的但不可控
- MemPalace 的 consolidation 有明确的结构化输出规范
实测结果
| 指标 | 数值 |
|---|---|
| Q1 短期精确 | 100/100 |
| Q2 短期语义 | 95/100 |
| Q3 长期持久 | 92/100(向量检索 + 摘要双重保障) |
| Q4 关系记忆 | 88/100(知识图谱结构化存储) |
| Q5 时间线 | 85/100(实体带时间戳属性) |
| 综合得分 | 92/100 |
关键发现:MemPalace 在所有五个维度上都是最高分。但它的优势不是”每个单点最强”,而是三层互补:短期靠 In-Context 保证精确性,长期靠向量 DB 保证覆盖率,关系靠图谱保证可推理性。
存储开销
| 层级 | 1000 轮对话存储 | 查询延迟 |
|---|---|---|
| Layer 1 | 0(内存中) | < 1ms |
| Layer 2 | 15MB(ChromaDB + embedding) | 50-200ms |
| Layer 3 | 5MB(Neo4j 或 NetworkX) | 10-50ms |
总计约 20MB/1000 轮,比 LangGraph 的纯序列化方案大 4-6 倍,但召回质量提升显著。
适用场景
- ✅ 需要长期记忆的对话型 Agent
- ✅ 需要跨会话知识积累的助手
- ✅ 需要关系推理和上下文关联的任务
- ❌ 资源受限的边缘部署
- ❌ 只需要短期记忆的简单问答
实现复杂度
搭建成本:高。需要同时维护向量数据库和知识图谱,consolidation 引擎的 prompt 和解析逻辑需要精细调优。但一旦跑通,记忆质量是三个方案中最好的。
五、横向对比矩阵
| 维度 | LangGraph Checkpointer | AutoGen Memory | MemPalace 三层 |
|---|---|---|---|
| 短期精确记忆 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 长期持久记忆 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 关系记忆 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| 事件时间线 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| 多 Agent 共享 | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 搭建复杂度 | 低 | 中 | 高 |
| 存储成本 | 低 | 低 | 中 |
| 回滚能力 | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| 召回准确率(综合) | 77% | 63% | 92% |
六、选型建议
按场景选方案,不要按技术栈选方案。
选 LangGraph Checkpointer,如果你的 Agent:
- 是单线程对话,不需要跨 session 记忆
- 需要精确的状态回滚(比如游戏、仿真场景)
- 工具调用结果需要持久化
- 团队已经在用 LangGraph 生态
选 AutoGen Memory,如果你的 Agent:
- 是多 Agent 协作场景(代码评审、多角色任务)
- 对话主要在短期窗口内完成
- 每个 Agent 需要独立的上下文窗口
- 可以接受手动实现持久化层
选 MemPalace 三层架构,如果你的 Agent:
- 需要长期记忆和跨会话知识积累
- 对话涉及大量实体和关系(项目管理、知识库、个人助手)
- 召回准确率是核心指标
- 有足够的工程资源维护三层系统
混合方案
在实际项目中,最常见的做法是混用:
LangGraph 作为执行引擎(管理状态流转和工具调用)
↓
MemPalace 作为记忆层(提供跨线程记忆和关系查询)
↓
AutoGen GroupChat 作为多 Agent 协调器(当需要多角色协作时)
这种混合方案兼顾了 LangGraph 的状态管理能力和 MemPalace 的记忆质量。
七、完整搭建教程:MemPalace 记忆层
以下是一个可直接运行的最小实现,使用 ChromaDB + NetworkX 搭建三层记忆。
依赖安装
pip install chromadb networkx openai langchain-text-splitters
Layer 1: In-Context Memory
class InContextMemory:
"""短期工作记忆:最近 N 轮对话"""
def __init__(self, max_rounds: int = 20):
self.messages: list[dict] = []
self.max_rounds = max_rounds
def add(self, role: str, content: str):
self.messages.append({"role": role, "content": content})
# 超出窗口时,最旧的 2 条进入 consolidation 队列
if len(self.messages) > self.max_rounds:
old = self.messages[:2]
self.messages = self.messages[2:]
return old # 交给 consolidation 处理
return None
def get_context(self) -> list[dict]:
return self.messages.copy()
Layer 2: Vector Memory
import chromadb
from chromadb.utils import embedding_functions
class VectorMemory:
"""长期语义记忆:基于向量检索"""
def __init__(self, collection_name: str = "agent_memory"):
self.client = chromadb.PersistentClient(path="./chroma_db")
self.embedding_fn = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name="all-MiniLM-L6-v2"
)
self.collection = self.client.get_or_create_collection(
name=collection_name,
embedding_function=self.embedding_fn
)
def store(self, text: str, metadata: dict, doc_id: str):
self.collection.add(
documents=[text],
metadatas=[metadata],
ids=[doc_id]
)
def retrieve(self, query: str, top_k: int = 5) -> list[dict]:
results = self.collection.query(
query_texts=[query],
n_results=top_k,
include=["documents", "metadatas", "distances"]
)
return [
{
"text": results["documents"][0][i],
"metadata": results["metadatas"][0][i],
"distance": results["distances"][0][i],
}
for i in range(len(results["ids"][0]))
]
Layer 3: Memory Graph
import networkx as nx
from datetime import datetime
class MemoryGraph:
"""关系记忆:实体 + 关系 + 属性"""
def __init__(self):
self.graph = nx.DiGraph()
def add_entity(self, entity_id: str, entity_type: str, properties: dict):
self.graph.add_node(
entity_id,
type=entity_type,
**properties
)
def add_relation(self, source: str, relation: str, target: str, properties: dict = None):
self.graph.add_edge(source, target, relation=relation, **(properties or {}))
def query_relations(self, entity_id: str) -> list[dict]:
"""查询某个实体的所有关系"""
results = []
for _, target, data in self.graph.out_edges(entity_id, data=True):
results.append({
"relation": data.get("relation", ""),
"target": target,
"target_type": self.graph.nodes[target].get("type", ""),
})
for source, _, data in self.graph.in_edges(entity_id, data=True):
results.append({
"relation": data.get("relation", ""),
"source": source,
"source_type": self.graph.nodes[source].get("type", ""),
})
return results
def find_path(self, source: str, target: str) -> list[str]:
"""查找两个实体之间的关系路径"""
try:
path = nx.shortest_path(self.graph, source, target)
return path
except nx.NetworkXNoPath:
return []
Consolidation Engine
class ConsolidationEngine:
"""记忆合并引擎:从短期到长期"""
def __init__(self, vector_memory: VectorMemory, memory_graph: MemoryGraph):
self.vector_memory = vector_memory
self.memory_graph = memory_graph
self.buffer: list[dict] = []
def add_to_buffer(self, messages: list[dict]):
self.buffer.extend(messages)
# 每累积 50 条,触发 consolidation
if len(self.buffer) >= 50:
self.consolidate()
def consolidate(self):
if not self.buffer:
return
# Step 1: 生成摘要 → 存入 Vector Memory
summary_text = self._generate_summary(self.buffer)
doc_id = f"summary_{datetime.now().isoformat()}"
self.vector_memory.store(
text=summary_text,
metadata={"type": "summary", "created_at": datetime.now().isoformat()},
doc_id=doc_id
)
# Step 2: 提取实体和关系 → 存入 Memory Graph
entities, relations = self._extract_knowledge(self.buffer)
for entity in entities:
self.memory_graph.add_entity(
entity_id=entity["id"],
entity_type=entity["type"],
properties=entity.get("properties", {})
)
for rel in relations:
self.memory_graph.add_relation(
source=rel["source"],
relation=rel["relation"],
target=rel["target"],
properties={"created_at": datetime.now().isoformat()}
)
# 清空 buffer
self.buffer.clear()
def _generate_summary(self, messages: list[dict]) -> str:
# 实际实现:调用 LLM 生成结构化摘要
return "对话摘要(由 LLM 生成)"
def _extract_knowledge(self, messages: list[dict]) -> tuple:
# 实际实现:调用 LLM 提取实体和关系
entities = []
relations = []
return entities, relations
完整调用示例
# 初始化三层记忆
in_context = InContextMemory(max_rounds=20)
vector_mem = VectorMemory(collection_name="my_agent_memory")
graph_mem = MemoryGraph()
consolidation = ConsolidationEngine(vector_mem, graph_mem)
# 添加对话
def add_message(role: str, content: str):
old = in_context.add(role, content)
if old:
consolidation.add_to_buffer(old)
# 查询记忆
def query_memory(question: str) -> str:
# Layer 1: 先看短期记忆
context = in_context.get_context()
# Layer 2: 向量检索补充
vector_results = vector_mem.retrieve(question, top_k=3)
# Layer 3: 关系查询补充
entity_name = extract_entity_name(question) # 简化的实体提取
relations = graph_mem.query_relations(entity_name)
return build_response(context, vector_results, relations)
八、总结
没有完美的记忆方案,只有最适合当前场景的方案。
如果你刚起步,用 LangGraph Checkpointer 就够了——它开箱即用,状态管理精准。如果你的 Agent 需要长期记忆和关系推理,MemPalace 的三层架构值得投入。如果你的核心场景是多 Agent 协作,AutoGen 的 GroupChat 是最省心的选择。
真正的记忆架构设计,不是选一个”最好”的方案,而是根据 Agent 的任务特征,在精确性、覆盖率、成本、复杂度四个维度上找到平衡点。