Mickey's Blog · · Agent Memory 向量数据库 图数据库 记忆系统

记忆的分层:向量、关系与技能

在云计算时期做 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。


存储类型+存储过程决定记忆的召回精度

不同类型的记忆,写入方式不同,存储结构不同,遗忘策略也应该不同。

  1. 日志记忆可以按时间衰减,太老的降权。关系记忆不能随便衰减
  2. 状态变更要保留最新状态,查询时根据关联关系访问。
  3. 技能记忆理论上越用越强,不该衰减,但要有升级概念——用了更好的工具之后,旧经验要能被覆盖或修正。

现在大部分 Agent 的记忆系统只有一层,要么全放向量库,要么就是简单的对话摘要。这对短对话够用,对真正的长期个人助理来说是不够的。

下一步值得认真做的事:把这三类记忆的边界定清楚,设计各自的写入、查询和遗忘策略,然后在上层给 Agent 一个统一的记忆调用接口,让它不用关心底层是向量库还是图库。

记忆系统的成熟度,会是下一轮 Agent 产品竞争的隐形门槛。