4.3. Memory Blocks 是实现可解释记忆模块的终极方法

Memory Blocks 是实现可解释记忆模块的终极方法

结论先行:在 Letta 架构中,Memory Blocks 不是一种“更好的存储格式”,而是将 Agent 的记忆从 LLM 内部隐式表征中剥离出来,使其成为开发者可直接读取、编辑和治理的显式结构化文本。当其他框架还在用向量相似度“猜测”Agent 记得什么时,Letta 的 Agent 已经通过函数调用精确地告诉了你——它正在记住什么、为什么记住、以及准备忘记什么。这就是可解释记忆模块的终极形态。

如果你还记得上一章结尾留下的任务——测试记忆块机制在低算力环境下的表现——那么本章就是理解这一切何以成立的钥匙。我们需要回到 MemGPT 那篇论文想要解决的核心矛盾:上下文窗口是被动的一块“黑板”,还是应由 Agent 主动管理的“工作内存”?Letta 的 Memory Blocks 给出的答案是后者,且这个答案远比简单的“分页”更激进。

时间线锚点:从系统指令到可审计的记忆段

在 2023 年大部分 Agent 实践中,“长期记忆”几乎等同于以下三件事之一:把对话摘要塞进下一轮的系统提示词(Summary Memory);把历史对话向量化后检索相似片段(Vector Memory);或者把所有东西都堆进越来越长的上下文里(Brute Context)。这三种方案都有一个共同的致命缺陷——可解释性为零。当你问“这个 Agent 为什么做出了这个决定?”时,你只能得到模糊归因:“可能因为系统提示里有一段相似的对话”,而无法明确指出是哪一条记忆、在何时写入、被何种逻辑触发。

Memory Blocks 在 2024 年底随着 Letta 框架的工程化落地而正式确立(截至当前调研资料,Letta 已将其作为核心抽象写入文档)。它的关键转变在于:不再把记忆看作一个检索池,而是看作一组被 Agent 主动读写的、具有明确标签和语义边界的文本段。这些 Block 会始终被“钉”在上下文窗口中(pinned to the context window),以类 XML 的结构持久存在,每次 LLM 调用时都能完整地看到它们。

换一种更直白的说法:普通 Agent 的记忆像一个你只能通过搜索关键词去翻找的地下室仓库;而 Memory Blocks 下的记忆,像你办公桌上分门别类、贴上标签、随时可拿起修改的文件夹。

一、三种标准块的职责与边界:关注点分离

Letta 的设计从最基础的三个内置 Memory Block 开始,直接回答了“Agent 凭什么认识用户、认识自己、知道此刻在干什么”这三个问题:

Memory Block 名称 存储内容 关键职责 为何必须分离
human 用户姓名、职责、偏好、背景等事实性信息 跨会话保持对用户的认知 将“用户画像”从 Agent 的自我意识中剥离,避免 Agent 将用户特质误认为自身能力
persona Agent 的身份、专业领域、语气、行为边界限制 定义 Agent 的“自我概念” 让开发者能精确定制 Agent 的人格,而不是靠提示词工程去“暗示”Agent 该成为谁
scratchpad 当前任务的中间状态、待办项、临时推理链 提供工作记忆(working memory) 将思考过程中的杂乱草稿隔离起来,防止它污染长期记忆或人格设定

作者的结论:这三个 Block 并非功能累加,而是对“Agent 心智”的一次结构化解耦——分别对应“对世界的认知”、“对自我的认知”和“对当前任务的认知”。这种解耦是实现可解释治理的前提:你可以单独审计 Persona 块来检查 Agent 是否越界;可以单独编辑 Human 块来纠正对用户的理解偏差;也可以随时清空 Scratchpad 来重置工作流,而不会伤及其他记忆。

在调研素材中,Letta 的 ADE(Agent Development Environment)提供了一个可视化的 Memory Block 编辑界面,开发者可以直接点击任意 Block 并修改其值——这意味着非技术人员也能直接介入记忆治理,而不需要去翻查向量数据库或调整嵌入参数。

