AI AinoCode AI 工具与基础设施
AI教程 8 分钟

AI Agent 的记忆到底存在哪?MemPalace vs LangGraph Checkpointer vs AutoGen Memory 深度对比

三种 Agent 记忆方案在同一组任务上的实测:短期/长期/关系记忆覆盖率、召回延迟、存储成本。附选型矩阵和搭建教程。

AinoCode 编辑部

AI Agent 记忆方案对比

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 的记忆有几个关键机制:

  1. GroupChat Messages:共享消息列表,所有 Agent 可见
  2. Termination 条件:可以控制记忆的生命周期
  3. Custom Memory:通过 register_reply 添加自定义记忆逻辑
  4. Summary 机制:长对话自动摘要,压缩上下文

实测结果

指标数值
Q1 短期精确95/100
Q2 短期语义80/100(受 summary 压缩影响)
Q3 长期持久50/100(跨 session 需要手动持久化)
Q4 关系记忆35/100(同样缺乏结构化存储)
Q5 时间线55/100(summary 会丢失时间线细节)
综合得分63/100

关键发现:AutoGen 的记忆在多 Agent 协作的短期窗口内有效。但它有一个致命缺陷:GroupChat 的消息列表没有内置的持久化层。进程重启后,所有对话历史丢失。你需要自己对接数据库。

踩坑记录

在测试中发现三个实际问题:

  1. Summary 丢失关键信息:当对话超过 max_consecutive_auto_reply 时,AutoGen 会触发 summary。但 summary 是 LLM 生成的,会丢失具体的配置参数值(比如把”超时阈值 30s”摘要成”设置了超时”)。
  2. 多 Agent 消息竞争:当 3 个以上 Agent 同时发言时,消息顺序可能不一致,导致上下文错乱。
  3. 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 10(内存中)< 1ms
Layer 215MB(ChromaDB + embedding)50-200ms
Layer 35MB(Neo4j 或 NetworkX)10-50ms

总计约 20MB/1000 轮,比 LangGraph 的纯序列化方案大 4-6 倍,但召回质量提升显著。

适用场景

  • ✅ 需要长期记忆的对话型 Agent
  • ✅ 需要跨会话知识积累的助手
  • ✅ 需要关系推理和上下文关联的任务
  • ❌ 资源受限的边缘部署
  • ❌ 只需要短期记忆的简单问答

实现复杂度

搭建成本:高。需要同时维护向量数据库和知识图谱,consolidation 引擎的 prompt 和解析逻辑需要精细调优。但一旦跑通,记忆质量是三个方案中最好的。


五、横向对比矩阵

维度LangGraph CheckpointerAutoGen MemoryMemPalace 三层
短期精确记忆⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
长期持久记忆⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
关系记忆⭐⭐⭐⭐⭐⭐⭐⭐
事件时间线⭐⭐⭐⭐⭐⭐⭐⭐⭐
多 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 的任务特征,在精确性、覆盖率、成本、复杂度四个维度上找到平衡点。