TD-AI 四层记忆系统详解:如何让 AI 拥有"第二大脑"
概述
@tdai/memory-tdai 是一个运行在 OpenClaw 上的四层本地记忆系统插件。核心特性:完全离线、四层渐进式提炼、零外部依赖,通过 LLM 将对话原始数据逐层抽象为结构化记忆、场景块和用户画像。
本文深入解析其核心机制,源代码级解读。
整体架构
1 | 对话结束 |
L0:对话录制
目标:原始捕获每轮对话消息,零丢失。
双写机制
L0 recorder 同时写入两个存储:
| 存储 | 路径 | 用途 |
|---|---|---|
| SQLite vec0 | vectors.db |
向量搜索(可选) |
| JSONL | conversations/*.jsonl |
原始消息持久化 |
1 | // 对话消息结构 |
质量门控(Quality Gate)
L0 不做过滤(全部捕获),L1 阶段才执行严格过滤:
1 | // L1 质量门控规则 |
这是设计选择:录制端保真,提取端严控。
原子性写入(Checkpoint + 文件锁)
auto-capture.ts 使用文件锁防止并发写入导致重复记录:
1 | await checkpoint.captureAtomically(sessionKey, pluginStartTimestamp, async (afterTimestamp) => { |
L1:记忆提取
目标:从 L0 原始对话中,用本地 LLM 提炼出结构化记忆片段。
核心设计:一趟 LLM 调用完成两件事
l1-extractor.ts 的 callLlmExtraction 函数,一次 LLM 调用同时输出:
- 情境切分(Scene Segmentation):将对话按话题边界分段
- 记忆提取:每段提取多条结构化记忆
提示词工程(Prompt 核心逻辑)
L1 提取提示词(l1-extraction.ts)定义了严格的输出规范:
1 | // 支持提取的三大类型 |
时间建模:episodic 记忆支持两种时间标注:
1 | { |
activity_start_time+activity_end_time:段时间(活动持续期)- 两者皆无时:回退使用 L0 的 message timestamp 作为点时间
冲突检测(Batch Dedup)
提取后的记忆通过向量相似度做冲突检测(l1-dedup.ts):
三段降级策略:
1 | 1. Vector Recall(向量召回)→ cosine similarity Top-K 候选 |
1 | // 冲突决策类型 |
场景连续性
previousSceneName 参数实现跨批次上下文连续:
1 | // 提取提示词模板 |
L2:场景归纳
目标:将 L1 碎片记忆融合为连贯的叙事文档(Scene Block)。
核心原则:不是清单,是叙事
场景文件不是记忆列表,而是连贯段落。这是 L2 和 L1 的本质区别:
| 层级 | 形态 | 单位 |
|---|---|---|
| L1 | JSONL 片段 | 单条记忆 |
| L2 | Markdown 叙事文档 | 场景(多条相关记忆融合) |
场景文件格式
1 | -----META-START----- |
热力管理(Heat)
每条场景记录 heat 值,驱动更新优先级:
| 操作 | heat 变化 |
|---|---|
| 新建 | heat = 1 |
| 更新 | heat = 旧值 + 1 |
| 合并 | heat = sum(所有相关) + 1 |
场景数量上限 15 个。达到上限时强制合并最低热度场景。
LLM 驱动的场景操作
scene-extractor.ts 使用 read_file + write_to_file / replace_in_file 让 LLM 直接操作 Markdown 文件。LLM 输出中的 [PERSONA_UPDATE_REQUEST] 信号触发 persona 更新。
L3:用户画像
目标:基于 L2 场景块,生成/更新 persona.md。
触发条件
每 N 条新记忆触发一次画像生成(默认 N = 50)。
Persona 文件结构
1 | # User Narrative Profile |
备份机制
每次更新前自动备份,保留最近 3 个版本(scene_backupCount: 10)。
Auto-Recall:记忆召回
目标:对话开始前,将相关记忆注入 Agent 上下文。
召回管线
1 | async function performAutoRecall({ userText, ... }) { |
三种搜索策略
| 策略 | 原理 | 适用场景 |
|---|---|---|
keyword |
FTS5 BM25 关键词匹配 | 无向量引擎 |
embedding |
向量余弦相似度 | 有本地/远程 embedding |
hybrid(默认) |
关键词 + 向量 RRF 融合 | 两者兼备 |
RRF(Reciprocal Rank Fusion)融合
1 | // RRF 公式:score = Σ 1 / (k + rank_i) |
关键词和向量两个排序列表,按 RRF 分数加权融合——同时命中两条检索路径的记忆得分更高。
记忆格式化(Prompt 注入格式)
1 | // 输出示例 |
向量引擎:sqlite-vec
存储:vectors.db(SQLite + vec0 扩展)
支持的操作:
1 | -- 向量存储(L0 和 L1 双重索引) |
本地 embedding:使用 node-llama-cpp 加载 GGUF 模型(首次运行自动下载),完全离线。
与 Builtin Memory 的区别
| 维度 | Builtin Memory | memory-tdai |
|---|---|---|
| 架构 | MEMORY.md + SQLite |
四层 L0→L1→L2→L3 管线 |
| 提取方式 | 手动写入 | 自动 LLM 提取 |
| 向量 | 可选 | sqlite-vec + 本地 GGUF |
| 用户画像 | 无 | persona.md 完整画像 |
| 场景归纳 | 无 | 叙事型 Scene Block |
总结
memory-tdai 的核心设计哲学:本地优先、LLM 驱动、四层渐进提炼。
- L0 原始保真,零丢失
- L1 结构化抽象,质量门控 + 向量去重
- L2 叙事融合,热力管理驱动演化
- L3 用户画像,跨场景归纳
整个系统无需任何外部 API,所有数据留在本地,是真正意义上的”私有第二大脑”。