MemGPT - Towards LLMs as Operating Systems · essay
01. MemGPT:把 LLM 当成操作系统来管理记忆
论文:MemGPT: Towards LLMs as Operating Systems
链接:https://arxiv.org/abs/2310.08560
代码:https://github.com/cpacker/MemGPT
本地原文:
![[papers/01-MemGPT-2310.08560.pdf]]
论文定位与阅读路径
核心定位
MemGPT 的核心想法是:LLM 的上下文窗口太小,所以要像操作系统管理内存一样,让 Agent 自己决定什么时候把信息放进上下文、什么时候把信息移到外部存储。
原文结构导读
| 原文部分 | 主要任务 | 阅读时抓什么 |
|---|---|---|
| Introduction | 提出有限上下文和长期对话矛盾 | 作者不是单纯扩大窗口,而是把上下文当成可调度资源 |
| MemGPT Architecture | 定义主上下文、外部上下文和函数调用 | 看清楚“模型可见内存”和“外部存储”的边界 |
| Memory Management | 说明何时读写、替换、压缩记忆 | 关注谁做决策、决策依据是什么、失败时如何恢复 |
| Experiments | 对话、文档问答、任务型场景验证 | 看它证明的是“记忆调度有效”,不是证明模型真正学会新知识 |
| Discussion | 讨论系统限制和未来扩展 | 注意 prompt 驱动的内存管理会带来不稳定性和审计问题 |
证据链阅读
| 证据点 | 读什么 | 工程判断 |
|---|---|---|
| 上下文调度效果 | 长对话/长文档任务是否比固定上下文更稳 | 证明“分页式记忆管理”有收益 |
| 函数调用轨迹 | 模型何时 page in / page out | 判断调度决策是否可审计 |
| 失败案例 | 什么时候取错记忆或忘记关键信息 | 需要 fallback、trace 和人工可检查日志 |
| 与 RAG 对比 | MemGPT 是否只是多了一层检索 | 它的核心是可见上下文管理,不是单次 top-k |
研究背景与问题定义
先懂背景
普通聊天机器人是:
代码块收起展开
历史消息 + 当前问题 -> LLM -> 回答问题是上下文窗口有限。对话一长,早期信息就放不下。MemGPT 用一个操作系统隐喻解决这个问题:
| 操作系统 | MemGPT |
|---|---|
| RAM | 当前上下文窗口 |
| Disk | 外部长期记忆 |
| Page in | 把相关记忆加载进上下文 |
| Page out | 把不常用内容移出上下文 |
| System call | 模型调用记忆工具 |
它解决的问题
MemGPT 要解决三件事:
- 长对话中,模型不能永远记住所有历史。
- 用户信息、偏好、事实需要长期保存。
- 记忆管理不能全靠开发者手写规则,Agent 要能自主决定。
方法框架与核心机制
核心架构
MemGPT 不是简单加一个向量库。它强调“模型自己通过工具管理记忆”。
关键机制拆解
1. 分层记忆
MemGPT 把信息分成几层:
- 当前上下文:模型这次推理能直接看到。
- 核心记忆:用户画像、长期偏好、任务目标。
- 归档记忆:大量历史对话、文档、外部知识。
概念解释:核心记忆像便利贴,归档记忆像资料柜。
2. 自主管理
模型可以调用类似这样的工具:
代码块收起展开
core_memory_append
core_memory_replace
archival_memory_insert
archival_memory_search这相当于让模型拥有“读写记忆”的系统调用。
3. 上下文调度
模型不是把所有历史都塞进 prompt,而是根据当前任务检索相关记忆。
这对工程很重要:上下文窗口是最贵的资源,不能无脑塞。
概念校准
你写课程作业时,脑子里只能同时想几个关键点,这是“工作记忆”。桌面上的草稿纸是“短期上下文”。硬盘里的资料、笔记、书签是“长期记忆”。MemGPT 做的事,就是让 Agent 会自己翻资料、整理便利贴、把重要信息存档。
工程映射与实践启发
工程落地方案
如果用 Java/Spring Boot 实现一个简化版:
| 模块 | 作用 |
|---|---|
MemoryService | 写入/更新长期记忆 |
MemorySearchService | 检索相关记忆 |
ContextBuilder | 把检索结果拼进 prompt |
ToolExecutor | 执行 memory 工具调用 |
MemoryAuditLog | 记录 Agent 何时写入/修改记忆 |
最小表设计:
代码块收起展开
memory(id, user_id, type, content, embedding, importance, created_at, updated_at)这篇的价值
MemGPT 的价值不是某个算法公式,而是提出了一个很强的系统视角:
Agent 需要像操作系统一样管理有限上下文和无限外部记忆。
局限、对比与阅读检查
局限与边界
- 让模型自主写记忆,可能写错、写重复、写隐私。
- 记忆工具调用增加成本和延迟。
- 需要评估“写入的记忆是否真的有用”。
- 如果检索不好,长期记忆再多也没用。
阅读重点
读这篇时重点看:
- 它如何类比 OS 内存管理。
- 它有哪些记忆工具。
- 它如何区分核心记忆和归档记忆。
- 它如何证明长对话能力提升。
- 它的思想如何迁移到你的 Personal Knowledge Agent。
和后续论文关系
MemGPT 是应用驱动派的代表。Mem0、Zep、MemOS 都可以看成是在回答:如果要把 MemGPT 这种记忆系统做成生产级,记忆该怎么抽取、更新、去重、治理和评测?
原文精读补充
1. Abstract 要抓什么
原文摘要的主线是:LLM 的上下文窗口有限,但很多任务需要持续交互、长文档处理和长期状态,所以作者把 LLM 类比为操作系统,用“虚拟上下文管理”来连接有限上下文和外部记忆。
你读摘要时要把三个词圈出来:
| 词 | 为什么重要 |
|---|---|
| limited context | 说明问题根源是上下文窗口 |
| virtual context | 说明 MemGPT 不是单纯扩窗口,而是做上下文虚拟化 |
| self-directed editing/retrieval | 说明模型自己决定什么时候读写记忆 |
2. 它为什么叫 OS
操作系统的核心任务之一,是把有限物理内存包装成更大的虚拟内存。MemGPT 借这个思想处理 LLM:
代码块收起展开
物理内存有限 -> OS 把部分内容换入/换出磁盘
上下文有限 -> MemGPT 把部分信息换入/换出外部记忆所以 MemGPT 的创新不只是“加数据库”,而是:
- 把上下文看成稀缺资源。
- 把外部记忆看成可分页存储。
- 把 memory tool 看成系统调用。
- 让 LLM 主动决定内存管理动作。
3. 原文里的两类外部上下文
你可以把 MemGPT 的记忆分成两块:
| 记忆 | 工程解释 | 适合存什么 |
|---|---|---|
| Core memory | 常驻便利贴 | 用户名、偏好、长期目标 |
| Archival memory | 资料柜 | 长历史、文档、过去对话 |
这对工程很重要。不是所有记忆都应该检索时才拿,有些高频稳定信息应该常驻在 prompt 的短小区域。
4. 为什么它不等于普通摘要
普通长对话摘要通常是:
代码块收起展开
对话太长 -> 总结一下 -> 继续聊MemGPT 是:
代码块收起展开
模型发现需要记忆操作 -> 调工具读写 core/archival memory -> 再继续推理差异在于控制权。摘要是开发者固定策略;MemGPT 强调 Agent 自主调度。
5. 实验怎么看
原文主要验证两个方向:
- 长对话场景中,系统能跨很久找回信息。
- 文档分析场景中,模型能处理超过上下文窗口的材料。
你不用先记所有指标,先问:
代码块收起展开
baseline 只能看到多少上下文?
MemGPT 是否能通过外部记忆补回被挤出去的信息?
工具调用次数和正确率之间有没有代价?6. 工程落地提醒
如果你做自己的 Personal Knowledge Agent,MemGPT 告诉你三条底线:
ContextBuilder必须是核心模块,不能到处散落拼 prompt。- 记忆写入要可审计,不能让模型偷偷改长期记忆。
- 常驻记忆和检索记忆要分层,否则上下文会被低价值历史占满。
深度精读:把 MemGPT 真正拆开
1. 论文真正要解决的不是“记不住”,而是“上下文资源调度”
很多人读 MemGPT 会停在一句话:给 LLM 加长期记忆。这个理解太浅。MemGPT 真正的问题定义是:
代码块收起展开
LLM 的推理能力依赖当前上下文;
当前上下文容量固定且昂贵;
任务需要的信息总量经常超过上下文;
所以需要一个机制决定哪些信息在当前上下文,哪些信息放在外部存储。这和操作系统里的虚拟内存问题几乎同构:
| OS 问题 | LLM Agent 问题 |
|---|---|
| 物理内存有限 | context window 有限 |
| 磁盘容量大但慢 | 外部数据库容量大但需要检索 |
| 页面置换策略 | 哪些消息/记忆保留在 prompt |
| page fault | 当前推理发现缺信息 |
| system call | LLM 调用 memory function |
所以 MemGPT 不只是 memory store,而是一个 context operating system。
2. 控制权设计才是这篇的精华
普通 RAG 的控制权在程序员手里:
代码块收起展开
每次用户提问 -> 程序检索 topK 文档 -> 拼 prompt -> LLM 回答MemGPT 的控制权部分交给 LLM:
代码块收起展开
LLM 推理时发现需要信息 -> 主动调用 archival_memory_search
LLM 发现用户长期偏好变化 -> 主动调用 core_memory_replace
LLM 发现新事实值得保存 -> 主动调用 archival_memory_insert这带来一个工程矛盾:
| 好处 | 风险 |
|---|---|
| Agent 更自主 | 可能乱写记忆 |
| 只在需要时检索 | 可能漏检索 |
| 能动态管理上下文 | 难调试 |
| 更接近真实长期助手 | 需要权限和审计 |
你以后写 Agent,不能只问“要不要让模型调工具”,还要问:
代码块收起展开
哪些工具允许模型主动调用?
哪些调用需要用户确认?
哪些调用只读?
哪些调用会修改长期状态?3. Core memory 和 archival memory 的区别要吃透
Core memory 是“常驻小内存”,archival memory 是“大容量资料库”。两者不是容量差别那么简单,而是语义职责不同。
| 维度 | Core Memory | Archival Memory |
|---|---|---|
| 位置 | 基本常驻 prompt | 外部存储,按需检索 |
| 内容 | 极少量关键事实 | 大量历史、资料、事件 |
| 更新频率 | 较低,但每次更新很重要 | 较高,可追加 |
| 风险 | 写错会长期污染行为 | 检索错会局部影响回答 |
| 例子 | 用户 A 偏好中文深讲 | 某次论文学习会话的细节 |
一个常见错误是把所有“用户信息”都放 core memory。这样 prompt 很快膨胀。正确做法是:
代码块收起展开
只把高频、稳定、强影响的信息放 core;
其他放 archival,通过检索进入上下文。4. MemGPT 的函数调用不是“插件”,而是内存指令集
你可以把 memory functions 当成一组指令:
| 指令 | 类比 | 作用 |
|---|---|---|
core_memory_append | 写便利贴 | 补充核心事实 |
core_memory_replace | 改便利贴 | 更新核心事实 |
archival_memory_insert | 存档 | 保存长期材料 |
archival_memory_search | 查档案 | 找过去相关信息 |
这给你一个 Agent 设计原则:
代码块收起展开
工具不是越多越好。
工具应该围绕状态变化设计成少量稳定原语。比如你的 Obsidian Agent 可以先有:
代码块收起展开
note_search(query)
note_read(path)
memory_add(scope, content)
memory_update(id, patch)
memory_search(scope, query)
trace_record(event)少而准,比一上来塞几十个工具更可控。
5. 递归摘要解决的不是记忆,而是上下文垃圾回收
长对话不可能永久保留所有消息。递归摘要做的是:
代码块收起展开
旧 summary + 即将被移出的消息 -> 新 summary这个结构比“每次重新总结全部历史”便宜,但有信息损失:
- 摘要会丢细节。
- 摘要错误会被后续摘要继承。
- 多次递归后可能产生漂移。
- 摘要必须和可检索原始记录配合。
所以工程上不要只保存 summary。更稳的做法是:
代码块收起展开
原始消息归档 + 滚动摘要 + 关键记忆抽取6. 最小实现伪代码
代码块收起展开
class AgentRuntime {
// handle = 一轮用户输入的总调度入口。
Answer handle(UserMessage input) {
// ContextBuilder 负责把当前问题、短期历史、长期记忆页组装成模型上下文。
Context ctx = contextBuilder.build(input);
// 循环存在的原因:模型可能先要求调用工具/翻页,而不是直接回答。
while (true) {
ModelOutput out = llm.call(ctx);
if (out.isFinalAnswer()) {
// 最终回答出现后,再考虑是否把这轮对话抽成长期记忆。
memoryWriter.maybeExtract(input, out);
return out.answer();
}
// toolCall 可以是搜索、读取记忆页、写入记忆页等运行时动作。
ToolCall call = out.toolCall();
ToolResult result = toolExecutor.execute(call);
// auditLog 是可追责边界:之后调试时能知道模型为什么用了某个工具。
auditLog.record(call, result);
// 工具结果必须回填上下文,否则模型下一步看不到外部动作的结果。
ctx = ctx.withToolResult(result);
}
}
}这里的重点是循环:
代码块收起展开
模型输出 -> 工具调用 -> 工具结果回填 -> 模型继续推理MemGPT 的 memory function 就在这个循环里生效。
7. 读实验时要追问
不要只看“MemGPT 比 baseline 高”。要追问:
- 任务是否真的超过上下文窗口。
- baseline 是否也有摘要/检索能力。
- MemGPT 是因为更会检索,还是因为 prompt 更长。
- 工具调用次数是否可接受。
- 错误案例是没写入、没检索、检索错,还是模型读了也没用。
这是工程读论文的方式。
8. 对你项目的直接结论
Personal Knowledge Agent 至少要有三层上下文:
| 层 | 内容 |
|---|---|
| Session context | 当前对话和任务状态 |
| Core user/project memory | 用户长期偏好、当前项目关键规则 |
| Retrieved archival context | 从 Obsidian/历史任务/论文库检索的材料 |
不要把它们混成一个长 prompt。混在一起后,压缩、审计、权限和评测都会变得很难。
论文精读主线:问题-方法-验证-局限-启发
1. 核心结论
MemGPT 把 LLM 的有限上下文窗口抽象成主内存,把外部记忆抽象成磁盘,让 Agent 通过工具调用主动读写和调度记忆。它的贡献不是多接一个向量库,而是把记忆管理变成 runtime 控制循环。
本篇的阅读重心是:上下文窗口被当成可调度资源,而不是一次性 prompt 容器。读完后要能说清它改变的是 runtime、存储、检索、更新还是评测层;否则只是记住了论文名。
2. 问题背景
长对话、长文档和跨会话任务都会超过上下文窗口。截断会丢早期事实,摘要会牺牲细节,普通检索又缺少何时检索、检索多少、怎样回填的控制。MemGPT 认为问题本质不是窗口不够长,而是上下文缺少类似操作系统的资源调度。
把问题具体化为失败样例:用户早期给出项目约束,后续要求继续实现;普通长对话截断后忘掉约束,普通检索又不知道何时主动查。用这个样例反推论文动机,比泛泛说“上下文不够”或“记忆不准”更有判断力。
3. 核心方法
系统把记忆分成 core memory 和 archival memory。core memory 放少量高频稳定事实,archival memory 放大量可检索资料。模型每轮可以选择直接回答,也可以调用 memory search、insert、replace 等函数,runtime 执行后把结果回填上下文。
flowchart TD
U[用户输入] --> C[当前上下文]
C --> M{模型判断是否缺信息}
M -->|缺历史事实| S[检索 archival memory]
M -->|需要保存稳定事实| W[更新 core/archive]
S --> C
W --> C
M -->|信息足够| A[最终回答]
方法部分按数据流读:用户输入进入 ContextBuilder,模型提出 search/insert/replace 意图,runtime 执行工具并把结果回填,再记录 trace。每一步都要能标出输入、输出、控制点和失败后该记录的日志。
4. 技术细节
核心技术不是某个公式,而是边界设计:模型只能提出工具调用意图,真正读写由 runtime 执行;core memory 必须小而稳定;archival memory 必须保留来源;上下文构造器必须按预算放入系统指令、短期对话、长期检索结果和工具返回。
代码块收起展开
final class MemGptRuntime {
private final ContextBuilder contextBuilder; // 按 token 预算组装 core memory、最近消息和检索证据
private final MemoryToolExecutor memoryTools; // 执行模型请求的 search/insert/replace,不让模型直接改库
private final MemoryPolicy policy; // 校验哪些内容能写入长期记忆、哪些需要用户确认
private final TraceLogger traceLogger; // 记录每次工具调用、记忆命中和写入原因
MemoryResult handle(MemoryInput input) {
// 1. 按 token 预算组装 core memory、最近消息和检索证据
// 2. 执行模型请求的 search/insert/replace,不让模型直接改库
// 3. 校验哪些内容能写入长期记忆、哪些需要用户确认
// 4. 记录每次工具调用、记忆命中和写入原因
// 返回结果时必须带 evidence、confidence、traceId,方便以后追查记忆为什么生效。
return MemoryResult.withTrace(input.traceId());
}
}字段检查重点是 coreKey、archivalSource、toolReason、budgetSlot、traceId 要能解释每条记忆为什么进入上下文。这些字段不是装饰,它们决定后续能否检索、审计、回滚、限权和做离线评测。
5. 实验验证
实验应证明模型在信息超出上下文窗口后仍能找回早期事实。重点看任务是否真的超过窗口、baseline 是否也有检索能力、MemGPT 的收益是否来自主动读写记忆而不是更长 prompt。长对话一致性和长文档问答都要检查答案是否引用了被调入的记忆。
实验阅读重点:检查收益是否来自主动调度记忆,而不是简单把历史塞长;同时看工具调用次数、无效检索和写错 core memory 的比例。如果论文没有直接给出这层证据,复现时就要自己补机制级指标。
6. 局限与启发
局限是模型自主调度不稳定:可能该查不查、乱查、写错 core memory 或频繁调用工具导致延迟。启发是 Obsidian Agent 不能把笔记一次性塞进 prompt,而应把上下文构造、长期检索、核心偏好、审计日志拆成独立层。
迁移到你的项目时,结论是:Personal Knowledge Agent 的第一层应是上下文调度器;没有它,RAG、记忆表和工具都会挤进一个不可审计的长 prompt。先把边界做对,再追求更复杂的模型或更大的记忆规模。
7. 关键术语表
| 术语 | 在论文里的意思 | 工程落地时要看什么 |
|---|---|---|
| Core memory | 小容量常驻稳定事实 | 用户长期偏好、Agent 身份、当前长期目标 |
| Archival memory | 大容量外部可检索记忆 | 向量库、全文索引、历史文档 |
| Virtual context | 用外部记忆扩展有限上下文 | 检索、回填、压缩、替换循环 |
| System call | 模型请求 runtime 执行状态操作 | tool calling 加权限校验 |
8. 复现难点
复现最难的是工具调用策略和写入质量。简单规则很难判断何时检索、查什么、写什么;错误写入比漏写更危险。必须实现记忆审计、可撤销更新、检索结果限流和工具失败降级。
复现入口应从失败集开始:先构造“第 1 轮规则、第 20 轮继续”的超窗口任务,再比较无记忆、被动 RAG、主动记忆工具三种链路。只有先证明旧方案会坏,才知道新机制是否真的解决了问题。
9. 代码框架建议
先做 archival_search(query, topK)、archival_insert(text, source)、core_replace(field, oldValue, newValue, reason) 三个工具。每次调用都写入 memory_audit_log,字段包含 toolName、args、resultIds、reason、createdAt。
代码验收门槛:最小实现必须输出 contextPlan:哪些内容常驻、哪些来自检索、哪些被丢弃、丢弃原因是什么。这条门槛应写进测试或 trace 字段里,避免实现只停留在 demo。
10. 相关论文对比
MemGPT 是系统隐喻的起点;Mem0 更像写入控制器;MemoryBank 更关注用户画像和遗忘;Zep 把长期记忆结构化成时序事实图;MemOS 则把这种思想上升到基础设施治理。
横向比较时抓这个角度:它和 Mem0 的差别在 runtime 调度,而不是写入决策;和 Zep 的差别在上下文分页,而不是事实图谱。比较对象不是谁“更先进”,而是谁负责哪一层失败。
11. 批判性思考
MemGPT 的 OS 类比很强,但 LLM 的工具决策没有真正操作系统那样确定。落地时必须追问:写错记忆如何撤销,多用户如何隔离,工具成本是否可控,检索出来的记忆是否真的被答案使用。
批判边界:OS 隐喻不能掩盖 LLM 工具决策的不确定性;生产系统必须有人工确认、预算限流和错误写入回滚。这不是否定论文,而是把论文结论放回真实系统的成本、权限和恢复约束里。