文章

给 Agent 设计记忆:短期上下文、长期事实与可删除性

Agent 记忆最难的部分不在存储。先决定哪些话值得留下,以及以后凭什么把它取出来。

Agent 忘了用户刚说过的话,很容易让人想到向量数据库:把聊天记录全部存进去,以后相似度检索。这个方案上线很快,过一阵子就会发现新问题。一句临时决定被反复召回,一次猜测变成了用户偏好,真正重要的事实反而淹在聊天里。

所以我会把“记住”拆成两件事:这条信息要不要写入,以后什么任务可以读取它。存储技术排在后面。

三种东西不要混着存

工作记忆只服务当前任务,包括目标、已经确认的条件、工具结果和待办步骤。任务结束后,多数内容都可以丢掉。

语义记忆是相对稳定的事实,例如称呼、时区、常用语言、明确说过的输出偏好。它会跨会话出现,写错一次的影响也更久。

情节记忆记录过去发生过的事,比如“上次旅行临时取消了夜间行程”。它可能对下一次旅行有帮助,却不能直接推导出“用户永远不喜欢夜间行程”。事件和偏好是两回事。

如果这三类内容共用一张表、同一套召回规则,模型迟早会把临时安排当成长期习惯。

自动写入要保守一点

我会先问:这是用户明确说的吗?过一段时间还有用吗?记错了会不会带来实际麻烦?前两项答得不够确定,就留在当前任务里。

“这次会议改到周五”没必要长期保存。“以后不要把会议安排在周五”可以保存,但最好让用户确认。健康、财务和身份信息更敏感,默认不自动写入会省掉很多后患。

一条记忆至少带来源和时间:

{
  "key": "preferred_language",
  "value": "中文",
  "source": "conversation:2026-08-03:message-18",
  "confidence": 0.98,
  "updated_at": "2026-08-03T10:30:00+08:00",
  "expires_at": null
}

来源用于回看原话,过期时间负责清理临时信息。confidence 可以帮助程序决定是否再问一次,但它不是事实证明。模型给出的 0.98 仍然可能错。

每次只取当前任务用得上的

把全部长期记忆塞进每次请求,会得到一种很吵的“个性化”。处理旅行计划时,语言和时区可能有用;三年前喜欢的咖啡品牌大概没用。

读取前先根据任务生成查询,只取少量相关事实。取回的记忆应该标成背景信息,当前对话里的明确说法优先。如果用户今天要订不同规格,就别拿“以前常买”去覆盖今天的选择。

涉及下单、付款或发送时,记忆只负责减少输入。动作执行前仍然展示关键字段,让用户确认。

长对话需要压缩,但别只截掉开头

上下文快满时,直接删除最早消息可能连任务目标一起删掉。可以生成一份结构化摘要,只留已确认事实、未解决问题、关键工具结果和用户明确偏好。

摘要也会出错。保留它指向原始消息的引用,写上版本和更新时间,出问题时还能回头查。自由发挥的一段“对话总结”看起来顺滑,漏掉一个限制条件却很难发现。

删除要真的删干净

只要有跨会话记忆,用户就该能查看、修改和删除。删除动作要覆盖主表、向量索引、缓存和等待处理的异步任务。多租户系统每次读取都用用户 ID 和租户 ID 做硬过滤,不能指望向量相似度顺便完成权限隔离。

验收删除功能的方法很直接:用户能看到系统记了什么,能追到原话,删掉某一条后,新会话再也搜不到它。

第一版其实只存语言、时区和输出格式就够了,而且可以要求显式确认。等团队知道哪些记忆真的被用到、哪些经常误召回,再扩大范围。什么都记下来很容易,之后让系统忘干净才费事。