[!MemGPT 的 OS 类比词典]

  • main context: LLM 的 context window, 类比物理 RAM
  • external context: 向量库 / 关系库 / 日志, 类比 disk
  • function call: 模型主动触发的 I/O, 类比 system call
  • queue manager: FIFO 驱逐器, 类比 page replacement policy
  • heartbeat: 定时唤醒, 类比 timer interrupt

Context Window 的硬上限

现有商用 LLM 每次 forward 能看到的 token 数是有限的, 比如 GPT-4 turbo 是 128K, Llama-2-chat 是 4K; 一旦 input + output 超出这个窗口, 后续内容要么被截断, 要么只能靠外部检索 (classic RAG) 在推理前硬塞进去;

这带来两个根本问题:

  • 长对话: session 时间够长后, 早期轮次会被挤出窗口, 模型彻底"忘"掉用户之前说过的事实
  • 长文档分析: 单份文档已经接近或超过 context 上限, 跨章节的 key-value 关联几乎做不了

两个问题本质都是同一个: context 是昂贵的短期存储, 不能无限扩张, 需要一种外部存储 + 调度机制;

另外注意, 自注意力的计算量是 O(n2)O(n^2), 直接把窗口拉到无限大在工程上也不现实, 因此"扩窗口"这条路至少短期内是有上限的;

OS Memory Hierarchy 做类比

传统 OS 已经用几十年解决了完全同构的问题, MemGPT 的直觉就是照搬这套层级:

层级 容量 延迟 OS 中的角色 MemGPT 中的角色
Register / Cache 极小 极低 CPU 直接取用 attention 直接读取的 prompt token
RAM 有限 低 活跃程序的状态 main context — 本轮 forward 能看到
Disk / SSD 很大 高 非活跃程序 / 文件系统 external context — 向量库 / 对话历史 / KV store

OS 通过 MMU, page table, page fault handler 让程序看起来有一个几乎无限的虚拟地址空间; MemGPT 想复刻这一套, 让 LLM 看起来有一个几乎无限的上下文;

区别是: OS 里 page fault 由 MMU 硬件触发, 而 MemGPT 里 page fault 由模型自己通过 function call 主动触发, 所以模型本身扮演了一部分 kernel 的角色;

论文定位

MemGPT 不是一个新模型, 也不是一个新的 attention 变种, 而是一个围绕现有 function-calling LLM 搭建的 memory management system; 它的核心主张是:

  • 与其等 context length 继续增长, 不如让模型主动管理自己的 context
  • 让模型通过 function call 发起 “装入 / 驱逐 / 归档” 操作
  • 把 LLM 本身当成 kernel 的一部分, 决定什么该留在 RAM, 什么该换出

论文解决的核心问题

现有方案的不足:

  • 暴力拉大 context length: 吃 O(n2)O(n^2) 的 attention 成本, 而且窗口再大也仍然存在超出的风险, 并不是根治
  • classic RAG: 在一次 forward 之前做一次向量检索, 然后把结果塞进 prompt 头部; 问题是 retrieval 时机固定, 只能被动响应当前 query, 无法在对话中途决定"我现在需要回忆起三周前那句话"
  • sliding window / attention sink: 只是延缓遗忘, 没有持久化, 也没有"回忆"能力

MemGPT 试图回答:

  1. 能不能让 LLM 自己决定何时去 external storage 拉数据?
  2. 能不能让 LLM 自己决定把哪些 context 驱逐 / 归档?
  3. 能不能把上面两件事用统一的 function-call 接口暴露, 保持可观测和可扩展?

insight

memgpt_architecture.png

原论文 Figure 3: MemGPT 在固定 8k context window 上叠了一层"操作系统式"的存储层级 — 主上下文里再切出 System Instructions (read-only system prompt) / Working Context (read-write 摘要区) / FIFO Queue (read-write 滑动 message 窗口) 三段, 外面挂 Archival Storage (任意 doc / KV) 和 Recall Storage (历次 message), Function Executor 是 LLM 输出 function call 后实际执行检索 / 写入 / 驱逐的总线; 这张图是后文所有 “main context 三段 / external context / function call / queue manager / heartbeat” 章节的视觉总索引;

Main context 的三段式分层

MemGPT 把 context window 不视作一块扁平的 prompt buffer, 而是切成三个区域:

分区 可写性 生命周期 类比
System instructions read-only 整个 session 常驻 OS kernel code
Working context read-write, 模型显式编辑 跨 turn 持续 进程 heap / 长期状态
Conversational context append-only, FIFO 驱逐 短期, 会被挤出 CPU 的 working set

其中 working context 是最关键的设计: 它是一个模型自己能写的小笔记本, 用于持久化那些"我希望一直记得的事实", 比如用户的名字, 偏好, 角色设定; 在 OS 类比里 working context 不是 buffer cache, 而是"进程自己持有的数据结构", 模型把它当作第一人称状态来编辑;

External context 的两种后端

超出 main context 的所有内容会流向 external context, 分两类:

  • Recall storage: 保存所有历史 event / message 的原始流水, 支持文本或向量检索; FIFO 驱逐下来的消息并不真的被删除, 而是进入 recall storage, 模型之后可以通过 conversation_search 拉回来
  • Archival storage: 模型主动写入的持久化知识库, 形式上是一组可检索的 document chunks; 比 recall 更结构化, 适合放笔记 / 摘要 / 总结

两者都只有通过 function call 才能被访问, 不会未经请求就被塞进 prompt; 这一点很重要, 它让 external context 的流量是受控的, 不会像 RAG 那样一上来就挤占 prompt 开头;

Function calls as system calls

