首页 › AI Agent › Agent100道面试题 › 记忆与状态 memory-and-state › 长期记忆存储介质选型:向量 / 结构化 / 图谱

长期记忆存储介质选型:向量 / 结构化 / 图谱

难度:中级 分类:Memory & State​

简短回答​

Agent 长期记忆有三种主要存储介质,各擅其长:(1) 向量记忆(Embedding + 向量数据库)擅长语义相似度检索,基于"意思相近"找到相关记忆,适合非结构化文本和模糊查询;(2) 结构化记忆(SQL / NoSQL)擅长精确属性查询,适合用户画像、偏好、配置等键值化数据;(3) 知识图谱(Neo4j + Graphiti 等)擅长关系推理与时间推理——支持多跳推理(A→B→C)、时间有效性追踪(事实何时变更)、实体关系网络,回答"A 的上级是谁?""这个信息何时变化?"等结构化问题。代表性的 Graphiti(Zep 出品)采用双时间线模型(事件时间 + 入库时间)+ 混合检索(语义 Embedding + 关键词 BM25 + 图遍历)。生产系统推荐混合架构——向量存对话历史和非结构化内容,图谱存事实、实体和关系,结构化存属性配置。Mem0 的混合方案实现了 26% 准确率提升和 90%+ token 成本降低。​

详细解析​

三种介质的核心区别​

​

#JxRTNbivxGhL text { white-space: pre; }#JxRTNbivxGhL .fb0 { stroke: var(--N900-FG, 0.15); }#JxRTNbivxGhL .fb0 {stroke: rgba(31,35,41, 0.15)}#JxRTNbivxGhL .fx0 { stroke-miterlimit: 10; }#JxRTNbivxGhL .fx0 {stroke-miterlimit: 10}#JxRTNbivxGhL .fa1 { fill: rgb(187, 191, 196); }#JxRTNbivxGhL .fa1 {fill: rgb(187, 191, 196)}#JxRTNbivxGhL .fx1 { font: 400 12px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }#JxRTNbivxGhL .fx1 {font-style: normal}#JxRTNbivxGhL .fx2 { text-anchor: middle; }#JxRTNbivxGhL .fx2 {text-anchor: middle}#JxRTNbivxGhL .fx3 { dominant-baseline: central; }#JxRTNbivxGhL .fx3 {dominant-baseline: central}#JxRTNbivxGhL .fx4 { stroke: none; }#JxRTNbivxGhL .fx4 {stroke: none}#JxRTNbivxGhL .fc0 { fill: var(--text-caption); }#JxRTNbivxGhL .fc0 {fill: #646a73}#JxRTNbivxGhL .fa2 { fill: var(--text-link-disabled); }#JxRTNbivxGhL .fa2 {fill: rgb(187, 191, 196)}#JxRTNbivxGhL .fx5 { font: 400 13px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }#JxRTNbivxGhL .fx5 {font-style: normal}#JxRTNbivxGhL .fx6 { text-anchor: start; }#JxRTNbivxGhL .fx6 {text-anchor: start}#JxRTNbivxGhL .fx7 { dominant-baseline: alphabetic; }#JxRTNbivxGhL .fx7 {dominant-baseline: alphabetic}#JxRTNbivxGhL .fc1 { fill: rgb(0, 0, 0); }#JxRTNbivxGhL .fc1 {fill: rgb(0, 0, 0)}#JxRTNbivxGhL .fb1 { fill: var(--N900-FG, 0.15); }#JxRTNbivxGhL .fb1 {fill: rgba(31,35,41, 0.15)}#JxRTNbivxGhL .fb2 { fill: rgb(209, 217, 224); }#JxRTNbivxGhL .fb2 {fill: rgb(209, 217, 224)}#JxRTNbivxGhL .fa3 { fill: var(--bg-body); }#JxRTNbivxGhL .fa3 {fill: #fff}ABCD1234介质向量结构化(SQL/NoSQL)知识图谱数据结构高维浮点向量表/键值/文档节点 + 边 + 属性查询能力语义相似度精确字段查询多跳推理 + 时间推理典型场景对话历史、文档检索用户画像、偏好、配置实体关系、事实追踪

​

向量记忆(Vector / Embedding-based)​

​

代码块​

Python

# 向量记忆的工作原理​

class VectorMemory:​

def store(self, text: str):​

embedding = embed_model.encode(text) # 文本 → 向量​

self.index.add(embedding, metadata={"text": text})​

​

def retrieve(self, query: str, top_k=5):​

query_vec = embed_model.encode(query)​

