本期拆解 L2:记忆卡片如何按情境归档成
.md场景文件,以及为什么"让 LLM 当 Agent 改文件"比"让 LLM 生成文本"更可靠。
代码版本:
2.0.0-beta.1
一、L2 的定位
官方定义:
L2 Scenario:围绕项目或场景组织的知识块 —— 用于快速恢复一个工作场景。
L1 的卡片是"点"(每条事实独立),L2 要把它们组织成"面"(按情境归档)。比如"鉴权模块重构"这个场景,会把相关的事实、决策、进度、约束全部收进一份场景档案。
核心实现文件是 scene-extractor.ts,官方架构文档的描述是:
L2:
core/scene/scene-extractor.ts—— LLM 作为"沙箱 Agent"(CleanContextRunner,enableTools),工作目录锁死在scene_blocks/,只能用工具读写.md场景文件;每次抽取前 backup/checkpoint,抽取后同步 scene_index、重建导航。
二、关键设计:LLM 是"沙箱 Agent",不是"一次性生成器"
这是 L2 最特别的地方。普通做法是"把记忆丢给 LLM,让它输出整理好的文本";TDAM 的做法是让 LLM 以 Agent 身份运行,自己决定读哪个文件、改哪个文件、合并哪些场景。
源码注释写得很直白:
SceneExtractor: LLM-driven memory extraction into scene blocks. Replaces the keyword-based SceneManager.processNewMemories() with an LLM agent that autonomously reads/writes scene block files using tools.
Security: The LLM is sandboxed — workspaceDir is set to scene_blocks/ so it can ONLY operate on .md scene files. System files (checkpoint, scene_index, persona.md) are physically invisible to the LLM.
三句话概括:
- 工具模式:CleanContextRunner 开启
enableTools,LLM 有 read / write 工具; - 物理沙箱:
workspaceDir锁死在scene_blocks/,checkpoint、scene_index、persona.md 这些系统文件对 LLM 物理不可见; - 自主决策:CREATE / UPDATE / MERGE / ARCHIVE 哪个场景,由 LLM 自己判断。
为什么这样做?场景整理是个"多次读改"的过程(先看现有场景 → 决定归并 → 写入),一次性生成的文本无法增量维护;而且把系统文件隔离在外,LLM 永远不可能误改索引和画像本体。
三、抽取流程(8 步)
① 备份 + 读 checkpoint
② 加载 scene_index + 构建场景摘要(含容量提示 "N / 15")
③ 容量控制分档警告(≥15 强制 MERGE;=14 禁 CREATE;≥12 建议 UPDATE/MERGE)
④ 快照 pre-extract 索引与内容(供 diff created/updated/deleted)
⑤ LLM 沙箱执行(工具模式,workspaceDir=scene_blocks/,超时 300s)
└── 失败 → 从备份 restore 回滚
⑥ 软删除清理 + 文件名规范化
⑦ 同步 scene_index + 更新 persona.md 场景导航
⑧ 解析 PERSONA_UPDATE_REQUEST 信号 → 写 checkpoint
容量控制(分档警告)
场景数量默认上限 15 个(maxScenes)。LLM 在 Prompt 里会看到"当前场景总数:N / 15"的提示,系统按档位约束:
| 数量 | 约束 |
|---|---|
| ≥ 15 | 必须先 MERGE 最相似的 2–4 个场景为 1 个,再处理新记忆 |
| = 14 | 本次只能 UPDATE,禁止 CREATE 新场景 |
| ≥ 12 | 建议优先 UPDATE 或主动 MERGE |
这套机制保证场景库有上限、可收敛,不会无限膨胀。
安全机制
- 备份 / 回滚:每次抽取前
BackupManager对scene_blocks/做目录备份(保留最近 10 份);LLM 执行失败时从备份恢复,防止部分写入泄漏进下一次召回。 - 软删除:LLM 没有 exec 工具、不能删文件,它"删除"的方式是往文件里写
[DELETED]标记(写空内容会被工具参数校验拒绝)。清理阶段统一移除这些标记文件。 - META-only 文件:LLM 合并场景时可能留下只有
[ARCHIVE]/[CONSOLIDATED]头、没有正文的文件,也会被清理。 - 文件名规范化:LLM 偶尔产出带空格 / 标点的文件名(如
Daily Rhythm in Shanghai.md),会破坏下游\S+\.md正则解析——抽取后统一规范为安全命名。
场景文件格式
每个场景是一个 Markdown 文件,frontmatter 记录元数据:
---
type: scene
title: 鉴权模块重构
created: 2026-08-01
updated: 2026-08-20
summary: 重构进度与约束
heat: 7
---
# 鉴权模块重构
- 别重构旧鉴权模块,移动端还在用
- 新方案已评审,待排期
heat(热度):被检索命中一次 +1,热度最高的场景在导航里排最前;- 正文是 Markdown,人可以直接读、直接改——这也是第 1 期说的"高层写 Markdown"的落地。
与 persona 的联动
L2 抽取完成后有两个"越界"动作:
- 更新 persona.md 的场景导航:导航块(场景列表)由系统生成并追加到 persona.md 尾部,LLM 不参与;
- 解析 Persona 更新信号:如果 LLM 在输出里带了
[PERSONA_UPDATE_REQUEST]reason: xxx[/PERSONA_UPDATE_REQUEST]块,说明它认为有值得写入长期画像的内容,系统把原因写进 checkpoint,触发 L3 生成(详见第 5 期)。
四、存储与同步
- 权威存储:
scene_blocks/*.md文件; - 索引:
scene_index(记录每个场景的 filename / heat / updated / summary),供召回与 L3 使用; - 远端同步:文件通过 ProfileRecord 同步(
id = profile:v1:sha256(scope+type+filename)),供 TCVDB 等远端后端拉取;profiles 表是同步副本,文件才是权威。
五、本期小结
- L2 的职责:把 L1 卡片按情境归档为可读可改的
.md场景档案。 - 核心机制:LLM 沙箱 Agent —— 工具模式 + 物理隔离系统文件 + 自主 CREATE/UPDATE/MERGE。
- 工程保障:备份回滚、软删除清理、文件名规范化、容量分档上限。
- 场景文件带 frontmatter(时间 / 摘要 / 热度),是召回导航与 L3 生成的输入。
- 与 L3 联动:场景变化可触发 Persona 更新请求。
下一期看金字塔尖:L3 长期画像——Persona 的生成与维护。
图示索引
- 图示:L2 场景记忆:LLM 沙箱 Agent 维护场景档案(在新窗口打开完整图示)
源码索引
| 内容 | 文件 |
|---|---|
| L2 抽取主流程 | MemoryCore/src/core/scene/scene-extractor.ts |
| 场景文件格式 | MemoryCore/src/core/scene/scene-format.ts |
| 场景索引 | MemoryCore/src/core/scene/scene-index.ts、scene-navigation.ts |
| 文件名规范化 | MemoryCore/src/core/scene/filename-normalizer.ts |
| 抽取 Prompt | MemoryCore/src/core/prompts/scene-extraction.ts |
| 沙箱运行时 | MemoryCore/src/utils/clean-context-runner.ts、checkpoint.ts、backup.ts |