Memory 记忆设计讨论:Agent Memory 的安全边界:权限、删除、版本与回执

两篇分别讨论了 Memory 的整体定义、向量检索的边界以及核心数据对象。这篇讨论一个更容易被低估的问题:

一个 Agent 记得越多,是不是就越有用?

不一定。

如果没有权限、范围、删除、版本和结果确认,Memory 记得越多,错误上下文被使用的范围也可能越大。

一、历史授权不等于当前授权

用户过去允许 Agent 做过一件事,不代表今天可以自动重复做。

比如用户上个月确认过一次酒店预订,不能因此推断:以后所有旅行都可以自动付款。授权通常和具体动作、具体任务、具体时间以及具体金额有关。

因此,Memory 可以记录“过去发生过什么”,但不能把历史行为直接当成当前授权。

读取记忆时,系统至少应该重新确认:

  • 当前用户是谁
  • 当前 Agent 是谁
  • 当前任务是什么
  • 当前数据属于哪个范围
  • 当前动作是否需要再次确认

二、权限必须发生在召回之前

这是一个非常重要的工程顺序。

错误的实现方式是:

  1. 从所有历史内容中搜索相似信息
  2. 把结果交给模型
  3. 让模型判断哪些内容可以使用

这种做法的问题是,模型已经看到了本不应该看到的内容。即使最后没有把它输出给用户,数据也已经进入了上下文。

更可靠的方式是:

  1. 确认用户、任务和访问范围
  2. 在数据层做硬过滤
  3. 只在允许的范围内检索
  4. 对结果再次检查来源和状态
  5. 最后组装上下文交给 Agent

权限是数据访问控制,不是 Prompt 里的提醒语句。

三、范围比“属于用户”更细

同一个用户也可能有多个相互隔离的范围:

  • 个人旅行计划
  • 家庭共享行程
  • 工作出差任务
  • 临时的朋友聚会

如果只用一个 user_id,系统可能会把不同任务中的信息混在一起。

因此 Memory 通常还需要任务、项目、会话或其他 scope。一个偏好可能适用于用户整体,也可能只适用于某次旅行。

例如:

用户通常喜欢早班机。

和:

这次旅行不要早于上午十点出发。

两条信息都可能是真的,但适用范围不同。当前任务的明确约束通常应该覆盖一般偏好,而且这种覆盖不应悄悄改变长期偏好。

四、删除不是把一行数据删掉

如果用户删除一条记忆,系统需要考虑它的所有派生物:

  • 原始对话或文档中的引用
  • 候选记忆
  • 正式记忆
  • 关键词索引
  • 向量索引
  • 缓存
  • 摘要
  • 图关系或其他查询投影

只删除正式记忆表中的一行,搜索索引里可能仍然能召回旧内容。

因此,删除更像一个需要传播的事件。系统可以通过 deletion ledger 或类似的删除记录,追踪删除请求已经传播到哪些存储和派生数据。

删除也需要明确语义:是删除原始来源,撤销某条记忆,还是限制未来使用?不同语义可能对应不同的处理流程。

五、版本能防止新旧信息互相覆盖

用户先说:“预算不超过 8000 元。”

后来又说:“这次可以到 10000 元。”

如果两个更新同时到达,或者旧客户端晚一点提交,简单的最后写入可能让旧值覆盖新值。

工程上通常需要 revision 或版本号进行并发控制。更新时带上自己读取到的版本:

读取 revision = 3
提交更新时声明 expected_revision = 3
只有当前版本仍然是 3,更新才成功

如果当前版本已经变成 4,系统应该拒绝这次更新并重新读取,而不是静默覆盖。

版本还帮助解释记忆为什么变化、旧版本何时失效,以及用户纠正后是否真的生成了新状态。

六、模型说完成不等于业务完成

这是 Agent 系统里另一个常见错误。

Agent 生成了“酒店已经预订”的文字,不代表预订系统真的创建了订单。模型的回答只是一个输出,不能替代外部系统的结果。

正确的流程应该是:

  1. Agent 生成动作计划
  2. 用户在需要时确认
  3. 系统绑定当前任务版本和动作摘要
  4. 执行外部动作
  5. 查询外部系统返回的真实结果
  6. 根据回执更新 Task State
  7. 只有确认成功,才写入“已完成”的事实

如果请求超时,系统可能不知道动作到底成功还是失败。此时应该进入 outcome_unknown,先查询、对账,再决定是否重试。

直接重试可能造成重复预订、重复付款或重复发送。

七、写入和读取都要受控

一个较完整的写入路径可以是:

事件接收
  -> 保存证据
  -> 提取候选
  -> 检查权限和敏感信息
  -> 处理冲突与有效期
  -> 必要时请求确认
  -> 写入正式记忆

读取路径则可以是:

确认用户和任务
  -> 权限与范围过滤
  -> 读取任务状态和当前事实
  -> 补充关键词、向量和时间召回
  -> 检查来源与新鲜度
  -> 组装上下文

这两条路径共同决定了 Memory 的可信程度。

写入控制不好,错误内容会进入长期记忆;读取控制不好,越权信息会进入当前上下文。

八、应该测试什么

Memory 的测试不能只看 Agent 最后回答得像不像。

至少应该覆盖:

  • 同一事件重复提交是否幂等
  • 不同任务之间是否串数据
  • 没有权限的内容是否在召回前被过滤
  • 新版本能否正确替代旧版本
  • 用户纠正是否立即生效
  • 删除是否传播到索引和缓存
  • 任务状态是否能正确恢复
  • 外部动作超时后是否避免重复执行
  • 来源是否可以被追溯

其中,跨范围泄漏和重复执行通常比“回答不够自然”更严重。

九、一个简单的安全判断框架

每当系统准备记住或使用一条信息时,可以连续问五个问题:

  1. 这条信息来自哪里?
  2. 它适用于谁、什么任务和什么时间?
  3. 它是否已经被更新、撤销或删除?
  4. 当前 Agent 是否有权使用它?
  5. 如果它触发外部动作,结果由谁确认?

这五个问题看起来朴素,却覆盖了来源、范围、生命周期、权限和回执五个核心边界。

结论

可信的 Agent Memory 不是一个“什么都记住”的系统,而是一个知道什么时候应该记住、什么时候不能使用、什么时候必须忘记,以及什么时候需要重新确认的系统。

可以把核心原则总结为:

历史信息可以帮助 Agent 理解当前任务,但不能自动获得当前授权;模型可以提出判断,但不能伪造业务结果;删除、版本和权限必须由系统控制,而不是交给 Prompt 自己约束。

当这些边界建立起来之后,Memory 才可能从一个方便检索的功能,变成一个能够支撑持续任务的基础能力。

posted @ 2026-09-10 21:10  杜文龙  阅读(29)  评论(0)    收藏  举报