二、自定义 Memory Block 以扩展领域知识

标准块提供了心智骨架,而真正让 Memory Blocks 成为终极方案的能力,在于自定义块的自由扩展。我们来看一个实际例子:项目上下文块

假设你正在构建一个处理 GitHub 仓库协作的 Agent。它可以审查 PR、回复 Issue 评论,并维护项目知识。在传统向量记忆中,你需要把每个 Issue 和 PR 摘要向量化,然后在每次对话时检索——但检索永远有遗漏,且无法保证 Agent 能看到“项目当前最关键的三件事”。

而使用 Memory Block,你可以创建一个名为 project_context 的块:

<memory_block>
  <label>project_context</label>
  <description>
    存储项目当前迭代的关键信息。包括:活跃 PR 的标题与状态、最近三个 Issue 的优先级排序、
    团队达成的架构决策记录。该块在每次收到新 PR 或 Issue 时自动更新,Agent 据此生成回复。
  </description>
  <value>
    [2026-06-08] P0 Issue: 登录模块 OAuth 回调失败 #452
    [2026-06-08] PR 审查中: 重构支付接口异常处理 #453 (待合并)
    [2026-06-07] 架构决策: 缓存层统一迁移至 Redis Cluster (已确认)
  </value>
</memory_block>

这个 Block 的精妙之处,在于它的 description 字段不只是面向开发者的注释——它是发给 Agent 的元指令。当 Agent 通过 memory_block_edit 函数更新此块时,LLM 会阅读这个 description,理解“我需要在这个块里维护什么类型的信息、按什么格式、触发条件是什么”。这本质上是一种可编程的记忆治理协议。

结合调研中提到的案例,一些社区实践已经探索了更激进的用法:创建 tool_usage_guidelines 块来存储“避免重复犯同一个工具调用错误”的经验;创建 user_current_document 块来镜像用户正在编辑的文件状态,让 Agent 拥有实时情境感知;甚至创建 performance_tracking 块来诱发 emergent behavior——Agent 发现自己性能低下后,会自发地改写自己的问题解决策略并写回该块,形成闭环的自我优化。

三、块的冲突解决与优先级

当记忆可以被多个 Agent 共享、被异步更新时,冲突就不可避免。假设我们有两个 Agent,一个负责收集用户反馈(写入 user_preferences 块),另一个负责根据偏好生成回复(读取同一个块)。如果收集 Agent 在生成 Agent 读取之后的瞬间更新了块,那么下一个生成回复就会基于旧数据——这是典型的脏读。

Letta 当前的处理方式并非分布式事务锁(这对 LLM Agent 而言过于沉重),而是依赖两种更务实的策略:

冲突场景 合并策略 适用条件 需要避免的陷阱
两个 Agent 几乎同时调用 memory_block_edit 更新同一个 block 最后写入胜出(Last-Write-Wins) 更新频率低、冲突概率小的场景 在高速并发场景下可能丢失关键更新,需评估业务容忍度
Agent A 写入的 user_preferences 与 Agent B 已有的认知矛盾 信源权重标记:在 block value 中显式标注信源可信度,由后续 Agent 自行判断 多信源、存在权威度差异的环境 需要开发者预先设计信源权重体系,否则 Agent 可能无法正确判定

调研资料中特别提到的一个坑点是:共享 Block 的读写权限需要极度谨慎地规划。如果让一个低权限 Agent 意外修改了全局策略块(比如 tool_usage_guidelines),它可能给所有 Agent 植入错误行为模式,造成连锁污染。建议的做法是,在设计阶段就明确将 Block 分为三类权限梯度:

  • 只读共享块(如公司政策、模型能力边界限制):所有 Agent 可读,仅治理者可写。
  • 读写共享块(如项目上下文):少数协调 Agent 可写,执行 Agent 只读。
  • 私有块(如 Agent 的 scratchpad):严格单 Agent 读写。

