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 变成主动能力。