dsh-journal:给 DSH 智能体加一套分级长期记忆

前言

DSH 的智能体默认只会活在一次会话里。会话结束之后,那些关于用户偏好、项目约定、上次进展的信息就全丢了,下一次又要重新问一遍。常见的解法是自己挂一个向量库做检索,或者把日志塞进一个 JSON 文件,但前者运维重,后者记到最后往往变成一锅粥——什么都想留,最后什么也找不到。

dsh-journal 走的是第三条路:不追求相似度检索,而是给每条记忆打上分级,让重要的留得久、不重要的按时淡出。下面介绍这个插件。

这是什么

dsh-journal 是 Ghill-0131 维护的一个 DeepSeek Harness 插件,属「记忆」分类,目前星标为 0。它把一个纯文本的 JSONL 文件包装成宿主里一等公民的 journal 工具,核心能力是分级长期记忆:每条记录带一个级别、一个过期时间和一个复核日期,让长期运行的智能体把对的东西留对的时间,其余的自动交给时间处理。

一句话定位:它是一个小的、可人工审阅的、手工整理的日志,更接近记事本而不是数据库。

分级模型

插件的逻辑是:写的时候要问的不是「这条重要吗」,而是「这条属于骨架还是文件」。等级直接决定生命周期:

级别 含义 生命周期
S 关系、情绪、共同经历、承诺 永不自动删除,钉住
A 持久事实、偏好、关键决策 365 天
B 项目上下文、任务进展 60 天
C 临时细节、一次性操作 7 天

规则很简单,但很实用:怎么跟人说话归 S,昨天排查的端口号归 B,留给下个会话的交接说明归 A,因为它只需要活到被读一次。

过期不会物理删除。prune 是软删除,把过期行移进 archive/;被钉住的行豁免。

核心功能

插件暴露一个工具、八种动作:

动作 作用
add 写入一条记录(level、title、text 必填)
list 列出记录,可按级别 / 状态过滤
search 在标题、正文、标签里做子串搜索
digest 输出 S + A 摘要,新会话最先该读的内容
stats 各级别计数、文件大小、已过期但未清理的数量
review 把某条记录的过期时间往后推
prune 软删除所有超期记录
render 重写 JOURNAL.md,生成可读摘要

存储只有一个文件:<root>/journal.jsonl,一行一个 JSON 对象。写入走临时文件再 rename,中途崩溃不会撕裂存储;读取时如果最后一行为残行则跳过,而不是让调用失败。记录结构如下:

{
  "id": "j-20261104-140902-479d",
  "ts": "2026-11-04T14:09:02+00:00",
  "level": "B",
  "kind": "fact",
  "title": "short one-line title",
  "text": "the body; facts, not reflections",
  "tags": ["..."],
  "pinned": false,
  "status": "active",
  "expires_at": "2027-01-03T14:09:02+00:00",
  "reviewed_at": null,
  "source": ""
}

格式刻意保持朴素:任何能读 JSONL 的脚本都能读它,任何能写一行的脚本都能往里加。

安装与启用

这个插件的安装方式和一般的 npm 依赖不同,需要特别注意。DSH 插件只有在以 link 形式安装时才能拿到宿主包(@deepseek-ai/*);普通的 npm 依赖会导入失败并被静默跳过。README 给出的安装步骤如下。

1、先把代码放到一个稳定的位置,不要放在 profile 目录里,例如 D:\DSH-Plugins\dsh-journal\0.1.0\。

2、用真正的 junction 建立链接。跨盘 symlink 可能被建成坏链且不会报错,所以这里要用 junction:

New-Item -ItemType Junction `
  -Path   "$env:USERPROFILE\.dsh\profiles\desktop\node_modules\dsh-journal" `
  -Target "D:\DSH-Plugins\dsh-journal\0.1.0"

3、profile 的 package.json 里两个列表都要加上它:

// dependencies
"dsh-journal": "link:D:/DSH-Plugins/dsh-journal/0.1.0"

// dsh.profile.bundles
"dsh-journal"

此处要让 Node 来改文件,不要做纯文本替换:多一个逗号就会让 profile 无法解析,harness 直接起不来。

4、重启 harness。

配置写在 bundle 层的 cordis.patch.yml 里:

# key / 默认值 / 含义
# root:  D:/dsh-data/journal (Windows) 或 /dsh-data/journal
#        —— journal.jsonl 所在目录
# toolName: journal
#        —— 该工具在模型工具集里的名字

另外 JOURNAL_ROOT 环境变量可以覆盖 root。

典型用法

下面是在 agent 循环里的典型调用,直接来自 README:

journal action=digest                          # 每次新会话开始时跑一次
journal action=add level=S title="..." text="..."
journal action=search query=备考
journal action=prune dryRun=true               # 先看哪些会过期,不做任何改动

日常的节奏是:会话开始读 digest 拿到该知道的部分;过程中把不断产生的信息按级别写进去;结束前跑一次 prune dryRun=true 确认没有要提前 review 的内容,需要延长就 review,不需要就让过期项自然归档。

适用场景与注意事项

适合那些需要跨会话延续上下文、但不想引入向量库和检索链路的 DSH 开发者。它的赌注是:一个写下几百条关键行、并按时遗忘其余内容的智能体,胜过一个什么都要存、再靠搜索找回来智能体。

要注意几点:

  • 这是一个插件,以当前 dsh 进程的权限运行,安装前应先检查源码与许可证(MIT)。
  • 它不是向量库,不做相似度检索,无法替代语义召回。
  • journal 工具会出现在模型的工具集里,级别划分是否合理、过期时间是否合适,需要结合实际任务调。
  • 依赖 Node >= 22.13。

结尾

dsh-journal 的价值不在于存储量,而在于它给了智能体一套「该记什么、记多久」的明确规则,并且整个存储是纯 JSONL,可以人工读、可以脚本读写。如果你在用 DSH 做长期运行的助手,值得把它作为第一个记忆层试一下。

  • 目录页:https://www.skillhub.cn/plugins/Ghill-0131/dsh-journal
  • GitHub:https://github.com/Ghill-0131/dsh-journal
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