# 基于余弦相似度找最近邻​

results = self.index.search(query_vec, top_k)​

return results​

​

# 示例​

memory.store("用户是 Python 开发者,偏好 FastAPI")​

memory.store("上次讨论了数据库优化,使用了 PostgreSQL")​

results = memory.retrieve("推荐一个 Web 框架")​

# → 返回语义相似的记忆条目​

​

优势:​

•

语义理解:基于含义而非关键词匹配​

•

灵活性:不需要预定义 Schema​

•

对数级延迟:HNSW 索引在百万级数据上仍保持毫秒级检索​

劣势:​

•

基于相似度而非真正理解——语义相近但含义不同的内容可能被错误检索​

•

不支持关系推理("A 的上级是 B,B 的上级是谁?")​

•

不支持时间推理("上周和这周的偏好有什么变化?")​

结构化记忆(SQL / NoSQL)​

​

代码块​

Python

# 结构化记忆:直接用关系数据库或键值存储​

class StructuredMemory:​

"""适合用户画像、偏好等键值化数据"""​

​

def __init__(self, db):​

self.db = db # PostgreSQL / DynamoDB / Redis​

​

def update_profile(self, user_id, updates: dict):​

# 例如:{"language": "Python", "framework": "FastAPI"}​

self.db.upsert("user_profile", user_id, updates)​

​

def get_profile(self, user_id):​

​

优势:​

•

精确查询:按字段名直接获取​

•

强一致性:ACID 事务支持​

•

低延迟:主键查询 ms 级​

•

易于审计和迁移​

劣势:​

•

不支持模糊匹配("偏好类似 FastAPI 的框架" 无法用 SQL 直接表达)​

•

Schema 演化成本高​

•

不擅长关系推理​

知识图谱记忆(Knowledge Graph)​

为什么用知识图谱做记忆?​

​

代码块​

Plain Text

向量记忆的局限:​

"张三在公司A工作" → embedding → 存入向量数据库​

"张三跳槽到公司B" → embedding → 存入向量数据库​

查询"张三在哪工作?" → 两条记忆都被检索出来,LLM 无法判断哪个是最新的​

​

知识图谱的优势:​

(张三) --[works_at, valid: 2024-01 ~ 2025-05]--> (公司A)​

(张三) --[works_at, valid: 2025-06 ~ now]-------> (公司B)​

查询"张三现在在哪?" → 图遍历直接找到当前有效的边 → 公司B​

​

知识图谱记忆架构​

​

​

图谱记忆:交互抽取入图(节点/边/双时间线),查询走图遍历 + 语义 + BM25 三路合流回灌上下文。​

基础三元组接口​

​

代码块​

Python

# 知识图谱记忆​

class GraphMemory:​

def store(self, subject, predicate, object, valid_from=None, valid_to=None):​

# 存储三元组 + 时间有效性​

self.graph.add_edge(​

subject, object,​

relation=predicate,​

valid_from=valid_from or datetime.now(),​

valid_to=valid_to # None = 当前有效​

)​

​

def query(self, query: str):​

# 支持图遍历和多跳查询​

return self.graph.traverse(query)​

​

Graphiti 框架详解​

​

代码块​

Python

from graphiti_core import Graphiti​

from graphiti_core.nodes import EpisodeType​

​

# 初始化 Graphiti(连接 Neo4j)​

graphiti = Graphiti(​

neo4j_uri="bolt://localhost:7687",​

neo4j_user="neo4j",​

neo4j_password="password"​

)​

​

​

双时间线模型(Bi-temporal)​

​

代码块​

Python

# 时间线 T:事件实际发生的时间​

# 时间线 T':数据被系统记录的时间​

​

class BiTemporalFact:​

subject: str # 主体​

predicate: str # 关系​

object: str # 客体​

event_time: datetime # T: 事件发生时间​

ingestion_time: datetime # T': 系统记录时间​

valid_from: datetime # 生效时间​

valid_to: datetime | None # 失效时间(None=当前有效)​

​

# 示例​

