Graphiti 深度拆解:给知识图谱加上时间之后,记忆怎样更新?

从 episode、实体和关系出发,理解事实时间与系统时间,看看时序知识图谱怎样处理变化、冲突与历史查询。

本文目录

Memory Agent 深度拆解 · 第 2 / 8 篇。查看系列目录

一家公司的负责人从张总变成了李总。助手需要知道现在找谁,也需要解释去年是谁批准的项目。

把新负责人覆盖进一个字段,会丢掉历史。把两句话一起塞进向量库,又可能在回答时同时找回两个相互冲突的答案。

Graphiti 把这个问题放进数据模型:关系有内容、有来源,也有它成立和失效的时间。它值得研究的地方,是如何从自然语言逐步建立这样一张不断变化的图。

本文依据 2026 年 9 月 22 日的公开资料与提交 16cdf7045378。以下是源码分析,不是运行验收;Graphiti 开源引擎与 Zep Cloud 的完整产品能力分开讨论。

1. 从原始经历到实体关系,中间隔着一层证据

Graphiti 的输入单位通常是 episode。它可以是一段消息、文本或结构化内容,并携带来源描述与参考时间。

图中至少要区分三类东西:记录原始输入的 EpisodicNode,代表人或组织等对象的 EntityNode,以及描述实体之间事实的 EntityEdge。关系边还保存支撑它的 episode ID。源码:节点模型关系模型

因此,“李总负责甲项目”不必成为一条无法解释来源的孤立文本。系统有机会沿关系回到原始材料,检查这句话由什么输入形成。

这是证据入口,并非真实性认证。如果原始消息是传闻,抽取出来的边仍然来自传闻。应用需要另外定义哪些来源能更新关键业务事实。

2. add_episode 其实是一条抽取与归一化管线

顺着 add_episode() 看,主流程会获取相关的先前 episodes,创建或读取本次 episode,提取实体并做消歧,再提取与处理关系,更新实体属性,最后保存节点与边。源码:add_episode

可以压缩成这条链:

原始 episode → 识别人和事物 → 与已有实体对齐 → 提取关系 → 处理重复与冲突 → 持久化图。

为什么必须先做实体对齐?因为“李明”“李总”“新负责人”可能指同一个人,也可能分别指不同的人。不解决主体,后面再准确的关系查询也会沿错节点前进。

节点消歧代码将候选实体与已有节点进行匹配、判断和 UUID 映射;后续边处理利用映射,把不同文本中的同一个对象连在一起。源码:节点维护

这是一种先规范对象身份,再规范关系的设计。它也解释了图记忆为什么通常比简单存一段文本做更多写入工作。

3. 四个时间字段,分别回答什么问题?

关系模型中的几个时间字段,是理解 Graphiti 的关键:

字段要表达的时间
created_at系统创建这条记录的时间
expired_at系统将它作失效处理的时间
valid_at事实开始成立的时间
invalid_at事实停止成立的时间

此外还有 episode 参考时间等信息。这里最重要的区分是:现实中的有效时间,与系统记录、处理信息的时间,不必相同。源码:EntityEdge

假设 9 月 10 日才导入会议纪要,纪要写着“李明从 8 月 1 日起担任负责人”。那么 9 月是系统获知时间,8 月是事实生效时间。

“8 月谁负责”与“截至 8 月系统已经知道什么”,由此成为两个不同问题。数据模型为这种区分提供基础,但具体 API、查询过滤和抽取质量仍要逐项验证,不能从字段存在直接推导出任意历史查询都正确。

4. 新事实如何使旧关系失效?

关系处理会同时面对重复、冲突和时间信息。代码里可以看到,根据新关系的有效时间设置旧关系 invalid_at,并记录 expired_at 的处理路径。源码:关系维护

这意味着旧事实不一定被物理删除。它仍然可以解释过去,只是不再代表某个时间之后的状态。

但“矛盾”本身依赖语义。一个人能同时负责两个项目,也可能先后负责同一个项目。两条关系看起来相似,不等于它们互斥。

因此,业务 schema 很重要。实体类型、边类型及允许的连接方式可以为抽取提供约束,但 schema 也不是业务真相裁判。高价值事实仍应回到可信系统记录,或保留人工确认入口。

还有一个特别好的测试:先导入新任命,再补录旧纪要。系统不能因为旧纪要“刚刚入库”,就把旧负责人恢复成现任。

5. 为什么图里还需要向量与关键词检索?

“有图”并不意味着所有问题都通过手写图查询解决。

Graphiti 的搜索配置把节点、关系、episodes 和社区分开,各自选择检索方法与重排策略。节点、关系支持余弦相似、BM25、广度优先搜索等配置,重排选项包括 RRF、节点距离、MMR 和 cross-encoder 等。源码:搜索配置

这些方法负责不同工作:关键词找专有名词,向量找语义表达,图遍历利用已建立的连接,重排再决定哪些结果进入上下文。不是每次查询都必须启用全部方法。源码:搜索实现

比如“谁能解释去年那个延期项目”,单纯匹配“负责人”未必足够。你可能先找到延期事件,再沿项目关系找到当时的人。但前提是相关事件、项目和人确实已正确连入图中。

图检索擅长利用结构,无法替代结构本身的建立。

6. group_id 与请求作用域为什么值得看?

group_id 用于图分区。当前 add_episode 还会为请求解析自己的 driver 与 clients,避免并发操作不同 group 时改写共享对象的目标。源码:请求作用域与写入

这揭示了记忆隔离的另一面:除了检索过滤,还要检查并发写入时到底连接到了哪个目标。

应用层仍需要把登录身份绑定到允许的 group。一个可随意填写的分区参数,只是选择器,不能自己证明调用者有权访问该分区。

同一事件序列的入库顺序也需要考虑。源码说明建议逐个等待 episode 加入。因为后一条输入的消歧和更新可能依赖前一条已经形成的图状态。后台队列能把重活移出响应链路,但不能消除这些依赖。

7. 我会怎样验证它是否适合业务?

先不用大测试集。构造一个小型组织变动故事:两位同姓负责人、一个调岗、一次补录、一条传闻、一次更正。

然后分别检查四层产物:episode 是否完整,实体有没有误合并,关系区间是否正确,回答引用的是哪条证据。再反转入库顺序,检查结果是否仍符合预期。

测量成本时,写入抽取与读取应分开。对关系变化缓慢、查询频繁的业务,可以接受较重的写入;对每秒大量事件的业务,则必须测吞吐、队列积压和何时可查询。

本文没有执行这些测试,它们是根据数据模型提出的验收设计。

8. Graphiti 真正改变的是什么?

它给“事实会变化”提供了明确的存储位置:旧事实可以继续解释历史,新事实可以接管当前状态,二者都有机会回到来源。

适合它的场景,往往需要持续理解人、组织、项目与事件之间的关系。如果需求只是记住几条风格偏好,图引擎的额外复杂度未必值得。

Graphiti 带来的最重要提醒是:记忆中的矛盾,不能总交给最后一轮回答模型临场处理。 你可以在数据层先记录变化发生了什么,让模型面对更清楚的证据。

系列阅读

返回系列目录与全景总览

上一篇:Mem0 深度拆解

下一篇:Letta 深度拆解