你有没有遇到过:同一个 Agent,上一轮刚告诉它「我叫小明、喜欢爬山」,刷新一下它又问你是谁?根因是——普通 Agent 把记忆全塞进上下文窗口,窗口一满或会话一断,记忆就没了。Letta(前身 MemGPT)是专门解决这个问题的开源框架:它把记忆拆成三层(Core / Recall / Archival),并让 Agent 自己决定「什么时候把什么写进哪层、什么时候读回来」,从而实现跨会话的长期记忆。
先搞懂:三层记忆各存什么?
| 记忆层 | 存什么 | 特点 / 何时用 |
|---|---|---|
| Core | 始终在上下文里的「人设/档案」块(如 human、persona) | 少量、高频引用;Agent 可随时编辑这些块 |
| Recall | 完整的历史对话记录 | 需要「我们之前聊过什么」时检索 |
| Archival | 长期知识库(超出上下文的文档/事实) | 海量、低频;按需检索,不占窗口 |
关键认知:记忆不是「自动变长」的,而是 Agent 主动管理的。Letta 给 Agent 提供了「写记忆 / 读记忆 / 搜索记忆」的工具,由它决定何时迁移(比如把一段对话要点从 Recall 提炼进 Core)。这套机制才是它「不健忘」的真正原因。
Step 1:安装并启动 Letta Server
pip install letta # 装 CLI 与本地 server
pip install letta-client # 装 Python REST SDK(写代码调用时用)
letta server # 默认监听 http://localhost:8283
~/.letta 初始化本地存储。Step 2:创建你的第一个长期记忆 Agent
from letta_client import Letta
client = Letta(base_url="http://localhost:8283") # 本地;云端用 token="..."
agent = client.create_agent(
name="memory-bot",
memory_blocks=[
{"label": "human", "value": "用户叫小明,喜欢爬山、住杭州"},
{"label": "persona", "value": "你是一个贴心的长期记忆助手"},
],
)
print("Agent id:", agent.id)
SDK 版本敏感点。Letta 的 Python 客户端 API 迭代较快:早期是 from letta import create_client,新版多拆成 letta-client 包。若 import 失败,先 pip show letta-client 看装没装,并核对官方对应版本文档的入口写法——核心概念(agent / memory block / message)不变。
Step 3:用 SDK 和 Agent 对话
resp = client.send_message(
agent_id=agent.id,
messages=[{"role": "user", "content": "你还记得我叫什么、喜欢什么吗?"}],
)
for m in resp.messages:
if getattr(m, "content", None):
print(m.role, ":", m.content)
它应该能回答「你叫小明,喜欢爬山」。注意:这不是因为它「这次」又听了你自我介绍,而是因为 Step 2 的 human 记忆块已经写进了 Core,每次都会带在上下文里。
Step 4:跨会话验证「它真的记住了」
长期记忆的试金石:断开、重新连上同一个 agent_id,问它「我叫什么」。如果还能答出「小明」,说明记忆在服务端持久化了,而不是藏在当前进程里。
# 重新起一个客户端(模拟新会话/新进程)
client2 = Letta(base_url="http://localhost:8283")
resp = client2.send_message(
agent_id=agent.id, # 同一个 id,记忆还在
messages=[{"role": "user", "content": "我叫什么?住哪?"}],
)
# 依然能答出:小明 / 杭州
Step 5:让 Agent 自己写记忆(Recall → Archival/Core 迁移)
告诉它一条新事实,然后看它是否把这条写进了记忆块:
client.send_message(
agent_id=agent.id,
messages=[{"role": "user", "content": "记一下:我最近开始学滑雪了"}],
)
# 读取当前记忆块,确认 human 块被更新
blocks = client.agents.memory.list_blocks(agent_id=agent.id)
for b in blocks:
print(b.label, "->", b.value)
不是所有版本都自动写回 Core。记忆的「自我更新」依赖该 Agent 配置的 memory 工具与模型能力。若发现它没自动更新,可显式用 memory 编辑接口,或在 system prompt 里要求「每当学到用户新事实就写入 human 块」。
Step 7:避坑与进阶
- 模型 Key:Letta server 需要配置一个 LLM(默认 OpenAI,也可用自托管/兼容端点),在 server 配置或环境变量里给。
- 存储位置:本地在
~/.letta;生产可接 Postgres,避免重启丢数据。 - 成本控制:Archival 用检索、不进窗口,是省钱关键;Core 别塞太多,否则每次都占 token。
- 边界:记忆会被模型「理解偏差」污染,重要事实建议人工校验或用结构化字段。
常见问题速查
| 现象 | 原因 & 解决 |
|---|---|
| send_message 报错/没这方法 | 客户端版本差异;改为 client.agents.send_message(...) 或查对应版本文档 |
| 重启 server 后记忆没了 | 用了默认本地存储且被清;改接 Postgres 持久化 |
| Agent 不主动记新事实 | 记忆工具未开启或 prompt 没要求;显式编辑 memory block |
| 回答变慢/变贵 | Core 块太大或 Recall 全量回灌;精简 Core、改检索式 Recall |