MemGPT: Towards LLMs as Operating Systems
论文:https://arxiv.org/abs/2310.08560 作者:Packer, Wooders, Lin, Fang, Patil, Stoica, Gonzalez(UC Berkeley / Letta)
本文基于 arXiv 源码(
~/.cache/nanochat/knowledge/2310.08560/,入口main.tex,正文sections/*.tex,表格tables/*.tex)通读整理。
0. 核心命题:虚拟上下文管理(virtual context management)
论文不打算”做出更长的上下文窗口”,而是要在固定窗口上伪造无限上下文的假象——这正是 OS 用磁盘伪造更大内存的做法:
| OS 概念 | MemGPT 对应物 |
|---|---|
| 物理内存 / RAM | LLM 的 context window(prompt tokens) |
| 磁盘 / swap | 外部数据库(recall + archival storage) |
| 页换入换出(page fault) | 函数调用 memory_search / archival_search / core_memory_* |
| 内核 / 调度器 | LLM 自己(system instructions 里的控制流说明) |
| 中断 | request_heartbeat 函数链、定时事件、内存压力警告 |
与传统 RAG 的根本区别:检索不是外挂的固定 pipeline(“总是取 top-k 塞进 prompt”),而是模型自主决定何时检索、检索什么、何时把什么写回持久存储,并且对 token 预算有感知。
1. 内存层级
两类内存:
- main context(= prompt tokens,in-context,可被模型直接读取)
- external context(out-of-context,必须显式搬入才能用)
1.1 Main context 的三段式布局(按顺序拼接成一个字符串)
-
System instructions(只读、静态) 包含三样东西:MemGPT 的控制流说明、各级内存的用途说明、完整函数 schema 及自然语言描述。对应 OS 的内核代码——它定义了”允许哪些内存操作”。
-
Working context(固定大小的可读写文本块,只能通过 MemGPT 函数改写) 对话场景下专门存”用户关键事实、偏好、agent 的人设要点”。相当于常驻热数据。这是论文里被低估的设计:它给了模型一块有界、可控、永远在上下文里的”便签纸”,避免关键事实被 FIFO 换出后只能靠检索碰运气。
-
FIFO queue(滚动消息历史) 存 user/assistant 消息、系统消息(如内存警告)、函数调用输入与输出。 第 0 槽位特殊:放”已被逐出消息的递归摘要(recursive summary)“——被换出历史的压缩残影。
1.2 External context(两个数据库,职责不同)
- Recall storage:无差别全量存档。每条进来的消息和模型每次输出都写入(
messages表)。检索命中后,消息被追加到 FIFO 队尾重新回到窗口。保证”信息永不丢失、可回溯”。 - Archival storage:任意长度文本对象的读写库,实现用 PostgreSQL +
pgvector(HNSW 索引、余弦相似度、亚秒级查询)。存模型主动决定长期保留的内容,例如整个 Wikipedia 文档集(实验里灌了 20M 篇的 embedding)。
设计哲学:recall 保证”可恢复性”(类似日志),archival 保证”可扩展检索”(类似文件系统)。前者是容量兜底,后者是精确查找。
2. Queue Manager:上下文溢出控制(最”OS”的机制)
Queue manager 是内存管理器,负责 FIFO 与 recall 的一致性,并实现两级水位线的换出策略:
正常路径:新消息到达 → 追加 FIFO → 拼接 prompt → 触发推理 → 输入与输出都写入 recall storage。
Warning 水位(如窗口的 70%): 向 FIFO 插入一条系统消息——“memory pressure” 警告,明确告知模型”即将发生换出(queue eviction),请现在就用函数把 FIFO 里的重要信息写进 working context 或 archival storage”。
Flush 水位(如 100%): 执行换出——按固定比例逐出消息(如窗口的 50%),用**“旧的递归摘要 + 刚被逐出的消息”生成新的递归摘要**,替换 FIFO 第 0 槽。被逐出的消息并未消失,仍永久留在 recall storage,随时可被函数取回。
三个关键细节:
- 换出 ≠ 删除,而是降级到慢速存储(分层内存的语义)。
- 是否降级、降级什么,由模型在警告驱动下自主决定——这是”LLM as OS”的关键接口。
- 递归摘要是累积压缩(summary of summary),天然有信息衰减,所以 working context 才是可靠防线。
3. Function Executor:自我编辑与错误闭环
self-directed editing/retrieval 的完整循环:
main context(拼接字符串) → LLM 推理 → 输出字符串
→ parser 校验函数名/参数 → 执行函数
→ 结果(含运行时错误,如"working context 已满")写回消息 → 再次推理
几个工程要点:
- 错误反馈闭环:解析失败、参数非法、容量超限等错误都被转成消息喂回模型,模型可自我纠正(先腾空间再写、换关键词重搜)。这是让”模型当内核”能跑起来的关键容错设计。
- 预算感知:system 提示中显式告知当前 token 余量与上限,让模型对”还剩多少空间”有感知,否则它会写出超过容量的内容。
- 分页(pagination):检索函数本身带分页参数,设计上就保证一次检索不会打爆窗口——与
Lost in the Middle的教训一致。
4. 控制流:事件、函数链、自发唤醒
Event 是推理的唯一触发器,共四类:
- 用户消息
- 系统消息(如容量警告)
- 用户行为事件(登录、文档上传完成)
- 定时事件(scheduled interrupt)——让 agent 在没有任何用户输入时自主醒来做事(整理记忆、写摘要、主动开口)。这是”长期陪伴型 agent”的关键,也是后来 sleep-time compute 的雏形。
Function chaining:函数可带特殊参数 request_heartbeat=true,表示”执行完立刻再跑一次推理”,于是能在一次用户交互内串联多次调用(翻多页检索结果、多跳 KV 查询、跨文档拼合)。不带此参数则算 yield——把控制权交还用户,等下个事件。这等价于系统调用的”返回/继续”语义。
5. 实验
5.1 对话智能体(Multi-Session Chat)
数据集:每个人的 5 个 session、每 session ~12 条消息;作者新增第 6 个 session只放一个 QA 对。
DMR(Deep Memory Retrieval)——一致性:用另一个 LLM 自指令生成问题,硬约束是”只能用旧对话内容回答、不能靠 persona 摘要蒙对”。指标:ROUGE-L recall + LLM judge(明确要求宽松,容忍冗长)。
| 模型 | 准确率 | ROUGE-L(R) |
|---|---|---|
| GPT-3.5 Turbo | 38.7% | 0.394 |
| + MemGPT | 66.9% | 0.629 |
| GPT-4 | 32.1% | 0.296 |
| + MemGPT | 92.5% | 0.814 |
| GPT-4 Turbo | 35.3% | 0.359 |
| + MemGPT | 93.4% | 0.827 |
基线只能看到”过去五轮对话的有损摘要”,MemGPT 有全量历史但必须分页检索才能取回——也就是说,“能检索”本身还不够,得靠模型自己翻对页。
Conversation opener——参与感:生成开场白与 gold persona(SIM-1/3)、与人类开场白(SIM-H)的相似度。MemGPT + GPT-4 的 SIM-1 = 0.868 > Human 0.800——记忆驱动的主动个性化可以超过人工写作。论文特别指出:把信息放进 working context 是生成好开场白的关键,即”hot memory”比”检索”更重要。
5.2 文档分析
多文档 QA(沿用 Lost in the Middle 的 retriever-reader 设置):
同一 retriever(text-embedding-ada-002 + 余弦相似度),基线取 top-K 塞窗口,MemGPT 则把整个文档集灌进 archival storage,用 archival search 自己检索并翻页。
结论:
- 基线上限 ≈ retriever 上限(gold 文档没被召回就永远看不到)。
- MemGPT 准确率不随文档总量下降,因为可用文档数不再受窗口容量限制;即使排序有噪声,只要 gold 文档在排名里,多翻几页就能找到。
- 但实测 MemGPT 经常”翻页翻到一半就停”,没穷尽检索——自主检索的**提前终止(premature stop)**是主要失败模式。
- GPT-3.5 版本显著退化(函数调用能力不足),GPT-4 最佳;GPT-4 与 GPT-4 Turbo 在该任务上等价。
嵌套 KV 检索(新任务):140 对 UUID(≈8k token ≈ GPT-4 窗口),value 本身可能是 key,形成 0–4 层多跳查找。
- GPT-3.5 在 1 层就 0%(典型失败:直接返回原始 value);GPT-4/Turbo 在 3 层掉到 0%。
- MemGPT + GPT-4 基本不随层数衰减,靠反复函数查询完成多跳拼合;MemGPT + Turbo/3.5 也在 2 层后开始衰减(“没查够次数”)。
- 提示词技巧(附录):
DO NOT STOP SEARCHING UNTIL YOU VERIFY THAT THE VALUE IS NOT A KEY—— 用显式的终止判据来治”提前停止”。
6. 批判性观察
- 成本没有被认真量化:每次换出要一次摘要推理,每次翻页要一次完整推理,多跳任务 token 成本很高,论文没给成本曲线。
- “LLM 当内核”不鲁棒:GPT-3.5 全面崩盘说明自我内存管理的可靠性直接绑定底层模型的函数调用能力;模型会忘记写回、误判余量、提前停止检索。
- 评测规模偏小:DMR 采样规模有限、judge 宽松;基线的”有损摘要 + 固定截断”对现代 RAG 基线略弱。
- Working context 是启发式固定块:无淘汰策略,写什么全靠模型自觉;水位信号也只有”内存压力”一条,粒度粗。
- 未涉及真正 OS 的核心问题:并发、多任务隔离、崩溃恢复、内存一致性——这些是后续工作(Letta / sleep-time compute)的空白区。
7. 与 harness-lab 的对应(本仓库现状 → 可做的实验)
你已经实现了简化骨架,缺口很清晰:
| MemGPT 机制 | harness_lab 现状 | 差距 |
|---|---|---|
| 三段式 main context | context.py 只有 system + 线性 history | 缺 working_context 常驻块 |
| 可写 working context | 无 | 缺 core_memory_append/replace 工具 |
| 70% 内存压力警告 | RollingSummaryContext 静默摘要,模型无感知 | 改成”先警告让模型自己写回,超限才 flush” |
| Recall storage | Trace 只记日志,不参与检索 | 落 sqlite + conversation_search(带分页) |
| Archival(向量库) | KeywordMemory 关键词重叠(零依赖) | 换 embedding;论文教训:检索质量决定上限,但可多次翻页突破 |
request_heartbeat | loop.py 的 for 循环天然支持多步 | 可区分”yield 回用户”vs”继续自循环”,统计 steps_per_event |
| 定时事件/自发唤醒 | 无(run() 一次性任务) | 加 scheduled event runner,即 sleep-time compute 雏形 |
| 内存管理评测 | metrics.py 只有成功率与 token | 加 DMR 式跨 session 一致性 + 嵌套 KV 多跳任务 |
| 错误反馈闭环 | _execute_tool 已把异常转字符串回喂 ✅ | 可补”容量超限”语义错误 |
优先做两件(成本低、区分度高):
working_context+ 水位线警告:把静默摘要改成”警告 → 模型自主写回 → 超限才 flush”,在config/experiments.yaml开 A/B(rolling_summaryvsmemgpt_style),观察的不只是tokens_saved,而是任务成功率——这才是论文的核心论点(自主管理 > 被动压缩)。- DMR 式跨 session 任务:在
tasks/加多轮次任务(同一 workspace 分 4–5 次run(),最后问早期细节),量出”memory on/off”与”关键词 vs embedding 检索”的差距,能直接和论文 Table 2 对照。
一句话启示:MemGPT 的贡献不是”给 agent 加个向量库”,而是把上下文管理变成模型的一等公民动作——有预算感、有水位线、有可写热区、有降级存储、有中断与函数链。复刻它,重点在水位线与自主写回,而不是检索器精度。
附:论文关键数据速查
上下文长度对照表(论文 Table,“messages” 按 1k preprompt + 50 token/消息估算):
| 模型 / API | 开源? | Tokens | ≈消息数 |
|---|---|---|---|
| Llama 1 | ✅ | 2k | 20 |
| Llama 2 | ✅ | 4k | 60 |
| GPT-3.5 Turbo(初版) | ❌ | 4k | 60 |
| Mistral 7B | ✅ | 8k | 140 |
| GPT-4(初版) | ❌ | 8k | 140 |
| GPT-3.5 Turbo | ❌ | 16k | 300 |
| GPT-4 | ❌ | 32k | ~600 |
| Claude 2 | ❌ | 100k | ~2000 |
| GPT-4 Turbo | ❌ | 128k | ~2600 |
| Yi-34B-200k | ✅ | 200k | ~4000 |
Conversation opener 结果(相似度越高越好):
| 方法 | SIM-1 ↑ | SIM-3 | SIM-H |
|---|---|---|---|
| Human | 0.800 | 0.800 | 1.000 |
| MemGPT (GPT-3.5 Turbo) | 0.830 | 0.812 | 0.817 |
| MemGPT (GPT-4) | 0.868 | 0.843 | 0.773 |
| MemGPT (GPT-4 Turbo) | 0.857 | 0.828 | 0.767 |
已公开资源:增强版 MSC 数据集、嵌套 KV 数据集、20M 篇 Wikipedia 文章 embedding、benchmark 代码(research.memgpt.ai)。