全部博客

Agent 架构 · 文章 04

Memory 应该是 skill,而不是启动时加载的文件

大多数 agent memory 的行为像旅程前打包好的行李:harness 加载一个 Markdown 文件,贯穿每一 turn 携带,很少再打开。Memory 应该更像 recall:选择性、上下文化,并在重要时刻可用。

核心结论

把 memory 当作可发现的 skill:保留小 registry 用于 routing,把明确 recall triggers 附到 granular memories 上,并在使用时读取最新相关 memory。

静态 memory 是 snapshot,不是 memory system

常见 agent setup 会把偏好、项目事实和过去决策存进 Markdown 文件。agent harness 把这个文件注入 system prompt 或初始 context。这很方便,因为几乎不需要基础设施,但它让 memory 像 configuration 一样运作:一次选择,急切加载,并在 thread 生命周期内固定不变。

随之产生两个问题。第一,每个 thread 都为每个已加载事实支付 token 成本,包括与当前任务无关的事实。第二,每个 thread 都从自己的 snapshot 开始。如果一个 thread 写入重要更新,其他运行中的 threads 仍然从启动时收到的版本继续。agent 也许会把 memory 写回去,但它很少有理由在下一个任务需要前再次读取文件。

  • Eager loading。

    Memory 在相关性已知前就消耗 context,与用户请求和工作材料竞争。

  • Snapshot isolation。

    并行 threads 保留 stale copies,即使另一个 thread 已记录更新决策。

  • Weak recall。

    系统定义了 write path,却很少定义触发 memory 再次读取的事件。

让每段 memory 具备 skill 的形状

skill 已经具备 memory 需要的行为。它有名称、有边界、可发现,并且只在定义好的条件下加载。agent 可以不再使用一个大型 memory 文件,而是拥有 granular memory skills,比如“Project A memory”、“writing preferences”或“deployment conventions”。每个 skill 说明它包含什么、当前来源在哪里,以及哪些事件应该触发 recall。

对 Project A 来说,triggers 可能包括进入它的 repository、在请求中看到它的名字、做 architecture decision、准备 release,或解决一个过去工作可能已经处理过的 ambiguity。当 trigger 匹配时,agent 在那一刻读取 memory,而不只是使用 thread 启动时可用的 copy。被 recall 的材料成为 task context,无关 memory 留在 prompt 之外。

当 retrieval 成为行为的一部分时,memory 才有用。没有 recall policy 的 storage 只是 archive。

从小型 memory registry 开始

选择性 recall 会创造发现问题:agent 无法加载它不知道存在的 memory。答案是一个紧凑 registry,作为关于 memories 的 memory。它包含名称、scope、简短描述、trigger hints、locations 和 freshness metadata,而不是完整 remembered content。

registry 是唯一适合常规加载的层。它让 agent 能以低 token 成本把任务 route 到相关 memory skills。它也能支持主动 recall:当 agent 怀疑存在 prior context,但没有明显 trigger 触发时,它搜索 registry,选择 candidate,并在决策前 retrieve 那段 memory。registry 应该小到足以扫描,结构化到足以查询。

  • Identity。

    稳定 name 和 scope 区分 project、user、organisation 和 general memories。

  • Triggers。

    明确 events 描述何时期待 automatic recall,以及何时 active lookup 可能有帮助。

  • Freshness。

    version 或 updated timestamp 让 agent 检测先前读取的 memory 可能已 stale。

跨 threads recall 最新状态

在使用时加载 memory 会改变 concurrency model。threads 不再只依赖 startup snapshot;每个 thread 都可以在相关事件发生时 retrieve 最新共享 Project A memory。因此,一个 thread 记录的决策,可以影响到达下一个 recall point 的另一个 thread。

动态 retrieval 不会消除 coordination problems。并发 writers 仍然需要 version checks、append-only decision records 或 merge policy,避免一个 update 静默覆盖另一个。memory skill 应该暴露 provenance 和 freshness,把 observed facts 与 inferred guidance 分开,并让冲突 entries 可见。共享 memory 应该变得更及时,但不假装完美一致。

On-demand reading 改善 freshness。Versioned writing 保护 truth。有用的 memory system 两者都需要。

为 recall 设计,不是为 total prefetch 设计

人类工作提供了比 prompt preloading 更好的隐喻。我们不会在开始任务前有意识地取回每段相关经历。情境提供 cues。熟悉的名称、地点、目标和问题会激活相关 memories。当 recall 不完整时,我们停下来搜索:检查 notes,重看 decision,或询问上次发生了什么。

Agent memory 可以遵循同样节奏,而不声称复制人脑。triggers 提供 associative cues。registry 支持 deliberate search。granular memory skills 限定 recall 内容。working context 保存当前重要内容。这创造了一个分层系统,其中 retrieval effort 随任务增长,而不是让每个请求都为整个过去付费。

  • Cue。

    Task context 激活一个或多个 memory triggers。

  • Recall。

    agent 从当前 source 读取最小相关 memory。

  • Reflect。

    完成有意义工作后,agent 用 provenance 更新 memory 和 registry metadata。

定义 memory skills 的最小 contract

memory skill 应该声明 scope、trigger events、retrieval location、read policy、update policy 和 conflict behaviour。它的内容应该偏向持久决策、约束、偏好和未解决问题,而不是记录所有发生过的 transcript。summaries 可能有用,但当后续 agent 需要验证 memory 为什么存在时,provenance 必须保持可用。

第一个实现可以继续基于文件。架构变化不是数据库,而是把 memory 从无条件 prompt content 移到明确 discovery 和 retrieval protocol 中。registry 加 granular、可触发的 Markdown skills,已经可以创造 selective recall。更高级的 stores 可以在 search、permissions、scale 或 cross-device synchronisation 需要时再跟进。

重要转变是从“每个 thread 启动时应该记住什么?”转向“这个 agent 现在应该 recall 什么,为什么被触发,它是否仍然 current?”Memory as a skill 把存储的 context 变成主动能力。