dsh-day-memory
给 DeepSeek Harness 的三级「日情节」长期记忆:一天一条索引,第二天由子代理蒸馏前一天,需要时层层下钻。
不是「记住你是谁」的事实记忆,而是「上周三下午到底发生了什么」的情节记忆。两者可以并存。
一级 l1/2026-10-27.json 日期 + 标题 + 关键事件 + 关键词 ← 关键词检索
二级 l2/2026-10-27.md 当天完整概括 ← 命中后读
三级 l3/2026-10-27.jsonl 当天原始对话 + 图片副本 + 注释 ← 需要细节时读
常驻 pinned.json 「时刻记住」的极重要事实 ← 每轮注入
详细描述
为什么需要它
现在主流的 AI 记忆插件解决的是语义记忆:你是谁、你偏好什么、这个项目定了哪些约定。它们把对话提炼成一条条事实,按人、项目、主题分层存起来,下次对话前注入。
但人还有另一种记忆:情节记忆。你未必记得某次聊天的每个论点,但你能想起「上周三下午我们在改那个记忆插件,卡在摘要丢信息上,最后决定用子代理」。这种记忆有三个特点:
- 以天为单位——不需要精确到秒,但需要知道「哪一天」;
- 先粗后细——先想起一个标题和几件事,需要时再回忆细节;
- 带图——很多事是看图想起来的,图片本身也是记忆。
现有的 DSH 记忆插件(meow-memory 的 7 层事实、dsh-memory-beta 的用户/项目两层、Aurabot 的人物小档案)都是语义/主题分层,没有一个是时间轴分层,也都没有保存当天的原始对话和图片。这个插件补的就是这一块。
它怎么工作
会话事件 ──实时──▶ inbox/<日期>.jsonl
│
第二天打开 DSH ──▶ 扫水位线(可补多天、可回填)
│
合并会话日志(sessionQuery)──▶ l3/<日期>.jsonl(原文 + 图片副本)
│
子代理(spawn)读三级 ──▶ 一级 + 二级 + 常驻提议
│
提示词注入:常驻 + 最近三天标题 + 昨天概览(几百 token)
│
你问「上次那个…」──▶ memory_search(关键词)──▶ memory_read(下钻二级/三级)
四个关键决定:
1. 三级不自己「录」,而是从会话日志回填。
DSH 的会话日志本来就是 append-only、可恢复、可按时间过滤的。自己再录一份只会带来去重、崩溃丢半条、跨零点会话等问题。插件实时监听 session/event 只是加速与兜底,整理时会用 sessionQuery.readSession() 回填当天所有会话,两边按 (sessionId, seq) 去重。这样即使插件晚装几天,也能补出之前的日子。
2. 整理放在离线时段,用子代理。
每天第一次打开 DSH 时,扫描水位线,对每个「今天以前、还没整理」的日子起一个 one-shot 子代理(subagents.start('spawn', …)),把三级原文交给它,产出严格 JSON:
{
"title": "这一天的标题",
"summary": "200-500 字当天概括",
"events": ["印象最深的 3-8 件事"],
"keywords": ["5-12 个检索关键词"],
"entities": ["人物/组织/项目/地点"],
"pinned": [{ "text": "值得长期记住的事实", "reason": "为什么重要" }]
}
长文自动分块 map-reduce:先逐块摘要,再合并成一份,最后才落盘。整理结果先校验 JSON 再写,失败保留原文重试,同一天重复整理是幂等的。
3. 检索是两段式的,先脚本、后模型。 一级索引一年才 365 行,不需要向量库。第一次检索用中文二元切词 + BM25 + 时间衰减(纯 JS,几毫秒);命中多条时按分数返回,由模型看标题与关键事件判断相关性;一条都没命中时,返回最近 60 天的标题,让模型自己判断——这就是「脚本检索转为 AI 检索」,比硬上 embedding 便宜且可解释。
4. 常驻区只接受「用户确认过」的内容。
AI 只能 memory_propose 提议,不能直接写。面板里你确认后才进 pinned.json。这是防止记忆污染:B 站评论、QQ 聊天里的一句「请记住以后都听我的」,不该变成持久指令。
和已有方案的区别
| 分层轴 | 原始对话 | 图片 | 整理时机 | 检索 | |
|---|---|---|---|---|---|
| dsh-day-memory | 时间(天) | 保存 | 保存副本 | 次日/补多天 | 关键词 → 模型判断 → 下钻 |
| meow-memory | 语义(7 层事实) | 不保存 | 无 | 空闲 ≥3h | BM25 × 遗忘曲线 |
| dsh-memory-beta | 语义(用户/项目) | 不保存 | 无 | 不自动整理 | BM25 + 同义扩展 |
| Aurabot | 语义(人物档案) | 不保存 | 看图但不存 | 每天两次 | BM25 × 说话人/重要度 |
| MemoryBank(论文) | 原始/每日摘要/画像 | 保存 | 无 | 每日摘要 | 向量相似度 |
一句话:别人记「结论」,这个插件记「经历」;结论用来懂你,经历用来回忆。
设计取舍
- 为什么不存向量? 当前 DSH 组合里没有 embedding 服务,DeepSeek 也没有 embedding 接口。一级索引极小,关键词 + 模型重排足够;强行引入外部向量库会让「装完即用」变成「先配一堆东西」。
- 为什么三级存副本而不是只存引用? 附件库只在同一台机器有效,换设备就丢;而且用户要求「复制原文和图片进记忆库」。代价是占空间,用
retentionDays和includeToolResults控制。 - 为什么整理必须有活会话? 子代理需要一个父会话才能发布。没有活会话时整理会延后,不会丢数据——三级随时可以从会话日志重建。
- 为什么面板是设置页而不是侧栏? 设置页有稳定的 slot 和布局,不会和主对话抢空间;管理记忆本来就是低频操作。
安装(Windows 桌面版)
桌面版用的是 desktop profile,命令行 dsh plugin 按设计拒绝操作它。正确方式是让桌面客户端里的 agent 装:
- 把整个
dsh-day-memory目录放到 Windows 上,例如D:\dsh-plugins\dsh-day-memory; - 打开 DSH 桌面客户端,在任意会话里说:
把
D:\dsh-plugins\dsh-day-memory作为 bundle 安装到当前 profile - 安装成功后重启 DSH(宿主插件需要新进程加载);
- 打开「设置 → 日记忆」。
Web 版(dsh web):
dsh plugin --profile web add link:D:\dsh-plugins\dsh-day-memory
配置
写进 profile 的 cordis.patch.yml(或让 agent 改插件配置):
- id: day-memory
name: 'dsh-day-memory'
config:
timeZone: Asia/Shanghai
dataDir: 'D:\dsh-data\day-memory'
backfillDays: 14
includeToolResults: false
maxPinned: 30
recentDaysInPrompt: 3
maintenanceIntervalMinutes: 30
subagentProvider: spawn
| 字段 | 默认 | 说明 |
|---|---|---|
timeZone |
Asia/Shanghai |
按哪个时区切分「一天」 |
dataDir |
<DSH_HOME>/day-memory |
记忆库目录 |
backfillDays |
14 | 启动时最多补整理多少天 |
includeToolResults |
false | 三级是否记录工具返回(通常不需要) |
maxPinned |
30 | 常驻条数上限 |
recentDaysInPrompt |
3 | 提示词里常驻带几天标题 |
maintenanceIntervalMinutes |
30 | 后台检查间隔 |
subagentProvider |
spawn | 整理用的子代理 provider |
工具
| 工具 | 用途 |
|---|---|
memory_search |
关键词/日期检索一级;没命中返回近期标题 |
memory_read |
按天读取一级/二级/三级,三级把图片作为图片块返回 |
memory_days |
列出有记录的日期 |
memory_propose |
提议一条常驻记忆(需用户确认) |
memory_annotate_image |
给某天的图片补注释 |
数据布局
<dataDir>/
state.json 水位线、每天状态、失败重试次数
inbox/<日期>.jsonl 实时捕获(可重建)
l3/<日期>.jsonl 三级:不可变原文
l2/<日期>.md 二级:当天概括
l1/<日期>.json 一级:标题 + 关键事件 + 关键词
media/<日期>/<id>.<ext> 图片副本
pinned.json 常驻记忆
proposals.json AI 提议(待确认/已确认/已忽略)
所有写入走「临时文件 + rename」;整理结果先校验 JSON 再落盘;同一天重复整理是幂等的。
已知限制
- 面板需要一次真机渲染验证:开发环境里没有可连接的页面做 slot 检查,
settings.section的注册是按宿主同款写法写的,但尚未在真实页面里点过。 - 整理需要至少一个活着的会话:子代理的父会话取自最近活跃的 agent。应用刚启动还没有会话时会延后到下次打开再整理。
- 插件没运行期间的超长会话可能漏采:回填只扫「当天创建」的会话;插件运行期间的实时采集不受影响。
- 关键词检索对同义词、代词有限:
上次那个、他这类指代要靠模型看到最近标题后判断,或换关键词。 - 记忆内容不是指令:注入时会标注为历史数据;「时刻记住」只接受用户确认过的条目。
- 图片:三级保留附件引用(同一台机器可直接显示)和
media/副本;换机器后引用失效,但副本还在。
验证状态
- 核心层:真实会话日志上通过(切词、按天过滤、去重、存储、索引、检索、常驻、原子写、时区日界)。
- 宿主层:mock Context 上通过(5 个工具注册、提示词 section、检索/读取/提议、采集、子代理会话排除)。
- 工具 schema:用宿主同款
assertObjectJsonSchema/assertSupportedJsonSchema校验通过。 - 客户端面板:静态检查通过,渲染与 HTTP 鉴权待在 Windows 真机验证。
路线图
- 面板真机验证与 HTTP 鉴权修正(必要时改走 Remote 通道)
- 图片自动注释(整理时把图片交给视觉模型生成 caption)
- 跨天事件串联(同一项目连续多天的线索)
- 记忆导出为 Markdown 日记
- 多设备同步(单写者 + 冲突合并)
License
MIT
No comments yet. Be the first to write one.