fact1 = BiTemporalFact(​

subject="张三", predicate="works_at", object="公司A",​

event_time="2024-01-15", # 实际入职时间​

ingestion_time="2024-03-01", # 我们获知这个信息的时间​

valid_from="2024-01-15", valid_to="2025-05-31"​

​

混合检索(Hybrid Retrieval)​

Graphiti 的检索结合三路信号:​

​

代码块​

Python

class HybridRetriever:​

"""三路混合检索"""​

​

async def search(self, query: str, top_k: int = 10):​

# 路径 1:语义向量搜索​

semantic_results = await self.vector_index.search(​

embed(query), top_k=top_k​

)​

​

​

​

​

​

⚠️ 延迟实测:Graphiti 检索阶段不调用 LLM,但实测中位数延迟 2-3 秒(受图查询深度、Neo4j 网络开销影响),并非常被引用的 "300ms" 数字。生产中需要做延迟测试并设置 SLA。​

​

多 Agent 共享图谱​

​

代码块​

Python

# 知识图谱作为多 Agent 的共享记忆​

class SharedKGMemory:​

"""多 Agent 共享的知识图谱"""​

​

def __init__(self, graph_db):​

self.graph = graph_db​

​

async def agent_update(self, agent_id, fact):​

"""任何 Agent 的更新对所有 Agent 可见"""​

fact["updated_by"] = agent_id​

fact["updated_at"] = datetime.now()​

​

# 检查冲突​

existing = await self.graph.find_conflicting(fact)​

if existing:​

​

何时选择哪种?​

混合架构(推荐)​

​

代码块​

Python

class HybridMemory:​

def __init__(self):​

self.vector_store = ChromaDB() # 语义检索​

self.knowledge_graph = Neo4j() # 关系推理​

self.profile_store = PostgreSQL() # 结构化属性​

​

async def store(self, interaction):​

# 1. 对话历史 → 向量存储​

self.vector_store.add(interaction["text"])​

​

# 2. 提取实体和关系 → 知识图谱​

entities = extract_entities(interaction["text"])​

for entity in entities:​

self.knowledge_graph.upsert(entity)​

​

Mem0 的混合方案正是这个思路:用向量存储做语义记忆,用图数据库做关系追踪,统一的 API 对上层透明。​

性能对比数据​

​

代码块​

Plain Text

Mem0 混合方案 vs 纯全上下文方案:​

- 准确率:+26%​

- P95 延迟:-91%​

- Token 成本:-90%+​

​

Agent Memory 框架横评(2026)​

上文讨论的向量 / 结构化 / 图谱是存储介质层面的选型。到了 2026 年——业界称之为"Agent Memory 元年"——记忆从一个"附属功能"升级为独立的工程学科,涌现出专门做记忆管理的框架层产品。理解这些框架的本质,是把上文介质选型"产品化封装"的结果。四大主流框架:Mem0 / Zep / LangMem / Letta。​

四大框架速览​

​

​

记忆抽象:类型与结构​

四个框架对"记忆是什么"有截然不同的抽象——这是理解它们差异的钥匙:​

​

代码块​

Plain Text

Mem0:扁平事实卡片(最细粒度,最易上手)​

{user_id, memory: "用户偏好 FastAPI"} → 向量 + 图​

​

​

一句话区分:​

•

Mem0 把记忆抽象成"原子事实",粒度最细,接入最快​

•

Zep 把记忆抽象成"带时间戳的图结构",最强于关系推理与时间推理(见上文 Graphiti 详解)​

•

LangMem 借鉴认知科学的三分类,强调"不同类型的记忆走不同的写入/检索策略"​

•

Letta 把记忆抽象成"计算机内存层级",核心是 Agent 自己通过 function call 翻页(page in/out)管理记忆​

抽取 - 更新 - 检索:机制横评​

记忆系统有三个核心环节,四个框架做法迥异。​

写入时抽取(Extract)​

​

代码块​

Python

# Mem0:LLM 驱动的事实抽取(用户无感)​

m.add("我之前用 Django,最近切到 FastAPI 了", user_id="alice")​

# 内部:LLM 提取"用户从 Django 切到 FastAPI"​

# → 与旧记忆比对 → 判定为冲突 → 覆盖旧事实​

​

# Zep:LLM 驱动的实体/关系抽取 + 双时间线​

await graphiti.add_episode(episode_body="张三跳槽到公司B", ...)​

# 内部:提取实体(张三/公司B) + 关系(works_at)​

# → 旧边(张三→公司A) valid_to=now → 新边 valid_from=now​

​

# LangMem:抽取策略由开发者在 LangGraph 节点里定义(最灵活)​

# Letta:Agent 自主抽取(self-edit)​

# Agent 调用 core_memory_append / core_memory_replace 工具自己维护​

​

冲突与更新(Update)​

​

​

检索(Retrieve)​

​

代码块​

Plain Text

Mem0: 向量相似度 + 图遍历(混合) → 返回扁平事实列表​

Zep: 向量 + BM25 + 图遍历 → RRF 融合 → 返回带时间的事实​

LangMem:可插拔 Store,检索策略由开发者定(语义/关键词/元数据过滤)​

Letta: core memory 常驻 → 需要时 Agent 主动调 archival_memory_search 拉取​

​

💡 最重要的范式差异:Mem0 / Zep / LangMem 都是系统在用户无感的情况下自动管理记忆(更像数据库);而 Letta 走 Agent 自主管理(self-editing memory) 路线——记忆操作本身是 Agent 可调用的工具,Agent 像人一样"决定记什么、忘什么"(更像大脑)。关于记忆的遗忘与更新机制,详见 #048 — 记忆的遗忘与更新机制。​

自研 vs 框架:取舍清单​

​

​

经验法则:​

•

MVP / 中小流量 → 直接上框架(Mem0 最快,Zep 最强推理,LangMem 最贴合 LangGraph 栈,Letta 适合需要 Agent 自治的场景)​

•

大流量 / 强数据主权 / 特殊记忆结构 → 自研,借鉴框架的设计(双时间线、三分类、self-edit);框架可用来做原型验证​

​

这一取舍逻辑与框架选型的通用判断一致,参见 #043 — 持久化记忆 中"何时该上专用记忆层"的讨论。​

​

对接生产级记忆系统的选型建议​

​

​

记忆框架按需求五路选型:召回选 Mem0,关系/时间推理选 Zep,Agent 自治选 Letta,共享选 Zep,严苛生产自研。​

​

🔗 与本文存储介质选型的关系:本节的框架,本质是把上文"向量 + 结构化 + 图谱"的混合架构产品化封装——Mem0 = 向量 + 图;Zep = 图谱 + 混合检索;LangMem = 可插拔后端;Letta = 块存储 + 向量。选框架 = 选一套预先组装好的存储介质组合 + 抽取/检索策略。理解了上文的介质取舍(参见 记忆类型总览 #040),框架选型就是"买现成组装车还是自己攒"的问题。​

​

A-MEM:Zettelkasten 方法的记忆系统​

​

代码块​

Python

# A-MEM 将 Zettelkasten 卡片笔记法应用于 Agent 记忆​

class AMemNote:​

"""结构化记忆笔记"""​

content: str # 原子化的知识点​

context: str # 上下文描述​

keywords: list[str] # 关键词标签​

links: list[str] # 与其他笔记的关联​

created_at: datetime​

access_count: int​

​

# 记忆笔记之间形成互联的知识网络​

# 类似人脑的联想记忆——从一个记忆可以"联想"到相关记忆​

​

设计挑战与解决方案​

​

​

常见误区 / 面试追问​

误区:"向量数据库能解决所有记忆需求" — 向量检索基于相似度,不是真正的"理解"。它无法回答"A 和 B 是什么关系?"或"这个信息是什么时候变的?"等需要结构化推理的问题。​

误区:"知识图谱太复杂,不值得用" — 对于简单应用确实如此。但当 Agent 需要追踪实体间关系、处理矛盾信息、或做时间推理时,知识图谱的价值会迅速超过构建成本。Graphiti 等框架已大幅降低了使用门槛。​

误区:"知识图谱就是把所有信息都存成三元组" — 不是所有信息都适合图谱。对话历史、非结构化文档适合向量存储;用户属性配置适合结构化存储。图谱应该只存储实体、关系和关键事实。混合架构是最佳实践。​

误区:"构建知识图谱必须预定义完整 Schema" — Graphiti 等现代框架支持 learned ontology——从数据中自动学习 Schema,同时支持预定义的 prescribed ontology 约束关键关系。​

追问:"向量检索返回了语义相似但实际无关的内容怎么办?" — 两层解决:(1) 加 Reranker 对检索结果做精排;(2) 结合结构化元数据过滤(如按用户 ID、时间范围、类别筛选后再做语义检索)。​

追问:"混合架构的一致性如何保证?" — 同一条信息在向量存储和图谱中需要同步更新。实践中用事务性写入或最终一致性。删除操作尤其要注意——向量存储和图谱中都要清理。​

追问:"图谱记忆的实体提取准确率不够怎么办?" — 三层保障:(1) 用专门的 NER 模型做初步提取;(2) LLM 做上下文理解和关系推理;(3) 对关键事实做人工审核或交叉验证。​

追问:"图谱和 RAG 的关系是什么?" — GraphRAG 是两者的结合——用知识图谱增强 RAG 检索。传统 RAG 只做文档级语义检索,GraphRAG 可以在检索后利用图结构做关系推理和多跳问答,提供更准确和完整的答案。​