dsh-memory:为 DeepSeek Harness 补上跨会话记忆

前言

在 DeepSeek Harness(DSH)里做多轮智能体开发时,常见矛盾是:会话内的上下文可以压缩,但会话一结束,模型对「上次聊过什么、项目里约定过什么」就无从自动继承。有人用 AGENTS.md 手写长期说明,有人靠会话 JSONL 或 SQLite 检索自己翻历史——前者不会随对话生长,后者需要主动查,且默认未必打开。

dsh-memory 针对的是中间这一环:一轮对话结束后自动蒸馏成长期笔记,下次会话在模型请求前把全局笔记与当前工作区笔记注入提示段。数据落在本地 markdown,不依赖云服务,也不写会话日志。

这是什么

  • 插件名称:dsh-memory(社区目录:dph-1121/dsh-memory)
  • 维护者:DPH-1121
  • 分类:记忆
  • 简介(目录页):Session-end memory for DeepSeek Harness: distils each turn into durable notes and recalls them per workspace
  • 许可:MIT(见仓库 LICENSE)
  • 当前包版本(package.json):0.1.1

实现上不替代 dsh-compaction-*(只压当前会话)、dsh-session-persistence-jsonl(存原文但无人总结)、dsh-agent-instructions(人手写的 AGENTS.md)或 dsh-session-query-sqlite(主动检索)。它只做「结束 → 总结 → 下次带上」。

核心功能

召回(每次模型请求前)

按 agent 注册作用域提示段 memory:recall,插入顺序在 FILE_REFERENCE(900) 减 50,即约 850:紧挨环境类上下文,在 persona 之后、工具说明之前。召回内容为 全局 MEMORY.md + 当前工作区 MEMORY.md,有字节上限(见配置 DSH_MEMORY_RECALL_BYTES)。

必须按 agent 注册,不能全局注册:AssembleContext 拿不到 agent,全局段无法知道当前工作区;且 fiber 随 agent 卸载,避免泄漏到下一会话。

蒸馏(agent/turn-stopping)

在 agent/turn-stopping 上 await 执行蒸馏。选用该事件是因为它是 serial 的——promise 未 settle 则 turn 不关闭。空闲防抖在 dsh --profile headless "…" 一类「跑完即退出」场景下不可靠,故不用「turn 之后再跑」。

普通短轮次通过两道闸门降低开销:

闸门 默认 环境变量
新一轮文本量下限 600 字符 DSH_MEMORY_MIN_CHARS
同一会话两次蒸馏最小间隔 60 秒 DSH_MEMORY_MIN_INTERVAL_MS

正文来源是 session/event 里 user/message 且 source.kind === 'user' 与 assistant/message。合成消息(召回段本身、文件变更、skill 正文、goal 续跑等)不纳入,避免记忆把自己的输出当新事实反复总结。

蒸馏走默认模型路由(agentDefaultModel.currentSelection()),即一次普通的 ctx.llm.stream(),无单独模型配置项。

存储布局

$DSH_HOME/memory/
├─ MEMORY.md                          # 全局笔记
├─ workspaces/
│  └─ <slug>-<hash8>/MEMORY.md        # 按工作区隔离
└─ journal/
   └─ YYYY-MM-DD.md                   # 每次蒸馏段落,append-only

工作区目录名生成 <slug>-<hash8>(路径 sha1 前 8 位),区分同名路径。笔记行格式:- YYYY-MM-DD HH:mm · <一句话>,可手改。追加按归一化文本去重;单文件超过 DSH_MEMORY_FILE_BYTES 时丢弃最旧条目。写入使用临时文件 + rename。

模型输出解析为 JSON:global、workspace、summary 分别写入全局文件、工作区文件与 journal;解析取最外层花括号对,容忍代码块包裹。

明确不做的事(0.1.x)

  • 不读 $DSH_HOME/sessions 会话日志;不依赖 session-query-sqlite。
  • 写入范围仅限 $DSH_HOME/memory/。
  • 无工具、无斜杠命令;不做向量检索,召回为全量注入(有上限)。

安装与启用

官方 README 给出的安装方式为本地 tgz 路径(示例文件名含 0.1.0,以你实际拿到的包为准):

dsh plugin --profile web add /path/to/dsh-memory-0.1.0.tgz

装完后 需要重启 profile:插件在进程启动时挂载 agent/created、session/event、agent/turn-stopping 等事件,非热插拔。

运行环境(package.json engines):

  • Node:^22.19.0 || >=24.0.0
  • DSH:>=0.1.6-alpha.1 <0.1.7-0 || >=0.1.7-alpha.0 <0.2.0-0 || >=0.2.0-rc.1 <0.2.1-0 || >=0.2.1-rc.2 <0.3.0-0

配置

全部通过环境变量,宿主侧无需导入本包(仅 node: 内置模块):

变量 默认 作用
DSH_MEMORY_DISABLED — 非空则挂载但完全惰性
DSH_MEMORY_ROOT $DSH_HOME/memory 记忆根目录
DSH_MEMORY_MIN_CHARS 600 新一轮文本量下限
DSH_MEMORY_MIN_INTERVAL_MS 60000 同会话蒸馏最小间隔
DSH_MEMORY_TRANSCRIPT_CHARS 16000 单次蒸馏正文上限
DSH_MEMORY_RECALL_BYTES 6000 召回段字节上限
DSH_MEMORY_FILE_BYTES 32000 单记忆文件字节上限
DSH_MEMORY_MAX_TOKENS 1200 单次蒸馏输出 token 预算
DSH_MEMORY_TIMEOUT_MS 45000 单次蒸馏超时

典型用法与验证

日常无需命令:装好并重启 profile 后,多轮对话满足闸门条件即自动蒸馏;下次同工作区会话会自动带上相关笔记。若要改长期事实,直接编辑 $DSH_HOME/memory/ 下对应 MEMORY.md。

维护者提供的冒烟测试:

node test/smoke.mjs

覆盖提示段注册、召回为空、合成消息过滤、蒸馏落盘、工作区键格式等;端到端行为见仓库 docs/verification.md。

适用场景与注意

适合:希望 DSH 在本地沉淀跨项目/跨工作区约定与事实、又不想维护云记忆或手写不断膨胀的 AGENTS.md 的开发者。

注意:

  1. 插件以当前 dsh 进程权限 运行,安装前宜阅读源码与 MIT 许可证,确认写入路径与模型调用符合你的环境策略。
  2. 召回不是语义检索;笔记量很大时可能需要后续版本换策略(README 提及 0.2 方向)。
  3. DSH 生态是「一切皆插件」;SkillHub 插件目录 为社区站点,与 DeepSeek / 幻方无官方从属关系。

结尾

dsh-memory 用本地 markdown 把「会话结束自动总结、下次按工作区召回」做成默认行为,与 compaction、会话持久化、手写 instructions 互补。目录与源码:

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

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

小夜