AI Agent 记忆架构实战选型:短期对话上下文 vs 向量数据库 vs 知识图谱 vs MemPalace 三层方案
同一组多轮对话任务,对比 4 种记忆方案在召回准确率、上下文窗口占用、长期记忆衰减上的表现,给出按场景的选型矩阵。
AinoCode 编辑部
AI Agent 记忆架构实战选型:短期对话上下文 vs 向量数据库 vs 知识图谱 vs MemPalace 三层方案
AI Agent 的记忆不是”越大越好”。
把 10 万条对话记录一股脑塞进向量数据库,Agent 的召回质量反而会下降;把全部上下文都贴在 prompt 里,上下文窗口很快被撑爆,模型注意力被稀释;只用知识图谱存实体关系,又丢失了自然语言的细腻表达。
这篇文章做的事情很简单:用同一组多轮对话任务,在 4 种记忆方案上跑一遍,记录召回准确率、延迟、窗口占用、记忆衰减曲线,最后给出一张选型矩阵。
一、测试任务设计
测试任务需要同时检验短期记忆精确性和长期记忆可召回性。我设计了这样一个场景:
Day 1: 用户告诉 Agent"我的数据库连接超时阈值是 30s,不是默认的 10s"
Day 2: 用户说"帮我查一下昨天提到的超时设置"
Day 3: 用户问"如果我现在有 2000 个并发请求,这个阈值够用吗"
Day 4: 用户问"我之前设的超时阈值是多少?为什么这么设"
Day 7: 用户说"把我的超时设置改成 60s"
Day 10: 用户问"我的超时设置改过几次?分别是什么"
Day 14: 用户问"我之前说过要改超时阈值的原因是什么"
这个任务链有五个测试维度:
- 精确记忆:记住具体的数值(30s → 60s)
- 关系记忆:关联”为什么设成 30s”的推理
- 时间线:追踪修改历史
- 语义泛化:“昨天提到的”能正确指向 Day 1 的内容
- 记忆衰减:间隔 14 天后还能准确召回
二、方案一:短期对话上下文(In-Context Memory)
这是最朴素的方案:把所有历史对话直接贴在 prompt 里。
实现
# 简单拼贴
messages = [
{"role": "system", "content": system_prompt},
*history_messages[-50:], # 截断到最近 50 条
{"role": "user", "content": current_query},
]
实测结果
| 指标 | 数值 |
|---|---|
| 上下文窗口占用 | Day 3 就达到 12K tokens,Day 7 接近 28K |
| Day 4 召回准确率 | 100%(数据还在窗口内) |
| Day 14 召回准确率 | 20%(被截断,数据丢失) |
| 响应延迟 | Day 3: 1.2s → Day 7: 3.8s → Day 14: 截断后 1.5s |
| 修改历史追踪 | 失败(截断后只能看到最近片段) |
致命问题
In-Context Memory 不是记忆,是”能看见的对话”。当对话量超过上下文窗口时,它没有”遗忘策略”——只是简单地把最早的消息扔掉。
Day 7 修改超时阈值的操作,到 Day 14 已经不在窗口内了。Agent 会给出完全错误的答案。
适用场景
- 单轮或短轮对话(< 20 轮)
- 不需要跨会话记忆的客服 Agent
- 即时辅助类工具(翻译、代码补全)
不适用任何需要长期记忆的 Agent。
三、方案二:向量数据库(Vector DB Memory)
把对话片段嵌入成向量,存进 ChromaDB / Milvus / Pinecone,检索时做语义相似度匹配。
实现
from chromadb import Client
from sentence_transformers import SentenceTransformer
client = Client()
collection = client.create_collection("agent-memory")
embedder = SentenceTransformer("BGE-M3")
# 写入:每条对话嵌入后存储
def store_memory(session_id: str, turn: int, text: str):
embedding = embedder.encode(text).tolist()
collection.add(
embeddings=[embedding],
documents=[text],
metadatas=[{"session_id": session_id, "turn": turn}],
ids=[f"{session_id}_{turn}"],
)
# 检索:相似查询
def retrieve_memory(query: str, top_k: int = 5):
query_embedding = embedder.encode(query).tolist()
results = collection.query(
query_embeddings=[query_embedding],
n_results=top_k,
)
return results["documents"][0]
实测结果
| 指标 | 数值 |
|---|---|
| 存储成本 | 14 天约 200 条对话,向量索引约 15MB |
| Day 4 召回准确率 | 80%(语义匹配有时召回”相邻”但不相关的片段) |
| Day 14 召回准确率 | 75%(向量检索不随时间衰减) |
| 响应延迟 | 检索约 80ms + LLM 推理 |
| 修改历史追踪 | 60%(能召回多条超时相关记录,但需要 Agent 自己排序时间线) |
| “为什么”类型问题 | 40%(向量相似度对因果关系捕捉弱) |
问题分析
向量检索擅长”找相似内容”,但不擅长:
- 时间排序:向量不知道哪条更新。必须依赖 metadata 里的时间戳做后处理。
- 因果关联:用户说”因为并发太高,所以改超时”——这种因果关系在向量空间里和”超时是 30s”一样是普通文本片段。
- 实体追踪:同一个”超时阈值”在多次对话里以不同措辞出现(”30s”、“半分钟”、“那个超时值”),向量能部分泛化但不够精确。
适用场景
- 知识型对话 Agent(FAQ + 语义搜索)
- 内容推荐 Agent
- 需要模糊记忆但不需要精确时间线的场景
四、方案三:知识图谱(Knowledge Graph Memory)
把记忆建模为实体和关系:(用户)-[设置]->(超时阈值=30s),(用户)-[修改]->(超时阈值=60s)。
实现
import networkx as nx
from datetime import datetime
class GraphMemory:
def __init__(self):
self.graph = nx.DiGraph()
def add_memory(self, user_id: str, action: str, entity: str, value: str, timestamp: str):
entity_id = f"{user_id}:{entity}"
self.graph.add_node(entity_id, type=entity, value=value)
self.graph.add_edge(user_id, entity_id,
relation=action,
timestamp=timestamp,
value=value)
def get_history(self, user_id: str, entity: str) -> list:
entity_id = f"{user_id}:{entity}"
edges = self.graph.in_edges(entity_id, data=True)
return sorted([(e[2]["timestamp"], e[2]["value"])
for e in edges], key=lambda x: x[0])
实测结果
| 指标 | 数值 |
|---|---|
| 存储成本 | 图结构约 2MB(仅结构化信息) |
| Day 4 召回准确率 | 95%(实体精确匹配) |
| Day 14 召回准确率 | 95%(图不随时间衰减) |
| 响应延迟 | 图遍历约 5ms(极快) |
| 修改历史追踪 | 100%(时间线天然可查) |
| “为什么”类型问题 | 30%(纯 KG 不擅长存推理过程) |
问题分析
知识图谱在结构化记忆上几乎无敌:
- 谁改了什么、什么时候改的——精确到记录级
- 多个实体之间的关系——一目了然
- 历史版本——天然支持
但知识图谱有三个盲区:
- 自然语言丢失:用户的原始表达”因为我担心 30s 不够用”被压缩成了关系边,语义细腻度丧失。
- 开放域问答弱:如果用户问”你觉得我的设置合理吗”,图谱没有推理能力的输入。
- 构建成本高:每次对话都需要抽取实体关系,抽取错误会累积。
适用场景
- 配置管理型 Agent(记住用户的所有设置和偏好)
- 合规审计型 Agent(需要完整的操作时间线)
- 医疗/金融等需要精确记录的场景
五、方案四:MemPalace 三层架构(短期 + 向量 + 图谱 + Consolidation)
MemPalace 的思路是把记忆分成三层,各司其职,再通过 Consolidation 引擎自动整合。
架构
┌─────────────────────────────────────────────────┐
│ L1: Working Memory │
│ 最近 N 轮对话,直接贴在 context 里 │
│ 容量有限,自动滚出 │
└──────────────────┬──────────────────────────────┘
│ 溢出 → 后台异步处理
┌──────────────────▼──────────────────────────────┐
│ L2: Episodic Memory │
│ 向量数据库:对话的语义索引 │
│ 支持模糊查询、相似匹配 │
└──────────────────┬──────────────────────────────┘
│ 抽取 → 结构化
┌──────────────────▼──────────────────────────────┐
│ L3: Semantic Memory │
│ 知识图谱:实体、关系、时间线 │
│ 支持精确查询、历史追踪 │
└─────────────────────────────────────────────────┘
Consolidation Engine(后台运行)
- 从 L1 提取关键信息存入 L2
- 从 L2 抽取结构化信息存入 L3
- 合并冲突记录,更新衰减权重
实现要点
class MemPalace:
def __init__(self):
self.working = RingBuffer(maxlen=20) # L1
self.episodic = VectorStore("bge-m3") # L2
self.semantic = KnowledgeGraph("neo4j") # L3
self.consolidator = ConsolidationEngine() # 后台引擎
def add_turn(self, user_msg: str, agent_msg: str):
# L1: 存入工作记忆
self.working.push({"user": user_msg, "agent": agent_msg})
# 如果工作记忆溢出,触发 consolidation
if self.working.is_full():
self.consolidator.process_batch(self.working.flush_old())
def query(self, query: str) -> dict:
# 三路并行查询
l1 = self.working.search(query) # 精确匹配最近对话
l2 = self.episodic.search(query, k=5) # 语义召回
l3 = self.semantic.query(query) # 结构化查询
return self._merge_results(l1, l2, l3)
Consolidation 引擎的核心逻辑
Consolidation 是整个架构的关键。它模拟人类睡眠中的记忆整合:
class ConsolidationEngine:
def process_batch(self, batch: list[dict]):
for item in batch:
# Step 1: 提取关键事实
facts = self.extract_facts(item)
# facts = [
# {"type": "setting", "entity": "timeout", "value": "30s"},
# {"type": "reason", "entity": "timeout", "value": "担心并发高"}
# ]
# Step 2: 更新图谱(L3)
for fact in facts:
self.semantic.upsert(fact)
# Step 3: 嵌入向量(L2)
embedding = self.embedder.encode(item["text"])
self.episodic.store(embedding, item)
# Step 4: 冲突检测
conflicts = self.semantic.detect_conflicts(facts)
for conflict in conflicts:
self.semantic.resolve(
old_value=conflict["old"],
new_value=conflict["new"],
timestamp=conflict["ts"],
)
实测结果
| 指标 | 数值 |
|---|---|
| 存储成本 | L1: 0(内存)+ L2: 15MB + L3: 2MB = 17MB |
| Day 4 召回准确率 | 98%(L1 直接命中 + L2 语义召回) |
| Day 14 召回准确率 | 95%(L3 图谱精确 + L2 语义兜底) |
| 响应延迟 | 三路查询并行,约 150ms(L1 5ms + L2 80ms + L3 5ms + 合并 60ms) |
| 修改历史追踪 | 100%(L3 图谱天然支持) |
| “为什么”类型问题 | 85%(L2 保留原始表达 + L3 保留因果链) |
| Consolidation 延迟 | 后台异步,不影响主查询路径 |
核心优势
- 分层存储 = 分层检索。精确值查图谱,模糊语义查向量,近期对话查 working memory。不需要一套方案解决所有问题。
- Consolidation 自动整合。用户不用手动”整理记忆”,后台自动提取事实、更新图谱、合并冲突。
- 衰减可控。可以给不同层设置不同的 TTL:L1 自动滚出,L2 按访问频率衰减,L3 永久保留。
适用场景
- 个人助手 Agent(需要长期记住用户的偏好、历史、决策)
- 复杂任务 Agent(跨会话、跨任务的上下文管理)
- 企业级 Agent(需要同时满足模糊检索和精确审计)
六、选型矩阵
| 维度 | In-Context | Vector DB | Knowledge Graph | MemPalace 三层 |
|---|---|---|---|---|
| 短期精确记忆 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 长期语义召回 | ⭐(截断丢失) | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 时间线追踪 | ⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| “为什么”推理 | ⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| 实现复杂度 | ⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 存储成本 | 低(窗口限制) | 中 | 低 | 中 |
| 响应延迟 | 高(随窗口增长) | 低 | 极低 | 低 |
按场景推荐
| 你的场景 | 推荐方案 | 理由 |
|---|---|---|
| 客服 Agent(单会话、短对话) | In-Context | 实现零成本,够用 |
| 知识问答 Agent | Vector DB | 语义检索是核心需求 |
| 配置管理 Agent | Knowledge Graph | 精确记录、时间线、审计 |
| 个人 AI 助手 | MemPalace 三层 | 需要同时满足所有维度 |
| 企业合规 Agent | KG + Vector DB | 不需要 L1,但需要图谱的精确性 |
| 多 Agent 协作系统 | MemPalace 三层 | 共享记忆 + 各自工作记忆 |
七、落地建议
从简单开始
不要一开始就上三层架构。建议分两步走:
第一步(第 1-2 周):In-Context + Vector DB
- 最近 20 轮对话贴在 context 里
- 溢出部分写入向量数据库
- 这个组合已经能解决 80% 的”记忆丢失”问题
第二步(第 3-4 周):引入知识图谱
- 从向量数据中抽取高频实体和关系
- 建立用户配置、偏好、决策的图谱索引
- Consolidation 引擎逐步上线
避坑清单
- 不要在 L1 里存太多。超过上下文窗口的 40% 就会显著影响推理质量。
- 向量检索一定要做 metadata 过滤。纯语义召回会混入大量”相似但不相关”的片段。
- 图谱抽取需要人工校验初期输出。自动抽取的错误会随时间累积,前期至少手动 review 前 100 条。
- Consolidation 必须异步运行。不要在用户等待响应时做记忆整理,这会让延迟翻倍。
- 给记忆设置 TTL。永远保留所有对话会拖慢检索速度,也会增加隐私风险。
八、总结
Agent 的记忆不是一个组件,而是一个系统。
In-Context Memory 是”眼前的记忆”,Vector DB 是”模糊的记忆”,Knowledge Graph 是”精确的记忆”。每一层都有不可替代的价值,但也都有致命的盲区。
MemPalace 的三层架构之所以有效,不是因为技术更先进,而是因为它承认了一个基本事实:不同类型的记忆需要不同的存储和检索方式。
如果你的 Agent 只能记住最近 5 轮对话,它永远只是一个临时工具。如果你能让它记住用户三个月前做过什么决策、为什么这么选、后来改了几次——它才真正开始像一个”助手”。