选记忆框架时,最容易比较的是安装命令和 API 数量,最容易遗漏的是更新语义。Alice 从“主要写 Java”变成“主要写 Kotlin”后,系统如何表达旧事实?删除学习目标后,哪些派生记录仍然存在?把同一组问题交给不同实现,比笼统询问谁的记忆能力更强更有价值。
本文属于 AI 记忆工程专题,调研日期为 2026-09-23。结论来自官方资料与以下固定源码快照,不包含三套框架的本地部署、性能压测或模型效果对比。选型建议是面向学习助手的工程判断,不能解读为框架官方承诺。
固定版本与比较范围
| 对象 | 本次源码提交 | 核对入口 |
|---|---|---|
| Mem0 开源 SDK | f8082a7345dadd9e042ebbc40b57b1498c8f6d63 |
Memory 的 add、检索及显式更新删除实现 |
| Graphiti | 16cdf7045378c8d53ae01f94e2fa60d238cb0f68 |
add_episode、实体关系处理与搜索入口 |
| LangGraph | 1afaca35a0d4962fb0203a0e9133a07ffd6a553c |
BaseStore 的命名空间、键值与检索接口 |
三者承担的职责并不完全相同。Mem0 提供面向记忆的 SDK 流程;Graphiti 围绕时间关系图组织信息;LangGraph 是 Agent 编排体系的一部分,Store 提供应用组织跨会话信息的基础能力。比较时应把“框架完成了什么”和“应用还要实现什么”分别写出来。
托管平台可能在部署、权限、运维和检索策略上增加其他能力。本文不把 Mem0 Platform 等同于开源 SDK,也不把 Zep 的托管基础设施等同于 Graphiti。访问官网看到的 SLA、延迟或产品界面,不能直接作为自行部署开源组件后的结果。
Mem0:从新交互形成可检索事实
固定版本的 _add_to_vector_store 先取得会话范围内的近期消息,再检索已有相关记忆,把这些上下文交给增量提取提示词,随后处理新事实的嵌入和批量写入。这里需要特别注意版本变化:本次核对的默认新增路径采用增量新增机制,不能沿用旧资料中“每次 add 自动决定更新或删除”的概括。固定源码
应用可以调用显式更新、删除接口,但这与“输入一句新话就自动获得我们期望的事实替换语义”不同。对于 Alice 的主要语言变化,接入方应验证旧事实是否仍可检索、如何表达当前状态,以及是否需要额外的属性或时间策略。不能只看到新 Kotlin 记忆写入成功,就认为更新问题已经解决。
这种封装适合希望较快接入提取和检索管线的场景。代价是必须理解 SDK 的版本行为、后端配置和错误处理,并为自己的业务约束建立回归案例。尤其在升级时,应重新跑补充、纠正、删除和重复投递测试,而不仅检查接口是否仍返回成功。
Graphiti:围绕实体、关系和时间组织信息
Graphiti 的输入入口围绕 episode 展开,后续提取和解析实体与关系。固定代码包含关系解析、失效关系处理和来源 episode 关联;搜索由配置决定使用的检索方式。它更适合讨论“某个关系何时成立,以及根据哪次事件得出”。固定入口源码
对于学习助手,可以把用户、语言和学习对象建模为实体,把主要使用、正在学习等建模为关系。这样能提出带时间的问题,例如“改变目标之前主要学习什么”。但抽取和实体合并仍可能出错:同名课程是否同一对象、关系是否真正矛盾,都需要样例验证和领域约束。
图结构不意味着自动获得更好的答案。如果场景只有几个稳定偏好,图数据库、实体解析和增量维护可能增加不必要的复杂度;如果需要跨事件关联多人、多项目和历史关系,图表达才更有可能体现价值。这个判断应来自查询需求,而不是图可视化是否吸引人。
删除时也应明确对象。删除某次输入、某条关系与删除某个用户的全部衍生信息,可能涉及不同范围。本文没有执行端到端删除实验,因此不承诺某个调用能清除所有副本;接入前需要针对选定版本、数据库和应用派生数据验证完整过程。
LangGraph:应用掌握记忆策略
固定版本的 BaseStore 提供命名空间中的键值读写、删除、搜索和批处理等抽象;检索能力与具体 Store 和索引配置相关。会话恢复则由检查点机制负责,与跨会话 Store 的职责有所区别。固定 Store 源码
学习助手可以在用户范围内保存结构化画像,在流程节点中决定何时提取、更新和检索。应用有较大的建模自由,也承担更多策略实现:如何识别替换、如何维护有效期、如何阻止旧事件重试,不能因为用了 Store 就自动完成。
命名空间也不是认证系统。服务端仍要从可信身份构造用户范围,不能直接让请求方选择任意用户命名空间。内存 Store 与持久化 Store 的运行保证不同,演示中跨节点可读不代表进程重启后能够恢复。官方记忆概念文档可以帮助理解这些职责。
用统一案例逐项提问
| 案例 | 接入时必须得到的答案 |
|---|---|
| Java 背景后补充 Python 目标 | 如何避免把不同属性当成矛盾事实 |
| 主要语言改为 Kotlin | 旧事实怎样退出当前使用,历史如何解释 |
| 重复投递同一事件 | 幂等由 SDK、存储还是应用保证 |
| 删除学习目标后重试旧任务 | 如何阻止已撤回的信息重新写入 |
| Alice 查询 Python | 用户范围由谁强制执行,是否发生跨用户召回 |
| 查询上个月的学习目标 | 是否支持明确的历史时点与来源追溯 |
这张表是验收清单,不是对三套框架的实测评分。每个团队可以把它转换成同一组输入事件与预期约束,然后在选定配置下运行。失败应记录具体原因,不宜只给某个框架贴上“记忆好”或“记忆差”的标签。
Java 服务如何接入
可以让 Java 业务服务掌握身份、事件、版本与删除任务,把框架部署成内部能力服务,通过结构化协议调用。Python SDK 负责其擅长的模型和检索流程,Java 侧继续控制业务边界。也可以先用本文Java 离线示例验证契约,再替换其中一个组件。
远程调用后,应处理超时的不确定性:客户端没收到响应,不代表写入没有发生。事件标识要贯穿两侧,重试前应能够确认状态。若框架接口没有满足所需幂等语义,就由应用建立收据与状态查询,而不是依赖每次请求生成新 ID。
部署成本也要拆开看:模型调用、Embedding、数据库、索引构建、后台维护和故障排查都可能占用资源。本文没有测量这些成本,因此不给出“最便宜”结论。小团队可以先选最少组件满足主要用例的实现,保留接口边界,之后再根据数据增长和查询复杂度演进。
怎样作出可解释的选择
如果主要需求是把对话转成可检索事实,可以优先验证 Mem0 的当前 SDK 流程;如果关系随时间变化且需要历史查询,可以验证 Graphiti;如果已经采用 LangGraph 编排并希望自行掌握策略,可以围绕 Store 组织实现。这些是候选方向,最终选择仍取决于统一样例的结果和运维能力。
选型报告至少记录源码提交、模型、索引配置、输入数据和失败案例。比较不同版本时,不要把一套系统的默认配置与另一套精心调优的配置直接排名。下一篇评测实践会将这组问题转化为可复现实验,明确哪些结果已经运行、哪些仍是计划。