MemGPT 依赖 function-calling LLM (原论文用的是 GPT-4), 给模型暴露一组统一接口, 每次 forward 可以输出若干 function call:

  • send_message: 正常回复用户
  • conversation_search, archival_memory_search: 从 external storage 拉取
  • core_memory_append, core_memory_replace: 编辑 working context
  • archival_memory_insert: 把新知识沉淀到 archival
  • pause_heartbeats: 暂停后台中断

每个 function call 对应一次"系统调用", 返回结果会作为下一次 forward 的 observation 注入; 这种"模型输出 →\rightarrow kernel 执行 →\rightarrow observation 回注"的循环, 和 OS 里 user space →\rightarrow kernel space →\rightarrow 返回 user space 的切换几乎一一对应;

Queue manager 与 FIFO 驱逐

Conversational context 的容量有限, 当 token 使用率超过阈值 (论文里用 main context 容量的某个比例) 就触发 queue manager:

  • 最早一批消息从 conversational context 驱逐 (evict)
  • 同一份内容同时被归档到 recall storage, 保留可检索性
  • 模型可以通过 conversation_search 再把这些内容召回 (recall) 回 main context

这就是一个完整的 page-out →\rightarrow page-in 周期; 与 OS 的 LRU/LFU 不同, 这里的驱逐策略显式采用 FIFO, 因为时间顺序本身就是对话语义的一部分, LRU 的"最近访问"在对话里反而不自然;

📝 关键区分
  • 驱逐不等于删除: 消息仍在 recall storage 里
  • 召回不等于重复: 召回后消息会被重新插入 main context, 但原位归档仍然保留

Heartbeat: 模型的自我中断

对话类场景有一个特殊问题: 模型只在用户有输入的时候才被调用; 但很多"记忆维护"动作其实希望在空闲时间做, 比如对一段长对话先做摘要再写入 archival;

MemGPT 的方案是 heartbeat events:

  • 系统会在某些条件下主动给模型一条空消息, 等价于一次硬件 timer interrupt
  • 模型也可以在本次 function call 中把 request_heartbeat=true, 表示"我还有后续工作要做, 请再给我一次机会"
  • 这让模型能做多步连续动作, 而不被"每轮只能输出一次"的默认 chat 协议卡住

这和 OS 中 中断 + syscall return 的组合极其相似: function call 返回后如果请求了 heartbeat, 等价于 schedule 一个后续 tick;

MemGPT vs Classic RAG

维度 Classic RAG MemGPT
检索时机 forward 之前, 固定一次 模型决定何时, 可以任意多次
检索对象 静态知识库 对话历史 + 模型自建 archival
写入能力 只读 模型可写 working / archival
驱逐策略 无 (每次都重构 prompt) FIFO, 保留原始归档
工作方式 reactive — 针对当前 query 拉文档 agentic — 主动管理自己的记忆
失败模式 retrieval miss 直接体现在答案里 模型可以察觉 miss 并重新检索

结论: RAG 是一次性 context 装填, MemGPT 是持续的 context 调度;

评估: 两个场景都是 context 上限放大器

Deep memory retrieval (多 session 对话)

设定: 给定先前 session 中提到过的事实, 在新 session 里正确引用;

baseline (固定 context) 在 session 数超过窗口容量后准确率断崖式下跌; MemGPT 依靠 conversation_search 主动查询早期 session, 能把准确率维持在高位;

关键启示: 让模型意识到自己应该去查, 比让模型天然记住更可扩展;

Nested key-value retrieval (长文档)

设定: 一个文档内部存在多层引用 (A →\rightarrow B →\rightarrow C →\rightarrow …), 要求模型最终给出末端值;

固定 context 装不下整份文档, 每次跳转都失败; MemGPT 通过 archival_memory_search 做多次跳转式检索, 能显著延长可成功跳转的层数;

关键启示: 长文档不是一次性全部装入的问题, 而是如何做受控随机访问的问题;

四个工程化细节值得留意

  1. Prompt 里的 kernel 协议: 模型要能可靠调用 function, 必须在 system prompt 里用自然语言告诉模型自己是 MemGPT 的一部分, 把 OS 类比直接交代清楚; 这其实是一次 prompt-level 的 OS ABI 定义
  2. Function schema 严格校验: 非 function-calling 模型 (比如早期开源 7B) 很容易出现格式漂移, 论文里用的是 GPT-4, 下游实现需要考虑格式矫正层
  3. Recall 的检索不是向量必选: 论文强调支持文本检索 (BM25) 和向量检索的混合, 因为对话历史里大量是精确字面引用, 向量反而会 miss
  4. Archival 的写入是幂等式的: 同一段摘要可能被多次追加, 工程上要做 dedup / merge, 否则 archival 会退化成垃圾场

具体的开源落地在 Letta (原 MemGPT 项目) 里有进一步实现, 工程上的 schema / retry / 格式矫正这里先挖个坑, 后面单独开一篇笔记讨论;

📝 论文主流观点总结

如果按论文主线浓缩, MemGPT 的主流观点可以总结为:

  1. Context length 的物理上限短期内不会被彻底抹平, 因此必须引入分级存储思想
  2. LLM 本身已经足够强, 可以扮演 memory management 的决策者, 而不是被动的 context 消费者
  3. Function call 是一种天然的"用户态 →\rightarrow 内核态"边界, 把它复用为 memory API 是最小侵入的做法
  4. 驱逐策略应当保留语义顺序 (FIFO), 而不是 OS 里常用的 LRU, 因为对话本身是时间敏感的
  5. Heartbeat 机制让 LLM 从"一次回复 = 一次决策"进化到"可以连续做多步内部任务", 为 agentic 行为打下协议基础
  6. MemGPT 不是 RAG 的替代品, 而是把 RAG 从一次性 retrieval 泛化为可调度的 memory subsystem