按类型构建内存可减少约 40% 的检索 Token。

为什么扁平化的内存存储会失效

大多数入门教程教导 LLM agent 通过将每一条新信息追加到一个单一列表中,并在每一轮对话中将该列表反馈给模型来实现“记忆”。代码可能只有短短三行,且能跑通演示。但在实践中,这个列表会无限制地增长。这会导致两个症状:

  • Agent 会将过时的数据视为真实信息,例如提供一个几小时前就已失效的预计到达时间 (ETA)。
  • 上下文窗口被无关紧要的琐事填满,这些信息对回答毫无影响,却增加了 API 成本并降低了响应速度。

普通的向量数据库或简单的键值缓存无法区分用户的职位头衔与临时的项目状态。当 agent 进行语义搜索时,相似度算法可能会因为查询中包含相同的词汇而提取出旧的 ETA,即便该数据已不再相关。

结构化内存:四个类别,一个目标

解决方法是停止将内存视为一个整体,而是开始将每个条目归类为以下四个类别之一:

  • 用户事实 (User facts) —— 稳定的属性,例如用户的角色、首选语言或安全权限。这些信息很少变动,可以在整个会话期间进行缓存。
  • 反馈 (Feedback) —— agent 必须遵守的明确规则,例如“绝不泄露数据库密码”或“在合规查询中避免使用幽默”。由于这些规则决定了行为模式,它们应该属于 system prompt,而不是可搜索的池。
  • 项目状态 (Project state) —— 快速变化的数据,如当前的 ETA、任务进度或临时 token。这类数据需要进行过期检查;一旦时间戳超出了定义的窗口,该条目就应被清除。
  • 引用 (References) —— 指向外部服务、文档 ID 或 API 端点的指针。它们不是用于展示的内容,而是用于在需要时获取最新数据的路径。

Mem0 允许开发者为每个内存记录附加任意元数据 (metadata)。通过对 “kind” 字段进行索引,查询可以在 LLM 决定如何使用结果之前,先过滤出相关的类别。

使用 Mem0 进行两步检索

  1. 按类别提取内存 —— 一个简短的过滤查询可以向 Mem0 请求“所有反馈”或“时间间隔内更新的项目状态条目”。结果集已经预先筛选到了合适的类别。
  2. 让 LLM 做出决策 —— 过滤后的片段会连同用户当前的问题一起插入到 prompt 中。模型现在可以对其进行推理,而无需在无关事实中进行筛选。

一个具体的例子:开发者不再等待语义匹配来提取“不要模拟数据库”这条规则,而是在会话开始时直接将该规则注入 system prompt,并在整个交互过程中进行缓存。即使用户的查询中没有明确提到数据库,模型也已经知道了这一约束。

降低成本的实用技巧

  • 缓存反馈规则 —— 在每个会话中仅存储一次规则集并重复使用,而不是在每一轮都重新搜索。这减少了每一轮的 token 使用量。
  • 在无关时跳过项目状态搜索 —— 如果用户问的是纯概念性问题(例如“监督学习和强化学习之间有什么区别?”),则无需提取任何 ETA 或任务进度数据。

通过应用这两个习惯,与原始的扁平化内存方法相比,token 使用量可以减少约 40%。这种节省可以直接转化为更低的 API 账单和更快的响应速度,特别是对于需要进行多次对话的 agent 而言。

谁获益,谁担忧

获益者 —— 构建客户支持机器人、内部工作流助手或任何多轮 LLM 交互界面的团队。他们能获得更可靠的回答,避免因数据过时而导致的尴尬错误,并能更有效地利用预算。

核心总结

如果你希望 LLM agent 在长会话中保持高效,请停止将每个事实都塞进单一的上下文窗口。将每条内存标记为用户事实、反馈、项目状态或引用,在需要时执行过期机制,并让 Mem0 之类的工具来承担繁重的工作。其结果是更及时的回答、更少的冗余 token 以及运营成本的显著降低。