跳到主要内容

Letta (MemGPT) — 架构与原理

30 秒导读: Letta(原名 MemGPT)是一个有长期记忆的 LLM agent 框架。它的核心洞见:LLM 的上下文窗口有限,就像计算机内存有限——那就借操作系统的分页思路,让 agent 用工具自己编辑一块「常驻内存」,并把放不下的对话历史和知识换页到数据库里,需要时再搜回来。这样 agent 能跨会话记住你是谁、聊过什么。


1. 这是什么(零基础也能懂)

一句话定义: Letta 是一个让 LLM agent 拥有持久、可自我编辑的记忆的框架——agent 不是每次对话都从零开始,而是记得过去、并能主动整理自己的记忆。

它解决谁的什么问题。 普通聊天机器人有个硬伤:上下文窗口装满就忘。你今天告诉它「我叫 Timber、我养狗」,聊久了这句被挤出窗口,它就再也不知道了。Letta 要解决的就是:

  • 怎么让 agent 跨会话记住关于你的事实?
  • 上下文塞不下时,该丢什么、该留什么、丢掉的怎么找回来?
  • 能不能让 agent 自己决定把哪条信息写进长期记忆?

核心类比(记住这一个就够了):把 LLM 当一台只有一点点内存的电脑。

计算机概念Letta 里对应什么特点
RAM(内存,快但小)上下文窗口里常驻的「记忆块」(core memory)模型每一步都能直接看到,但有字符上限
磁盘(慢但大)数据库里的归档记忆(archival)+ 历史消息(recall)装得多、永久存,但要用工具「搜」才能调进来
操作系统的换页Letta 的压缩(compaction)+ 搜索工具把溢出的东西移到磁盘,需要时再读回内存

这就是 MemGPT 那篇论文的全部精髓:给 LLM 配一个「内存管理器」,让它像操作系统管理内存一样管理自己的上下文。

它能做什么:

  • 维护一块始终在上下文里的核心记忆(比如 human 块记你是谁、persona 块记 agent 自己的设定)。
  • 让 agent 用工具自己改写这块核心记忆(发现新事实就 append、信息过时就 replace)。
  • 把对话历史和长期知识存进数据库,用语义搜索找回来。
  • 上下文快满时自动压缩旧消息成摘要,腾出空间继续聊。

用起来什么样。 创建 agent 时给它两块初始记忆,然后发消息——它会记住:

# 示意:来自 README 的真实用法
from letta_client import Letta
client = Letta(api_key=...)

agent = client.agents.create(
model="openai/gpt-5.2",
memory_blocks=[
{"label": "human", "value": "Name: Timber. 养了一条狗。"}, # 关于用户的常驻记忆
{"label": "persona", "value": "我是一个会自我改进的助手。"}, # 关于 agent 自己的常驻记忆
],
tools=["web_search", "fetch_webpage"],
)
# 之后发消息;agent 会把它学到的关于 Timber 的新事实写进 human 块,跨会话保留
client.agents.messages.create(agent.id, input="What do you know about me?")

这两个块(human / persona)会被渲染进系统提示、每一步都喂给模型——见 letta/schemas/memory.py:840-854(ChatMemory)。

本节不碰底层。记住一句话就行:Letta = 给 LLM 装一个内存管理系统,让它能记事、能自己整理记忆。


2. 顶层全景(它大概怎么转)

2.1 三层记忆 + 一个工具循环

Letta 的整个系统可以拆成两件事:记忆放在哪(三层存储)agent 怎么动(工具驱动的循环)

先看记忆的三层结构——这是「内存 vs 磁盘」类比的具体落地:

┌──────────────────────── 上下文窗口(模型每一步都能看到) ────────────────────────┐
│ │
│ 系统提示 = 基座指令 + <memory_blocks>(core memory) + <memory_metadata> │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ human 块 │ │ persona 块 │ ← 这就是「RAM」:常驻、可被 agent 改写 │
│ └──────────────┘ └──────────────┘ │
│ │
│ 最近的对话消息(recall 的「在上下文那部分」) │
└────────────────────────────────────────┬───────────────────────────────────────┘
│ 工具读 / 写 / 搜
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ recall memory │ │ archival memory │ │ core memory 工具 │
│ = 全部历史消息 │ │ = 长期知识(向量) │ │ 改写 RAM 的工具 │
│ (数据库) │ │ (数据库 + 嵌入) │ │ │
└───────────────┘ └─────────────────┘ └──────────────────┘
conversation_search archival_memory_search memory_replace / insert
(按文本+语义搜历史) (按语义+标签搜知识) core_memory_append ...

怎么读这张图(从上到下 = 从「内存」到「磁盘」): 上面方框是模型每一步实际看到的上下文;下面三个方框是数据库里的东西,模型看不到,只能通过箭头上的工具把它们搜进上下文。

2.2 三层记忆,一句话各是什么

记忆层是什么在不在上下文里怎么访问代码锚点
Core memory(核心/常驻)一组「记忆块」(human/persona/自定义),每块有 label、description、value、字符上限(渲染进系统提示)agent 用 memory_replace / memory_insert / core_memory_append 等工具自己改letta/schemas/memory.py:68(Memory)、schemas/block.py:67(Block)
Recall memory(回忆)这个 agent 的全部历史消息,存在数据库只有最近一段在conversation_search(文本 + 语义混合搜)functions/function_sets/base.py:87(conversation_search)
Archival memory(归档)agent 主动写入的长期事实/知识,带向量嵌入和标签不在(永远在数据库)archival_memory_insert 写、archival_memory_search 按语义搜functions/function_sets/base.py:164,194

2.3 主线走一遍(高层,不进代码)

一条用户消息进来,大致经历:

  1. 组装上下文。 取出系统提示(里面已嵌入 core memory 块)+ 在上下文的历史消息 + 这条新消息。
  2. 调模型。 把上面这一大坨连同可用工具的定义发给 LLM。
  3. 模型回应。 它要么直接回话(发 send_message),要么调一个工具——比如 archival_memory_search 去翻长期记忆,或 memory_replace 去更新你的资料。
  4. 执行工具、决定是否继续。 关键规则(v3):调了工具就继续循环、没调工具就结束(agents/letta_agent_v3.py:1979)。这样 agent 能连着搜记忆、改记忆、再回话。
  5. 持久化。 新产生的消息写库;若上下文逼近上限,触发压缩把旧消息换成摘要。

这个工具驱动的循环 + 三层记忆,就是 Letta 的「大盘」。


3. 顺着读下去

这是个大项目,下面按由浅入深拆成四章。建议顺序:

  1. 01-memory-tiers.md — 先彻底搞懂三层记忆:记忆块长什么样、怎么渲染进提示、agent 用哪些工具读写、归档的语义搜索怎么工作。这是 Letta 的灵魂。
  2. 02-agent-loop.md — 再看 agent 怎么动:v3 工具驱动主循环,以及它和老版 MemGPT「心跳(heartbeat)」模型的区别。
  3. 03-system-prompt-assembly.md — 深入系统提示是怎么一块块拼出来的,以及「只在记忆变化时才重建提示」这个性能优化。
  4. 04-compaction-and-internals.md — 上下文满了怎么办(压缩)、整套设计的巧妙之处、边界、横向对比、代码地图。

如果你只想要一句话精华:Letta 把「上下文管理」从一个被动的截断问题,变成了一个 agent 能主动用工具操作的、像操作系统分页一样的系统。