这种权限模型不需要复杂的 ACL 系统——它通过 Letta 的工具绑定机制直接实现:只需在创建 Agent 时不向其暴露 memory_block_edit 对于特定 block 标签的调用能力即可。

核心限制与设计原则

在给出最佳实践之前,我们必须正视 Memory Blocks 的固有约束:

1. 恒定上下文窗口成本
每个 Block 始终占据 token 空间,无论它在本轮对话中是否被需要。如果你塞入 10 个满字符限制的 Block,可能连第一轮对话都还没开始,上下文窗口就已经被吃掉几千 token。因此,chars_limit 参数不是可选项,而是每个 Block 设计时必须精确计算的硬约束。

2. Label 和 Description 的语义负载
这两者会直接影响 LLM 组织和管理记忆的方式。一个糟糕的 description 会导致 Agent 将错误类型的信息写入 Block,或误读 Block 的用途。例如,如果你将 project_context 的 description 写为“存储项目信息”而不是“仅存储当前迭代的活跃事项,按时间倒序排列”,Agent 可能将所有历史文档一股脑塞进去。

3. 隐式约定 vs 显式结构
Block 的 value 是自由格式文本,这提供了灵活性,但也带来了结构一致性风险。A Agent 可能用 - [ ] 任务 格式写 scratchpad,而 B Agent 可能用 1. 任务——当这些 Block 被共享时,解析就容易出错。社区最佳实践建议,在 description 中规定 value 的结构范例,让 Agent 遵循模板。

评测场景下的可操作性结论

基于当前调研资料,如果我们从三个维度——可解释性、可编辑性、可共享性——对 Memory Blocks 与其他主流记忆方案进行对比:

记忆方案 可解释性(你能知道 Agent 记得什么吗) 可编辑性(你能直接修改记忆吗) 可共享性(多个 Agent 能否共用记忆) 作者的结论
向量检索记忆 低 — 只能看到检索出的片段,不透明 低 — 需要操作向量库,间接且易出错 中 — 可以共享同一向量库但无权限控制 适合模糊召回,不适合需要审计的场景
摘要记忆 中 — 可以看到摘要内容,但无法追溯来源 中 — 可以重写摘要,但陈旧更替逻辑不可控 低 — 通常绑定在单个 agent 的提示词中 适合简单的上下文延续,不适合复杂治理
Letta Memory Blocks 高 — 每个 Block 显式可读、可审计来源 高 — API 或 ADE 界面直接编辑任意 Block 高 — 原生支持跨 Agent 共享与权限控制 当前唯一能在生产环境中同时满足三者的方案

按场景推荐

  • 如果你的 Agent 需要处理合规审计(如金融顾问、医疗问答),Memory Blocks 的“全透明记忆”特性是刚需,无替代方案。
  • 如果你需要运行长时间任务(数天甚至数周),其中 Agent 需要持续学习并更新自身知识,scratchpad + 自定义块的组合可以让你随时检查 Agent 是否“学歪了”。
  • 如果你正在构建多 Agent 协作系统,利用共享 Block 进行状态同步,远比让每个 Agent 维护独立记忆然后靠消息传递协调要高效——因为 Block 更新是即时的、始终可见的。

向前看:从可解释走向可信赖

Memory Blocks 为 Agent 记忆带来可解释性,但可解释性只是手段,目标是可信赖。当一个 Agent 的 Persona 块被审计、Human 块的来源可追溯、所有共享块的修改记录都被显式存储在对话历史中时,我们就不再需要信任厂商“我们的 Agent 很安全”的承诺——我们可以自己验证。

下一章,我们会将这个论证放入更大的技术版图中去审视:《Mem0 与 Letta 的技术路线之争代表了两种未来》。向量驱动的记忆检索与分页内存模型,背后是对“Agent 应该像人一样模糊记忆,还是像程序一样精确记忆”这一根本问题的两种回答。而 Memory Blocks,恰恰是这场争论中最锋利的那把手术刀。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~