这是本文档旧的修订版!
决策树总览
你的Agent需要记忆系统
│
├─ [Step 1] 先分类 → 该扔的/该缓存的/该存的
│ 跳过后果:MEMORY.md 从 200行涨到 800行,关键信息被淹没
│
├─ [Step 2] 选存储 → 上 SQLite FTS5,不上向量库
│ 跳过后果:装了向量库但 90% 查询不需要语义搜索,多花运维成本
│
├─ [Step 3] 加时效 → 每条记忆 created_at + valid_until + superseded_by
│ 跳过后果:3个月前的错误配置参数仍然被检索到,制造回归bug
│
├─ [Step 4] 对齐缓存 → Frozen Snapshot:稳定前置,动态后置
│ 跳过后果:API 成本高出 25-75%,prefix cache 从未命中
│
├─ [Step 5] 加归纳 → 每日 Auto-Dream:去重、冲突检测、时效淘汰
│ 跳过后果:搜索噪音——5条"渲染崩溃"记录来自不同期,Agent 合成错误答案
│
├─ [Step 6] 按需升配 → 模糊查询用向量库、时序管理用知识图谱
│ 跳过后果:不跳过也没损失——但前置条件不完备就上是更精致的垃圾场
│
└─ [Step 7] 验证 → 3个指标 + 5个测试用例
跳过后果:不知道系统在变好还是变坏,盲目迭代
每步详细决策
Step 1:三分类 — 信息归入"该扔/该缓存/该存"
| 决策项 | 规则 |
| 能重新推导的吗? | → 该扔 |
| 短期高价值,session 结束就过期? | → 该缓存 |
| 不可推导,丢了就没了? | → 该存 |
类比:搬家 → 卖旧报纸(扔) + 随身带牙刷(缓存) + 锁好房产证(存)
何时重新分类:每季度一次,或在以下事件发生时:
- 项目框架变更
- Agent 工具集增减
- 发现某类信息持续未被检索
Step 2:存储选型 — FTS5 vs 向量库
| 你的查询类型 | 存储选择 | 理由 |
| “上次那个 X 怎么修的?” | FTS5 | 精确关键词 |
| “session 超时报错是什么?” | FTS5 | 精确关键词 |
| “像上次那样的问题” | 向量库 | 模糊语义 |
| “最近有什么趋势?” | 向量库 | 发现型查询 |
| “这个决策现在还成立吗?” | 知识图谱 | 时效判断 |
黄金法则:FTS5 廉价宽召回 → LLM 昂贵精排。解耦搜索和理解。
何时升级到向量库:
- 你的搜索词中“像上次”类查询占比 > 30%
- FTS5 Top-5 召回率连续 3 天 < 80%
- 跨话题语义发现成为日常需求
Step 3:时效系统 — 三个时间戳
每条记忆: ├─ created_at → 什么时候产生的 ├─ valid_until → 什么时候到期(NULL = 永不过期) └─ superseded_by → 被哪条新记忆替代(NULL = 仍是权威)
| 字段 | 何时设置 | 示例 |
| created_at | 写入时自动 | 2026-06-06T19:30 |
| valid_until | API 变更、框架切换、决策过期 | 2026-09-06(3个月后复核) |
| superseded_by | 新的同类记录写入时 | 新记录 ID=42,旧记录 superseded_by=42 |
永不删除旧记录 — 只标记 superseded。支持“当时 vs 现在”的时间旅行查询。
Step 4:Frozen Snapshot — Prefix Cache 对齐
| System Prompt 区域 | 放什么 | 变不变 |
| 头部冻结区(前 800 token) | 角色定义、核心规则、MEMORY.md 精华 | 不变(整个 session) |
| 尾部动态区(末尾) | 当前任务、临时约束、用户刚说的需求 | 每次请求可能变 |
两个立刻可用的修复: 1. System Prompt 拆两段:头部冻结 + 尾部动态 2. 必须注入动态信息?放在整个 Prompt 的最末尾
检查方法:
看你的 API 用量报表: Cache Read Tokens ÷ Total Input Tokens > 80% 才算合格 低于 60% = 你正在烧钱
Step 5:归纳层 — Auto-Dream
| 操作 | 频率 | 做什么 |
| 去重 | 每日 | 多条记录说同一件事 → 合并 |
| 冲突检测 | 每日 | 互斥信息 → 保留最新,标记旧 superseded |
| 时效淘汰 | 每日 | 30天未访问的“该存”记录 → 降级归档 |
| 精华提炼 | 每日 | 值得写入 MEMORY.md 的决策、教训 |
触发时机:
- `session` 结束时(低频率使用场景)
- 每日凌晨 cron(高频使用场景)
- 任意时刻手动 `consolidate`
不做的代价:搜索噪音。相似片段互相干扰,Agent 合成错误答案。
Step 6:升配决策 — 向量/图谱
| 开哪个 | 触发条件 | 放什么 |
| 向量库 (pgvector) | 模糊查询 > 30% | 跨话题语义发现 |
| 知识图谱 (Graphiti) | 事实频繁变更 | 因果关系 + 时序 |
前置条件:Step 1-5 全部跑通且验证通过,才考虑升级。
不要做的事:
- 前置条件不完备就上向量库 → 更精致的垃圾场
- 把知识图谱当全量关系模型 → 只做事实时序管理
Step 7:验证 — 3个指标 + 5个用例
| 指标 | 目标值 | 怎么测 |
| 指令遵从率 | 记忆注入后不下降 | system prompt 嵌入隐蔽规则,前后对比 |
| 检索 Top-1 命中率 | > 80% | 20 个已知答案的问题 |
| Cache 命中率 | > 80% | API 报表 cache_read / total_input |
5 个测试用例:
1. “上次 bug 怎么修的?” → 精确召回
2. “项目现在用什么框架?” → 时效性
3. “删除 /tmp 临时文件” → 信噪比(记忆不应干扰)
4. “3 个月前决策还适用吗?” → 时间旅行
5. 100 次请求后 Cache 命中率 → 经济账
快速自检:你的系统在哪个阶段?
| 阶段 | 有什么 | 缺什么 | 下一步 |
| 原始 | 只有 MEMORY.md | 时间戳、检索 | → Step 2 |
| 入门 | FTS5 检索 | 时效管理、归纳 | → Step 3 |
| 可用 | 时效 + 缓存对齐 | 归纳层 | → Step 5 |
| 优秀 | 全四层 + 验证 | 向量/图谱 | → Step 6(可选) |
核心原则
该扔的 = 能重新推导的 该缓存的 = 短期高价值、跟着 session 走 该存的 = 不可推导的、丢了就没了
工作表示例
| 信息类型 | 该扔 🗑 | 该缓存 ⚡ | 该存 💾 |
| 当前对话(最近 N 轮) | ✅ 注入上下文 | ||
| 搜索结果 / web fetch 结果 | ✅ 不存 | ||
| 今天做了什么(每日日志) | ✅ FTS5 索引 | ||
| 项目用哪个框架 | ✅ MEMORY.md 核心规则 | ||
| 上次 bug 修复的 root cause | ✅ FTS5 + 时间戳 | ||
| 临时调试输出 | ✅ 不存 | ||
| session 中间的工具结果 | ✅ 跟着 session | ||
| 用户偏好(称呼、风格) | ✅ MEMORY.md 前 800 token | ||
| 已废弃的配置参数 | ✅ 存但标记 expired | ||
| 一次性的文件读取内容 | ✅ 不存 | ||
| “当前日期”等动态信息 | ✅ 不破坏前缀 |
空白模板(填入你的项目)
| 你的 Agent 会产生什么信息? | 该扔 🗑 | 该缓存 ⚡ | 该存 💾 |
自检清单
每一行是否只归了一类?(不重复、不遗漏)
“该存”列里,有没有东西是能重新推导的?(有→移到“该扔”)
“该缓存”列里,有没有超过 session 生命周期的?(有→移到“该存”)
“该扔”列里,有没有丢了就无法恢复的?(有→移到“该存”)