记忆块与睡眠时计算 本节摘要:MemGPT(第 07 节)解决了虚拟内存的控制流,但生产里冒出三个新问题:每次记忆操作都卡在关键路径上,尾巴延迟爆炸;写入堆积、矛盾事实残留,检索被陈旧内容淹没;扁平归档库表达不出「Human 块常驻提示、Persona 块常驻、Task 块按会话换」。Letta(MemGPT 在 2024 年的产品化名字)用两个机制回答:记忆块(Memory Blocks) 把结构变成模型可直接编辑的一等公民类型化对象——Human 块、Persona 块、以及任意的 Task / Project / Safety 块;睡眠时计算(Sleep-Time Compute) 让一个后台 Agent 在主 Agent 空闲时异步地合并、去重、作废记忆。
本节摘要:MemGPT(第 07 节)解决了虚拟内存的控制流,但生产里冒出三个新问题:每次记忆操作都卡在关键路径上,尾巴延迟爆炸;写入堆积、矛盾事实残留,检索被陈旧内容淹没;扁平归档库表达不出「Human 块常驻提示、Persona 块常驻、Task 块按会话换」。Letta(MemGPT 在 2024 年的产品化名字)用两个机制回答:记忆块(Memory Blocks) 把结构变成模型可直接编辑的一等公民类型化对象——Human 块、Persona 块、以及任意的 Task / Project / Safety 块;睡眠时计算(Sleep-Time Compute) 让一个后台 Agent 在主 Agent 空闲时异步地合并、去重、作废记忆。本节吃透三层记忆(Core / Recall / Archival)、记忆块的工具面、睡眠期 Agent 的三个性质(零延迟代价、可上更强模型、天然的合并窗口),并用标准库实现一个双 Agent 脚本循环:主 Agent 负责响应、睡眠 Agent 在轮次间整理块。读完本节,你应理解记忆如何从「单次对话」扩展到「跨对话持久」。
对应原课程:Phase 14 · Lesson 08 ·
memory-blocks-sleep-time-compute(原英文phases/14-agent-engineering/08-memory-blocks-sleep-time-compute/docs/en.md)。
阅读完本节,你应当能够:
MemGPT 解决了虚拟内存的控制流,但生产里冒出三个问题:
Letta(原 MemGPT 项目 2024 年采用的平台名,论文仍叫 MemGPT)用两个机制解决:记忆块让结构显式化,睡眠时计算把合并移出关键路径。
MemGPT 的两层(主上下文 + 外部)在生产里被拆成三层,各自职责清晰:
| 层级 | 范围 | 住在哪 | 谁来写 |
|---|---|---|---|
| 核心 Core | 始终可见 | 主提示词内 | Agent 工具调用 + 睡眠期重写 |
| 回忆 Recall | 对话历史 | 可检索 | 自动轮次日志 |
| 归档 Archival | 任意事实 | 向量 + KV + 图 | Agent 工具调用 + 睡眠期摄入 |
Core 就是 MemGPT 的 core;Recall 是带淘汰尾的对话缓冲;Archival 是外部库。这个拆分清理了 MemGPT 两层模型里的职责重叠。
块(Block) 是核心层里一个类型化、持久、可编辑的区段。原 MemGPT 论文定义了两块:
Letta 推广到任意用户自定义块:Task 块装当前目标、Project 块装代码库事实、Safety 块装硬性约束。每个块都有 id、label、value、limit(字符上限)、description(让模型知道何时该编辑它)。
块通过工具面编辑(注意它们就是第 07 节记忆工具的细化):
block_append(label, text)block_replace(label, old, new)block_read(label)block_summarize(label) —— 当块接近上限时压缩它。2025 年 Letta 的新增:跑第二个 Agent 在后台,脱离关键路径。睡眠期 Agent 处理对话转录与代码库上下文,把 learned_context(学到的事实)写进共享块,并合并或作废归档记录。
由此带来的三个性质:
这个形状跟人类的工作方式一致:白天做事、晚上睡觉、长期记忆在夜里沉淀。
💡 设计要点:睡眠期是「用算力换延迟」的极致。主 Agent 只负责快和准;所有的整理、合并、深度推理都甩给一个不慌不忙的后台 Agent。这也是为什么睡眠期可以承担更贵的模型——它的代价是钱,不是用户体验。
Letta V1(letta_v1_agent, 2026)废弃了 send_message/心跳包和提示里的内联 Thought: token,改用原生推理(Native Reasoning)。OpenAI 的 Responses API 和 Anthropic 带扩展思考的 Messages API,都在单独的通道上输出推理,跨轮次透传(生产里跨厂商加密)。控制循环仍是 ReAct,但思考轨迹是结构性的,而非提示形状的。
block_append 很快就撞上限。在「会把块推过上限的那次写入」之前,先接一个块摘要器。原课程 code/main.py 实现:
Block —— id、label、value、limit、description。BlockStore —— 增删改查 + near_limit(label) 辅助。PrimaryAgent 出一轮响应,SleepTimeAgent 在轮次间整理。核心骨架如下,用伪代码展示。
class Block: def __init__(self, label, description, limit=500): self.id = f"blk_{label}" self.label = label # 如 "human" / "persona" / "task" self.description = description # 让模型知道何时该编辑 self.limit = limit # 字符上限 self.value = "" def near_limit(self, threshold=0.8): return len(self.value) >= self.limit * threshold
class BlockStore: def __init__(self): self.blocks = {} # label -> Block self.history = {} # label -> [旧值...] 用于调试与版本 def append(self, label, text): blk = self.blocks[label] self.history.setdefault(label, []).append(blk.value) blk.value += text + "\n" if blk.near_limit(): return f"警告:{label} 块接近上限,建议睡眠期摘要" return f"已追加到 {label}" def replace(self, label, old, new): blk = self.blocks[label] self.history.setdefault(label, []).append(blk.value) blk.value = blk.value.replace(old, new) return f"已替换 {label} 中的片段"
def primary_turn(ctx, user_msg): # 主 Agent:快,只做原始写入 reply = f"(主 Agent 响应 {user_msg})" ctx.store.append("task", f"用户问:{user_msg}") return reply def sleep_time_pass(ctx): # 睡眠 Agent:慢,做整理 for label, blk in ctx.store.blocks.items(): if blk.near_limit(): summary = f"(摘要 {label}: ...核心要点...)" ctx.store.blocks[label].value = summary # 压缩 invalidate_stale_archival(ctx) # 作废矛盾事实 return "睡眠期整理完成"
运行 python3 code/main.py 会展示这个分工:主 Agent 轮次很快、产出原始写入;睡眠期回合负责压缩和清理。
💡 设计要点:主 Agent 与睡眠 Agent 的分工边界要硬。主 Agent 永远不碰摘要、不去重、不作废——这些都在睡眠期做。这条边界一旦模糊,延迟又会被拉回关键路径。
| 维度 | Letta | Claude Agent SDK 技能 | 自建 |
|---|---|---|---|
| 层级数 | 3(Core/Recall/Archival) | 块状技能 + 会话存储 | 自定 |
| 睡眠期 | 内置 | 无(需自接) | 需自接 |
| 推理通道 | 原生(2026 V1) | 扩展思考 | 自定 |
| 运维形态 | 自托管/托管 | 框架内置 | 全控 |
本节产出一份可复用技能(原课程 outputs/skill-memory-blocks.md):
skill-memory-blocks.md:给定任意运行时,生成一个 Letta 形状的块系统 + 睡眠期钩子,内置安全规则与引用接线。包含块设计清单(每个块的 label / description / limit 怎么定?哪些块该有版本?哪些块该被睡眠期视为不可信?),以及睡眠期安全清单(睡眠 Agent 写 Persona / Safety 块是否需二审?learned_context 是否带来源?合并后的旧值是否归档可回溯?)。Python 代码(code/main.py)是独立可运行的双 Agent 骨架,块结构、CRUD、睡眠期钩子都是厂商无关的;把脚本 Agent 换成真实 LLM、把内存块库换成持久存储即可投入生产。
block_summarize 工具:当 near_limit 为真时,用模型生成的摘要替换块值。哪个触发阈值能同时最小化摘要调用次数和块溢出?block_history(label),让运维能调试「Agent 为什么忘了 X」。letta_v1_agent)。块模式变了什么?原生推理如何改变轨迹形状?block_append/replace/read/summarize,是第 07 节记忆工具的细化。send_message/心跳与内联 Thought:,改用厂商级单独通道输出思考。下一节,我们把记忆推向混合存储——Mem0 用向量 + KV + 图三层后端融合在一个打分层里,带冲突检测与显式作废,正是本节「睡眠期去重作废」的工程化生产版。