在云计算时期做 memory service 的时候,我们接触了几个典型场景——媒资推荐、家用智能、车机交互。做着做着发现一件事:记忆不是一种,是多种,而且这多种在存储,生成阶段有很大差异。
第一种是日志形式的记忆。
2025-3-2 12:00,我和张伟今天吃了 肯德基外卖,还是很爽的
时间、地点、事件,流水账。查询这类记忆靠的是语义相似——"他最近吃了什么",就去找描述相似的记录。向量数据库天然适合这个。
第二种是关系形式的记忆。
2023年从上一家公司离职,个人状态:自由职业者
2025年和女友张玉结婚,婚姻状态:已婚,妻子:张玉,女朋友:无
这不是流水账,是实体和状态的变更。查询这类记忆靠的是逻辑关联——"我有什么状态,可以查询到当前的工作状态和婚姻关系等",不是通过相似文本去找,就好像你不会因为想一个人的名字,就去回忆你第一次见到他他介绍自己的场景,这个信息是挂载到这个人的属性上的,在图数据库里是一个property。图数据库适合这个。
两种记忆、两种存储、两种查询方式,混在一起用会出问题。早期我们踩过坑,把关系型记忆也塞进向量库,结果"他老婆是谁"这种问题检索召回率受到影响——因为语义搜索里的需要把结婚的事件召回,同时会把其他无关噪声也召回了(因为结婚事件可能发生了很久,随时间记忆有衰减)
还有第三种:技能和经验
日志和关系之外,还有一类记忆我们讨论了很久——skill,技能和工具的使用经验。
这类记忆的特点是可抽象、可迁移。
举个例子:我用过 Git,积累了一套使用经验。现在让我用 SVN,我虽然不知道具体命令,但我知道它一定有拉取、推送、合并、分支这些概念。这个"知道它一定有"的部分,就是可以迁移的抽象经验。
这种经验不是日志(没有时间戳),也不是关系图里的实体状态,它是结构化的方法论——某类工具或任务的通用模式。
存向量库可以,但怎么组织还没有定论。粗暴的做法是直接把经验文本向量化,但检索出来之后 Agent 怎么用,还需要有一套触发和迁移的机制:
- 触发:当前任务和哪个已有经验最相关
- 迁移:把抽象经验映射到当前具体工具或场景
这两步如果没有显式设计,经验就只是存着,用不上。
目前思路是把技能和经验分层,技能分成抽象和具体,经验依附到工具和场景上,这样抽象的部分和工具的经验可以迁移,具体的部分可以在迁移过程中抛弃。
三种存储,三条写入流水线
说清楚了三类记忆,存储结构就自然出来了。
三种存储形态:
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ 向量索引 │ │ 结构化存储 │ │ 图 / 关系 │
│ (Vector DB) │ │ (SQLite) │ │ (Graph DB) │
├─────────────────────┤ ├─────────────────────┤ ├─────────────────────┤
│ memories 文本向量化 │ │ events 表(原始日志) │ │ 实体 ← 属性挂载 │
│ embedding + metadata│ │ memories 表(派生记忆)│ │ 意图依赖关系 │
│ │ │ policies 表(策略) │ │ 状态变更历史 │
├─────────────────────┤ ├─────────────────────┤ ├─────────────────────┤
│ 语义相似检索 │ │ 精确过滤 / 时效管理 │ │ 逻辑关联查询 │
│ "他最近吃了什么" │ │ status / valid_to │ │ "他老婆是谁" │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
日志记忆 事件与策略 关系记忆
三个写入阶段:
原始输入(对话 / 工具调用 / 传感器)
│
▼
┌─────────────────────────────────────┐
│ Stage A 原始层(不可变证据) │
│ events 表 │
│ raw_text · signals · 时间 · 地点 │
└──────────────────┬──────────────────┘
│ LLM 异步抽取
▼
┌─────────────────────────────────────┐
│ Stage B 补充层(派生候选) │
│ memories 表 │
│ 摘要 · 实体 · candidate_fact · 置信度│
└──────────────────┬──────────────────┘
│ 情境化意图识别
▼
┌─────────────────────────────────────┐
│ Stage C 关联层(条件化策略) │
│ policies 表 │
│ intent · condition_json · action │
│ (不写死单值,避免"冬天也记成16度") │
└─────────────────────────────────────┘
写入是单向流水线,召回是反向检索:向量库做语义召回,结构化表做精确过滤,图库做关系推理,三路合并后压缩成几百 token 的 Memory Pack 注入 prompt。
存储类型+存储过程决定记忆的召回精度
不同类型的记忆,写入方式不同,存储结构不同,遗忘策略也应该不同。
- 日志记忆可以按时间衰减,太老的降权。关系记忆不能随便衰减
- 状态变更要保留最新状态,查询时根据关联关系访问。
- 技能记忆理论上越用越强,不该衰减,但要有升级概念——用了更好的工具之后,旧经验要能被覆盖或修正。
现在大部分 Agent 的记忆系统只有一层,要么全放向量库,要么就是简单的对话摘要。这对短对话够用,对真正的长期个人助理来说是不够的。
下一步值得认真做的事:把这三类记忆的边界定清楚,设计各自的写入、查询和遗忘策略,然后在上层给 Agent 一个统一的记忆调用接口,让它不用关心底层是向量库还是图库。
记忆系统的成熟度,会是下一轮 Agent 产品竞争的隐形门槛。