Skip to content

[FEATURE | Memory Graph] 给 MemoryItem 之间加上关联链接(wiki-links) #458

Description

@MrXnneHang

Description

Warning

ADR 0007(Proposed)已决定移除图结构,检索统一为 embedding + BM25 hybrid search。
本提案中"竖井式检索"的论述在新架构下不再成立。
仍然有效的论点是:SUPERSEDES 矛盾链追踪和因果关联 — 这些是 hybrid search 做不到的。

给 memU 的 MemoryItems 加上 wiki-link,允许跨 Category。针对 LLM mode

目前的三层检索已经是非常 Map-Reduce 而且 Clear,这意味着 memory graph 不需要承担 Category 的工作就可以达成按类搜索匹配(知识图谱)的功能——目前更需要关联图谱。目前三层检索有一个局限,就是 Category 下的 MemoryItem 都是孤立的——无论跨 Category 还是同一 Category,就好像一个分类下每篇博客都是独立的,如果想发现博客之间的关联只有都读一遍。对于 memU 来说要发现关联就是 LLM 遍历 MemoryItems。

但如果, MemoryItems 之间原本就有 wiki-link,那么在遍历时就会更快地进行搜集齐足量的信息。这也类似于变相给了 memU 关联联想的能力。

问题

memU 当前的检索是竖井式的:一旦选中 TopK categories,模型就无法发现未被选中的 category 中的相关 items。每次检索都从零开始,items 之间没有任何预存的关联关系。

1. Category 竖井阻断了跨主题发现

假设用户的记忆分布在多个 category 中:

Category Items
职业 "用户从市场营销转行做了后端开发"
居住地 "用户从北京搬到了上海"
社交 "用户想念北京的朋友"

这三条 item 可能存在因果关系 — 转行导致了搬家,搬家导致了社交上的失落。但如果查询只命中了"居住地"这个 category,模型只能看到"住在上海"这个孤立的事实。它无法发现用户为什么搬家,也无法发现搬家带来的情感影响 — 除非全量扫描所有 category。

2. 每次检索都要重新发现关联,浪费 token

没有持久化的链接,模型每次都要花 token 重新推导 item 之间的关系。一个了解你的人知道你搬到上海是因为换了工作,不需要每次对话都重新推导 — 他只是记住了这个关联。memU 目前缺少这种"记住关联"的能力。或者准确来说是一种类似联想的能力。

3. 矛盾链被静默丢弃/直接覆写

当一条记忆被更新(例如 "喜欢喝咖啡" → "最近戒了咖啡"),当前系统直接在 category summary 中替换旧信息。变化本身 — 用户的习惯发生了转变这件事 — 被丢失了。在 Zep 等系统中,完整的矛盾链作为一等数据被保留,支持 "用户的习惯发生过哪些变化?" 这类查询。


Motivation

提案:MemoryItem 之间的关联链接[wiki-link]

在 MemoryItem 记录之间引入轻量的、有向的、带类型的边(link)。

类比:博客中的 wiki-link

个人知识博客中的双向 wiki-link 解决的是同样的问题。博客文章按"系列"分组(类似 memU 的 category),但光靠系列分组会制造信息孤岛。wiki-link(如 [[云服务商跑路之后:重新审视个人博客的形态]])把不同系列的文章连接起来,形成关联图谱。

在博客中,wiki-link 的语义是隐式的 — 作者只是在后文中提到了前文。至于为什么提到(主题延续、反驳、前置知识),并没有编码在链接本身中。

memU 可以做得更好:由 LLM 执行链接,它可以为每条边赋予关系类型

建议的关系类型

类型 语义 示例
CAUSED A 导致了 B 转行 → 搬家
TEMPORAL A 在 B 之前,且有延续性 学 Python → 拿到开发岗 offer
SUPERSEDES B 更新/矛盾了 A "喜欢咖啡" → "戒了咖啡"
ELABORATES B 细化了 A "在上海工作" → "公司在浦东"
THEMATIC A 和 B 共享主题 "喜欢徒步" → "周末去了黄山"

检索方式的变化:链式联想

有了 wiki-links,检索获得关联遍历能力:

查询: "用户住在哪里?"
    │
    ▼
Category 命中: 居住地
    → item: "用户目前住在上海"
        │
        │ ── CAUSED ──→ "用户因为换工作搬到了上海"  (职业 category)
        │                    │
        │                    │ ── CAUSED ──→ "用户转行做了后端开发"
        │                    │ ── TEMPORAL ──→ "之前住在北京"
        │                         │
        │                         │ ── THEMATIC ──→ "在北京做市场营销"
        │
        │ ── CAUSED ──→ "用户想念北京的朋友"  (社交 category)

模型通过沿着链接走来发现完整上下文 — 职业历史、情感状态、之前的居住地 — 而不是扫描所有 category。这更快(更少 token)、更完整(跨越 category 边界)、产生更丰富的回答。

遍历结果中可能会有信息冗余(比如"上海"出现在多个关联 item 中),但这恰恰是人类联想的运作方式 — 一些重叠和冗余无关联想是连通性的代价,远好于完全没有联想。

矛盾链变得可查询

通过 SUPERSEDES 链接,一个变化中的事实的完整历史得以保留:

"每天喝3杯咖啡" ──SUPERSEDES──→ "减到1杯" ──SUPERSEDES──→ "完全戒了咖啡"

模型不再只知道当前状态,而是可以回答"用户的咖啡习惯是怎么变化的?"—— 沿着 supersedes 链遍历即可。


收益总结

现状 有了 wiki-links 之后
TopK categories 是硬边界 链接支持跨 category 遍历
每次查询都重新推导关联(消耗 token) 关联被持久化并复用
矛盾信息被静默覆盖 变化链通过 SUPERSEDES 保留
最新和最早的 items 之间没有路径 间接链接链跨越时间连接
检索只是局部搜索 检索获得图遍历能力

非目标(初始版本)

  • 本提案不指定具体的图数据库 — 链接可以存储为新的关系表(类似 CategoryItem),也可以使用可选的图数据库后端。
  • 本提案不定义具体的提取工作流(提取时生成 vs 事后关联)。两种方式都可行,选择属于实现细节。这个可以再讨论,我倾向事后关联且非全量关联。
  • 关系类型是建议性的。最小化的初始版本可以先用无类型链接,之后再加类型。但处于 LLM 的考虑最好是明确关系,避免抽取出来很多失语的连接。

Q&A

为什么不需要做全量的关联?

一方面是 token 和耗时问题。

另一方面是可以依赖间接联系。

比如一个 item 的直接关联只有三个。

Image

但是它可以通过间接关联和更早的 items 连到一起。形成一种类似追忆式”联想“。

Image

Platform

Platform Independent

Priority

Critical

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions