Agent 记忆不是数据库:四层结构和一个必须的遗忘机制
把整段对话塞进向量库不等于有记忆。真正可用的 Agent 记忆需要分层,并且必须会忘——本文给出四层设计、写入时机和冲突处理办法。
「给 Agent 加个记忆」听起来像加一个向量数据库。做完会发现:检索回来的东西又旧又碎,还经常和当前状态冲突。问题不在检索,在没有区分记忆的种类。
一、四层结构
工作记忆:当前任务上下文,就是上下文窗口本身,任务结束即丢弃。
情景记忆:「上次发生什么了」。带时间戳的事件流:用户周三说预算 5 万,周四改成 8 万。
语义记忆:「稳定的事实」。从情景记忆提炼出来的结论:该客户属于制造业、偏好简洁回复。
程序记忆:「怎么做事」。操作步骤、工具偏好、失败过的路径。最容易被忽略,但它决定 Agent 第二次做同类任务时是否更快。
四层用途完全不同:查偏好进语义层,查「上次怎么处理的」进情景层。混在一起就是多数实现效果差的原因——向量检索对时间顺序和事实时效几乎无感。
二、写入时机:别每轮都写
最常见的错误是把每轮对话都向量化入库,结果库里 90% 是「好的」「谢谢」。
推荐三个触发点:任务结束(写情景 + 提炼语义候选)、事实变更(检测到冲突时标记旧事实失效而非删除)、显式指令(用户说「记住」)。再定期离线跑合并任务,把多条情景归纳成一条语义事实。
三、冲突处理比检索更重要
真正的质量指标不是召回率,是冲突正确率。
当「预算 5 万」和「预算 8 万」同时被召回,模型会随机挑一个。正确做法是把时间和置信度一起返回:
{"fact": "预算 8 万", "valid_from": "2026-04-20",
"supersedes": "预算 5 万", "confidence": 0.9}
并在提示词里明确:同一字段冲突时取 valid_from 最新的一条。这比换更强的 embedding 模型有效得多。
四、遗忘机制
长期记忆必须有衰减和清理,否则三个月后检索质量会断崖下跌。三种机制配合:
- 时间衰减:检索评分乘递减权重。注意语义事实衰减要慢得多(用户行业十年不变);
- 访问频率:被反复命中并确认有用的提权;
- 容量上限:按类型设条数上限,超出时按「引用次数 × 置信度 × 衰减权重」淘汰。
特别提醒:不要用「删除过期」来简化实现。删掉的事实下次被提及时会重新写入,形成抖动。用失效标记,保留历史。
五、最小可行方案
不想一开始就做四层,先做两件事,收益已占 80%:
- 事件流和事实表分开存,事实表带
valid_from/invalid_at; - 检索时把当前事实和最近 5 条相关事件一起给模型,让它自己判断时效。
记忆的价值不在于记得多,在于记得对、忘得准。