🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

四层记忆 jiachenleo9-create/dsh-memory

DeepSeek 客户端
jiachenleo9-create20 天前有提交已提供中文文档扫描:含敏感能力兼容 / 相关生态

自动记住你的偏好与目标,跨会话不再失忆

29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/16 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/jiachenleo9-create/dsh-memory.git

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
数据截至 2026/11/04·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 20 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件
查看扫描证据(共 34 处,展示前 21 条)
  • 读取本地文件
    lib/store.js:104
    return readFileSync(path, 'utf8')
  • 写入本地文件
    lib/store.js:119
    mkdirSync(join(path, '..'), { recursive: true })
  • 写入本地文件
    lib/store.js:124
    writeFileSync(temp, text, 'utf8')
  • 写入本地文件
    lib/store.js:125
    renameSync(temp, path)
  • 删除本地文件
    lib/store.js:129
    rmSync(temp, { force: true })
  • 写入本地文件
    lib/store.js:140
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    lib/store.js:192
    if (existsSync(join(candidate, 'WORKSPACE.md'))) {
  • 读取本地文件
    lib/store.js:240
    const existed = existsSync(this.globalIndexPath)
  • 读取本地文件
    lib/store.js:416
    if (existsSync(path)) continue
  • 读取本地文件
    lib/store.js:481
    if (!existsSync(port)) {
  • 读取本地文件
    lib/store.js:522
    if (!existsSync(active)) {
  • 删除本地文件
    lib/store.js:758
    try { rmSync(file.full, { force: true }) } catch { }
  • 写入本地文件
    lib/store.js:976
    writeFileSync(probe, token, 'utf8')
  • 删除本地文件
    lib/store.js:978
    rmSync(probe, { force: true })
  • 删除本地文件
    lib/store.js:982
    try { rmSync(probe, { force: true }) } catch { }
  • 读取本地文件
    lib/audit.js:38
    return readFileSync(path, 'utf8')
  • 读取本地文件
    lib/audit.js:154
    if (existsSync(archiveDir)) {
  • 读取本地文件
    lib/audit.js:156
    const files = readdirSync(archiveDir)
  • 读取本地文件
    lib/audit.js:161
    try { mtime = statSync(full).mtimeMs } catch { }
  • 读取本地文件
    lib/audit.js:188
    if (existsSync(sessionsDir)) {
  • 读取本地文件
    lib/audit.js:190
    result.sessionLogs = readdirSync(sessionsDir).filter((name) => name.endsWith('.md')).length
扫描于 2026/11/4(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DSH 四层自动记忆系统:会话开始自动读取记忆、长任务目标锚定防遗忘、每轮结束自动沉淀、跨工作区审计。纯 Markdown、零依赖、可审计。

README

由 DeepSeek 最新模型翻译生成
dsh-memory 四层自动记忆系统,为 DSH(DeepSeek Harness) 开发。 让每一个工作区的 AI 都记得住你、记得住自己在干什么。 装一次,全局生效;你只需要偶尔当「班主任」检查一下。 架构总览 目录 - 一、它解决什么问题 - 二、和别的记忆方案比,它凭什么不一样 ← 重点 - 三、班级分工:四层各管什么 - 四、自动化发生在什么时候 - 四·补、L1 记忆库到底落在哪 ← 新用户必读 - 五、省 token 的六条设计 - 六、安装 - 七、使用:你只需要做三件事 - 八、班主任审计 - 九、配置 - 十、模型可用的工具 - 十一、消息来源格式(DSH 插件开发者必读) - 十二、隐私红线 - 十三、可靠性:14 套测试与 8 个真实事故 - 十四、文件结构 - 十五、常见问题 - 十六、设计取舍 一、它解决什么问题 AI 编程助手有个通病:每一次对话它都从零开始认识你。 你昨天说过的技术栈、上周定下的规范、半小时前刚踩过的坑 —— 新开一个会话就全没了。 更糟的是长任务:聊到几十轮之后,它开始忘记最初要做什么,产出越来越偏。
展开完整文档(README 剩余 1 节)
dsh-memory

四层自动记忆系统,为 DSH(DeepSeek Harness) 开发。

让每一个工作区的 AI 都记得住你、记得住自己在干什么。
装一次,全局生效;你只需要偶尔当「班主任」检查一下。

架构总览

目录

- 一、它解决什么问题
- 二、和别的记忆方案比,它凭什么不一样 ← 重点
- 三、班级分工:四层各管什么
- 四、自动化发生在什么时候
- 四·补、L1 记忆库到底落在哪 ← 新用户必读
- 五、省 token 的六条设计
- 六、安装
- 七、使用:你只需要做三件事
- 八、班主任审计
- 九、配置
- 十、模型可用的工具
- 十一、消息来源格式(DSH 插件开发者必读)
- 十二、隐私红线
- 十三、可靠性:14 套测试与 8 个真实事故
- 十四、文件结构
- 十五、常见问题
- 十六、设计取舍

一、它解决什么问题

AI 编程助手有个通病:每一次对话它都从零开始认识你。

你昨天说过的技术栈、上周定下的规范、半小时前刚踩过的坑 —— 新开一个会话就全没了。
更糟的是长任务:聊到几十轮之后,它开始忘记最初要做什么,产出越来越偏。

dsh-memory 把这件事变成全自动的基础设施:

| 问题 | 没有它的时候 | 有它之后 |
| 每次都要手动唤起记忆技能 | 忘了唤起 → AI 这次就不"懂你" | 会话开始自动注入,零操作 |
| 长任务做到后面忘了最初目标 | 压缩/长对话后跑偏、产生幻觉 | 原始目标逐字存档,压缩后与每 N 轮自动重述 |
| 换个项目就"失忆" | 不知道这个目录是干嘛的、要守什么规矩 | 每个工作区独立记忆端口,首次进入自动建好 |
| 任务做完经验没留下 | 下次遇到同样问题重新踩一遍 | 归档闸门逼着沉淀进跨工作区共享的长期库 |
| 怕隐私被落盘 | 不知道 AI 偷偷记了什么 | 隐私红线落成可执行代码,写入前强制自检 + 脱敏 |
| 不知道 AI 到底记了啥 | 只能一个个文件翻 | 一条命令看全部工作区的审计报告 |

全部数据都是你自己磁盘上的 Markdown 文件。 没有数据库、没有云同步、没有账号,用任何编辑器都能读写,删掉插件也照样在。

二、和别的记忆方案比,它凭什么不一样

这一节是我在写这个插件前调研了同类项目之后总结的。如果你只用一句话选它,那就是:它是唯一把「记忆的四种职责」分开、并且为「跨工作区共享」设计了强制机制的方案。

2.1 三类主流方案,各自的取舍

| 方案类型 | 代表 | 强项 | 代价 |
| 向量库 / RAG | mem0、Zep、cognee | 语义检索强,能处理海量碎片 | 需要 embedding 服务或本地模型;引入依赖;不透明(你不知道它记住了什么、为什么这么答) |
| 单文件指令 | CLAUDE.md / AGENTS.md | 简单、直接、人人会用 | 只有一层;越写越长,最后没人维护;每次全量注入,token 浪费 |
| 会话记忆插件 | Cline Memory Bank、memory-toolkit、claude-compact-memory | 解决"这次会话别忘事" | 大多只管当前会话/当前项目;跨项目共享基本靠手动 |

2.2 dsh-memory 的四个结构性差异

差异一:四层职责分离,而不是四层文件夹

大多数"多层记忆"是按容量分的(热/温/冷、短期/长期)。
dsh-memory 是按职责分的 —— 这是它最核心的设计:

L1 班长 跨工作区共享的长期知识 ← 只能模型主动写(所以有闸门) L2 课代表 这个工作区怎么运作 ← 只记稳定事实,不记进度 L3 组长 这个任务做到哪了 ← 插件自动维护 L4 工作日志 本轮原始轨迹 ← 全自动,可丢

为什么这个区分重要:它划出了唯一真正需要跨工作区共享的那一层(L1)。
其他方案常见的失败模式是"什么都在一个文件里",于是:
- 项目进度和用户偏好混在一起 → 换项目时携带一堆无关信息
- 每条记忆都要判断"该不该全局共享" → 模型无从下手
- 没有一个层是"共同的大脑" → 换个项目就重新认识你

dsh-memory 明确:L2 记「这个工作区怎么运作」,L3 记「这个任务做到哪了」, L1 记「关于用户和可复用的知识」,L4 自动记录。 每个文件都只回答一个问题,所以每层都能保持精简。

差异二:为「跨工作区共享」加了强制机制

这是 dsh-memory 独有的。调研中我发现同类方案的共同盲点: 它们都假设模型会自觉把经验写进长期库 —— 而实测中模型几乎不会。

真实的失败链条是这样的:

模型一路更新任务进度(那是 L3,自动的) ↓ 从不回头沉淀"可复用的结论" ↓ 任务完成、归档 ↓ 经验困在本工作区的 archive/ 里 ↓ 换个项目 → 完全看不到,下次重新踩坑 dsh-memory 用两道机制封住这个漏洞:

| 机制 | 时机 | 行为 |
| 归档闸门 | 调用 archive_task 时 | 本任务从未写过 L1 → 拒绝归档,要求先判断一次(可用 skipGlobalCheck: true 明确跳过) |
| L1 轮询 | 每 4 轮(可配) | 仍未写过 L1 → 提醒一次,并说明「这是唯一跨工作区共享的一层」 |

两者都有护栏(已写过就不提醒 / 同轮只提醒一次 / 走冷却期),不会变成骚扰。
效果是把「经验沉淀」从靠自觉变成流程必经点。

同类方案里,只有少数提到了「定期整理记忆」(如 agent-memory 的 sleep-time Manage 层、memory-toolkit 的 handoff),但它们都是建议,不是闸门。

差异三:按「token 性价比」分层,而不是全量注入

CLAUDE.md 那类方案是每次全会话注入。文件一长,成本线性上涨,而且「注入得越多 ≠ 效果越好」。

dsh-memory 的分层预算:

| 层 | 注入什么 | 上限 |
| L1 | 只给入口指针 + 10 条画像 + 读取指南 | 1.4 KB |
| L2 | 本工作区速览(定位/规范),详述按需读 | 2.2 KB |
| L3 | 任务目标 + 验收 + 最近进度 | 1.6 KB |
| L4 | 完全不注入(需要时用工具读) | 0 |

总计约 6 KB ≈ 1500–2000 token,而且是「索引 + 按需检索」而不是全量。

研究依据:
- Chroma《Context Rot》(2025) —— 18 个模型实测,~300 token 的聚焦输入优于 ~113k 全量输入;原因是全量迫使模型同时做检索与推理
- 《Lost in the Middle》(TACL 2023) —— 相关信息放在上下文开头或结尾时召回率最高,放中间显著下降 → 所以目标锚点插在消息靠前位置

差异四:零依赖、零进程、纯 Markdown

| | dsh-memory | 向量库方案 | 独立守护进程方案 |
| 运行时依赖 | 0(只用 Node 内置模块) | 向量库 + embedding | 常驻服务 |
| 需要的服务 | 无 | 需要 API key 或本地模型 | 需要启动/保活 |
| 数据形态 | 纯 Markdown | SQLite / 向量索引 | 数据库 |
| 可读性 | 人直接读 | 需要工具查询 | 需要工具查询 |
| 卸载后数据 | 照样能用 | 需要导出 | 需要导出 |

这不是「功能更少所以更简单」—— 而是刻意的取舍:记忆是你要保留十年的东西,它不应该依赖任何会过期的基础设施。 详见第十六节。

2.3 一张表说清差异

| 能力 | CLAUDE.md 式 | 会话记忆插件 | 向量库方案 | dsh-memory |
| 自动读取(无需手动唤起) | ✅ 全量注入 | ⚠️ 部分 | ✅ | ✅ 索引 + 按需 |
| 自动写入 | ❌ 手动 | ⚠️ 会话级 | ✅ | ✅ 三层自动 + 一层闸门 |
| 跨工作区共享 | ⚠️ 手动同步 | ❌ 多数不管 | ✅ | ✅ 带强制机制 |
| 长任务防遗忘 | ⚠️ 靠文件 | ⚠️ 会话级 | ❌ 不解决 | ✅ 四重保险 |
| 归档 / 任务生命周期 | ❌ | ⚠️ 部分 | ❌ | ✅ |
| 跨工作区审计 | ❌ | ❌ | ❌ | ✅ |
| 隐私红线可执行 | ❌ | ❌ | ❌ | ✅ |
| 零依赖 | ✅ | ✅ | ❌ | ✅ |
| 数据是纯文本 | ✅ | ✅ | ❌ | ✅ |
| 自带测试 | ❌ | ⚠️ | ✅ | ✅ 13 套 / 450+ 断言 |

2.4 什么情况下不该用它

诚实地说,它不是万能的:

- 你的记忆量极大(几万条以上) → 关键词检索会不够用,该上向量库。
dsh-memory 的 memory_search 是逐行打分,记忆库在几百到几千条时最合适。
- 你要多台机器同步 → 本插件不管同步。把记忆库放进 Git / 网盘目录是可行的(它就是一堆 Markdown),但合并不是自动的。
- 你用的不是 DSH → 目前只支持 DSH。核心逻辑(store.js / brief.js / audit.js)与平台无关,移植到 Claude Code / Codex 的 hooks 模型理论可行,但目前没做。

三、班级分工:四层各管什么

用「班级」来理解这套设计:

┌──────────────────────────────────────────┐
│ 你 = 班主任 │ │ 偶尔检查:干得怎么样?按时归档了吗? │ │ 有没有写错文件? │ └────────────────────┬─────────────────────┘ │ memory_audit(一键总览) ┌─────────────────────────┴──────────────────────────┐ │ │ ┌──▼───────────────┐ ┌────────────────┐ ┌──────────────▼──┐ │ L2 课代表 │ │ L3 小组组长 │ │ L1 班长 │ │ 工作区记忆端口 │ │ 任务档案 │ │ 全局记忆库 │ │ │ │ │ │ │ │ 这个工作区是做什么 │ │ 当前任务目标 │ │ 关于你这个人的 │ │ 要守哪些规矩 │ │ 验收标准 │ │ 一切:身份/偏好/ │ │ 踩过哪些坑 │ │ 进度时间线 │ │ 技术栈/目标/雷区 │ │ 有哪些里程碑 │ │ 关键约束 │ │ │ │ │ │ │ │ ★ 所有工作区共享 │ │ 每工作区一份 │ │ 每任务一份 │ │ 全局唯一一份 │ └──────────────────┘ └────────────────┘ └──────────────────┘ │ ┌────────▼─────────┐ │ L4 个人工作日志 │ │ 会话轨迹 │ │ 本轮做了啥/啥成果 │ │ 可丢,不影响其它层 │ └──────────────────┘

职责边界不能串岗

| 层 | 角色 | 管什么 | 不管什么 |
| L1 | 班长 | 关于你这个人的长期信息,跨工作区共享 | 某个具体项目的进度 |
| L2 | 课代表 | 本工作区的稳定事实:定位、规范、踩坑、里程碑 | 任务进度(那是组长的活) |
| L3 | 小组组长 | 当前任务的目标、验收、进度、约束 | 跨任务的长期结论 |
| L4 | 工作日志 | 本轮的原始轨迹,供回溯 | 一切需要长期保留的东西 |

为什么强调这个:本项目开发早期,L2 里有一节叫「进行中与已完成的任务」,和 L3 的职责重叠 —— 同一个任务状态写在两个文件里,一旦不同步就互相矛盾,归档时也不知道该以哪个为准。现在明确:进度只写 L3。
这个教训也写进了测试里。

各层落在哪里

L1 <memoryRoot>\ ← 默认 <DSH_HOME>\memory MEMORY.md ← 入口索引(画像/读取指南/条目统计) 00-隐私红线.md ← 写入前的硬性红线 01..NN-.md ← 分类文件(可自由增删) 12-记忆维护日志.md ← 变更流水

L2 <工作区>\.dsh\memory\WORKSPACE.md ← 本工作区专属 L3 <工作区>\.dsh\memory\ACTIVE.md ← 当前任务 <工作区>\.dsh\memory\archive\ ← 已完成任务 L4 <工作区>\.dsh\memory\sessions\ ← 会话轨迹(默认留最近 40 份)

四、自动化发生在什么时候

| 时机 | 触发点 | 做什么 | 花 token 吗 |
| 会话开始 | agent/session-start | 建立工作区端口;交代四项职责 | 否 |
| 每一步之前 | agent/pre-step | 注入记忆简报 / 目标锚点 | 注入占上下文 |
| 每轮结束 | agent/turn-stopping | 采集进度、写轨迹、条件式提醒、L1 轮询 | 采集零 token |
| 上下文压缩后 | compaction/end | 标记下一轮立即重述目标 | 否 |
| 归档时 | memory_write action:archive_task | 归档闸门:没沉淀过 L1 就拦下 | 否 |

会话开始时会明确交代「四项职责」

每次新对话/新任务,插件都会在简报里逐项告诉模型它要维护哪四份东西,以及哪些是自动的、哪些必须它主动写:

你的四项职责(要维护的四份东西)

① L1 班长(全局库)—— 你主动写关于用户本人的长期信息、跨项目可复用的结论 → target:"global" + category ⚠️ 这是唯一跨工作区共享的一层;你不写,别的项目就永远看不到。

② L2 课代表(本工作区)—— 你主动写本工作区的稳定事实:做什么的、守什么规矩、踩过什么坑、有什么里程碑注意:不要把任务进度写这里,那是 L3 的事。

③ L3 小组组长(当前任务)—— 插件自动维护,你只在关键处补插件每轮自动记进度、压缩后自动重述目标;你负责设目标/记决定/归档。

④ L4 工作日志(会话轨迹)—— 全自动,你无需管

目标怎么保证不被忘记(四重保险)

1. 逐字保留 —— 会话里第一条实质用户消息(非寒暄)被原样写进 ACTIVE.md,之后只增不改
2. 压缩感知 —— 上下文被压缩后,下一轮立刻重新注入原始目标
3. 周期重述 —— 默认每 10 轮重述一次,对抗长对话中的目标漂移
4. 位置优先 —— 锚点插在消息靠前位置(研究显示开头/结尾的召回率最高)

连续做多个任务也没问题:每次归档后,下一个任务会从归档点之后重新寻找自己的目标,不会张冠李戴。

两道防漏机制:归档闸门 + L1 轮询

L2/L3/L4 都由插件自动维护,只有 L1 必须靠模型主动写 —— 而它恰恰是 唯一跨工作区共享的一层。

| 机制 | 时机 | 行为 |
| 归档闸门 | 调用 archive_task 时 | 若本任务从未写过 L1 → 拒绝归档,要求先判断一次;确实没内容可带 skipGlobalCheck: true 跳过 |
| L1 轮询 | 每 4 轮(可配) | 若本任务仍未写过 L1 → 提醒一次,并说明"跨工作区共享"这件事 |

archiveGate: true # 归档闸门 l1PollEveryTurns: 4 # 每 N 轮检查一次;0 = 关闭

实现上有坑:闸门拒绝后,那次 archive_task 调用不能被当成"任务已归档" 来推进任务边界 —— 否则前面写过的 L1 会被划到"上一个任务",闸门就会再次拒绝,陷入死循环。所以成功的归档会带一个机器可读标记,边界只在看到它时才推进。
这条有专门的回归测试(见第十三节事故 #8)。

四·补、L1 记忆库到底落在哪?(新用户必读)

这个目录由插件自动决定,你什么都不用配。

规则只有一条:跟着 DSH 主目录走。

<DSH_HOME>/memory

DSH_HOME 的取值顺序:

| 情况 | L1 落点 | 说明 |
| 设了环境变量 DSH_HOME | <DSH_HOME>/memory | DSH 装在非默认位置时是这种 |
| 没设(绝大多数人) | C:\Users\<你的用户名>\.dsh\memory | Windows 默认;macOS/Linux 是 ~/.dsh/memory |
| 两个环境变量都没有(极端) | <当前工作目录>/memory | 仍能工作,不会崩 |

举例:
- 小明 DSH 装在默认位置 → C:\Users\小明\.dsh\memory
- 小红把 DSH 装到 D 盘 → D:\DSH\.dsh\memory(跟随 DSH_HOME)

目录不存在?自动建

首次运行时如果这个目录不存在,插件会自动创建一套最小骨架(7 个文件):

<DSH_HOME>\memory\
MEMORY.md ← 入口索引(含填写指引) 00-隐私红线.md ← 写入前的硬性红线 01-身份与基本档案.md ← 建议记录:称呼、职业定位、地域…
02-沟通与协作偏好.md ← 建议记录:回答风格、输出格式…
03-技术栈与工具.md ← 建议记录:硬件、软件、踩坑结论 04-工作与项目.md ← 建议记录:行业、项目、工作目标 12-记忆维护日志.md ← 变更流水(自动追加)

每个文件都带「建议记录」指引,不是丢给你一个空文件。
已存在的文件绝不覆盖 —— 你已有的记忆库会被原样尊重。

想放别处?也可以

比如放进 Obsidian 库、或放到同步盘:

在 profile 的 cordis.patch.yml 里
- id: memory
name: 'dsh-memory'
config:
memoryRoot: 'D:\Obsidian\vault\我的记忆'

memoryRoot 一旦显式配置就完全覆盖自动推导。留空或纯空白视为"未配置"。

怎么确认我的库在哪?

看插件报告的路径 Invoke-RestMethod http://127.0.0.1:19387/memory/ping

或看四层状态 Invoke-RestMethod "http://127.0.0.1:19387/memory/status?cwd=E:\任意目录"

日常也可以直接问 AI:「我的记忆库在哪?」 —— 它会用 memory_read target:"list" 把各层路径列出来。

以上四种场景(默认位置 / 自定义 DSH_HOME / 都未设 / 显式指定)都有测试覆盖,见 tests/l1-location.mjs。

五、省 token 的六条设计

| 手段 | 说明 |
| 只注入索引 | L1 不注入全文,只给入口指针 + 10 条画像 + 读取指南 |
| 分层预算 | 每层独立字节上限,超限即截断并注明"按需再读" |
| 零 token 采集 | 轮次/工具/文件改动直接读会话事件,不调用模型 |
| 零 token 压缩感知 | 从压缩事件得知,不需要模型汇报 |
| 不注入子代理 | 子代理短命且任务聚焦,注入是纯浪费 |
| 提醒有冷却 | 唯一额外花 token 的机制,限每轮一次 + 每 N 轮一次 |

注入总量上限 6000 字节(约 1500–2000 token),可配。

关于那个提醒

它是唯一会额外花 token 的机制(一次提醒让模型多跑一步)。
即使关掉它,三重保障仍在:系统提示词指引 + 锚点末尾提醒 + 机械进度采集。

steerOnHarvest: false # 极致省 token l1PollEveryTurns: 0 # 也关掉 L1 轮询

六、安装

前置条件

- DSH(DeepSeek Harness)已安装并至少启动过一次
- Node.js(DSH 自带,通常无需另装)

步骤

git clone https://github.com/jiachenleo9-create/dsh-memory.git
cd dsh-memory

先看会改什么(推荐) powershell -ExecutionPolicy Bypass -File .\install.ps1 -DryRun

正式安装(需要写入 DSH 安装目录的权限,建议管理员身份) powershell -ExecutionPolicy Bypass -File .\install.ps1

安装器会部署三个位置(缺一不可):

| # | 位置 | 作用 |
| 1 | <profile>\plugins\dsh-memory | 源副本(便于阅读与再安装) |
| 2 | <profile>\node_modules\dsh-memory | 实际被加载的模块 |
| 3 | <profile>\package.json | 登记 dependencies + dsh.profile.bundles |

只做第 1 步不会加载 —— 这是 DSH 的插件解析机制决定的。
覆盖前自动备份,备份名带时间戳。

装完必须重启 DSH

插件只在启动时加载,没有热重载。改代码后同样要重启。

验证

1. 确认已加载 Invoke-RestMethod http://127.0.0.1:19387/memory/ping

2. 四层读写自检(应全部通过) Invoke-RestMethod "http://127.0.0.1:19387/memory/selftest?cwd=E:\你的项目"

3. 预览即将注入的记忆简报 Invoke-RestMethod "http://127.0.0.1:19387/memory/brief?cwd=E:\你的项目" 19387 是 DSH Web GUI 的默认端口,以你实际的为准。

首次运行会自动建库

如果 memoryRoot 指向的目录不存在,插件会自动创建一套最小骨架:入口索引 + 隐私红线 + 4 个常用分类 + 维护日志,每个文件都带填写指引。

已存在的文件绝不覆盖 —— 你已有的记忆库会被原样尊重。

七、使用:你只需要做三件事

1. 正常干活,什么都不用管

- 开新会话 → 自动注入记忆
- 干活 → 自动记进度
- 长任务 → 自动重述目标
- 换工作区 → 自动建端口

2. 偶尔说一句「记住这个」

AI 会自己判断该写哪一层;你也可以直接说:

「记住:我偏好用内置 Python,不要装系统 Python。」
→ 写进 L1

「这个项目以后都优先用 TypeScript。」
→ 写进 L2 的 行为规范与约定

3. 任务做完说一句「归档」

「这个任务完成了,归档吧。」
→ 先触发闸门(判断有没有值得进 L1 的结论),然后归档到 archive/

八、班主任审计

一条命令看全部工作区。

人看的报告(Markdown) Invoke-RestMethod "http://127.0.0.1:19387/memory/audit?cwd=E:\你的项目"

或者在对话里直接问 AI:「最近各个工作区干得怎么样?有没有按时归档?」
→ AI 会调用 memory_audit 工具,返回同样的报告

报告长这样:

记忆系统审计报告

生成时间:2026/10/16 02:57:50 全局库:E:\my-memory 工作区端口:7 个 | 发现问题:2 项

一、总览
| 工作区 | 任务状态 | 当前任务 | 归档数 | 轨迹数 | 最近活动 | 问题 |
| my-app | 进行中 | 实现登录模块… | 3 | 12 | 0 天前 | ✅ |
| comfyui-lab | 空闲 | — | 5 | 8 | 2 天前 | ⚠️ 1 |
| legacy-tool | 进行中 | 重构数据层… | 1 | 4 | 45 天前 | 🟡 2 |

二、全局记忆库(班长)
- 索引更新:2026-10-16
- 声明条目:184 | 实际统计:184 | ✅ 一致
| 分类文件 | 条目(声明/实际) | 更新 | 大小 |
...

三、发现的问题全局库
- 🟡 count-mismatch — 03-.md 声明 5 条,实际 6 条——可能有写入绕过了 memory_write legacy-tool
- 🟡 stale-task — 任务「…」已 45 天没有更新,可能忘了归档

四、最近归档 my-app
- 2026-10-15-实现登录模块.md(0 天前)
- 目标:…

它会检查什么

| 检查 | 说明 |
| 按时归档 | 有进行中的任务但很久没更新 → 提醒可能忘了归档 |
| 写错文件 | 分类文件声明的条目数与实际不符 → 有写入绕过工具层 |
| 索引一致 | MEMORY.md 声明的总数与实际统计是否一致 |
| 条目落点 | 有没有条目掉在 ## 条目 小节之外 |
| 归档命名 | 文件名是否符合 YYYY-MM-DD-标题.md |
| 状态自洽 | 状态说"进行中"但目标为空 → 数据不一致 |
| 脱敏残留 | 有没有【已脱敏】占位符(可能是误报,需人工核对) |

审计是纯只读的 —— 不会修改任何记忆文件,你随时可以跑。

全部诊断端点

| 端点 | 用途 |
| /memory/ping | 确认插件已加载、回显全部开关与预算 |
| /memory/brief?cwd= | 预览将注入的记忆简报(含字节数) |
| /memory/anchor?cwd= | 查看当前目标锚点长什么样 |
| /memory/status?cwd= | 单个工作区的四层状态与任务卡片 |
| /memory/audit | 跨工作区审计报告(?format=json 给程序用) |
| /memory/selftest?cwd= | 四层读写自检 |
| /memory/rules | 导出全部隐私规则(机器可读) |
| /memory/seed?cwd= | 手动为某工作区建立端口 |

九、配置

在 profile 的 cordis.patch.yml 里加一行,覆盖任意字段:

- id: memory
name: 'dsh-memory'
config:
---- 路径 ---- memoryRoot: 'D:\我的记忆库' # 留空 → <DSH_HOME>/memory(不存在则自动建骨架) workspaceDir: '.dsh/memory' # L2/L3 在工作区里的位置 sessionRoot: '' # 留空自动用 <DSH_HOME>/sessions

---- 自动读取 ---- autoRead: true # 会话开始注入简报 injectIntoSubagents: false # 不向子代理注入(省 token)

---- 目标锚定 ---- autoAnchor: true anchorEveryTurns: 10 # 每 N 轮重述;0 = 只在压缩后

---- 自动沉淀 ---- autoHarvest: true # 每轮机械采集(零 token) steerOnHarvest: true # 条件式沉淀提醒(唯一额外花 token 的项) steerCooldownTurns: 6 # 两次提醒最小间隔 steerMinToolCalls: 3 # 触发提醒所需的最少工具调用 harvestMinToolCalls: 2 # 记进度所需的最少工具调用

---- L1 保障 ---- archiveGate: true # 归档闸门 l1PollEveryTurns: 4 # 每 N 轮检查一次;0 = 关闭

---- 预算(字节)---- maxInjectBytes: 6000 # 单次注入硬上限 portInlineBytes: 2200 # L2 速览 globalInlineBytes: 1400 # L1 索引 anchorInlineBytes: 1600 # L3 锚点

---- 其它 ---- privacyGuard: true # 隐私红线自检(强烈建议开启) tools: true # 注册 memory_* 工具 diagnostics: true # 注册 /memory/* 路由 keepSessionLogs: 40 # 会话轨迹保留份数 persistTrajectory: true

自定义分类文件

想加自己的分类(比如「健身记录」):

1. 在 memoryRoot 下新建 15-健身记录.md(照抄任一分类文件的结构即可)
2. 在 MEMORY.md 的索引表里加一行
3. 在 lib/tools.js 的 GLOBAL_CATEGORIES 里加映射:
fitness: { file: '15-健身记录.md', label: '健身记录' },

这样模型就能用 memory_write target:"global" category:"fitness" 写进去。

十、模型可用的工具

| 工具 | 用途 | 何时用 |
| memory_read | 按需读 global/port/task/category/list,支持关键词过滤 | 需要更多细节时(不要读整个库) |
| memory_search | 跨全部记忆文件检索,返回 [文件:行号] 内容 | 不确定记在哪个文件时 |
| memory_write | 唯一写入口,内置隐私自检 | 得出"下次仍会用到的"结论时 |
| memory_audit | 跨工作区审计报告 | 用户问"最近工作怎么样"时 |

memory_write 的用法:

target: "global" + category → 关于用户的长期信息 target: "port" + section → 本工作区的稳定事实/规范 target: "pitfall" → 本工作区的踩坑教训 target: "task" + action → set_goal / progress / decision / set_acceptance / archive_task

十一、消息来源格式(DSH 插件开发者必读)

这一节是给写 DSH 插件的人看的。我踩了这个坑,希望你别再踩。
如果你只是使用者,可以跳过。

DSH 使用 V4 会话格式。写路径的准入检查 assertV4MessageSources 要求消息的 source.kind 是生产者自有 kind,并显式拒绝 kind === 'plugin':

format v4 message requires a producer-owned source kind

命中时的表现是整轮失败(界面显示「本轮运行失败」,错误码 UNKNOWN)。

| 写法 | 结果 |
| { kind: 'plugin', plugin: '任意名' } | ⛔ 已退役,写路径被拒,整轮失败 |
| { kind: 'plugin:<插件名>' } | ✅ 命名空间形式(本插件采用) |
| { kind: '<自有生产者名>' } | ✅ 如 agent-instructions |

最容易踩的坑:DSH 第一方包的源码里能看到
createUserMessage({ source: { kind: 'plugin', plugin: 'dsh-xxx' } }) 这种写法,
而且 producerKind() 里有一张白名单(含 agent-instructions、time-context、 goal 等 30 个名字)会把 plugin 映射成生产者 kind。

但那是「读取旧 V3 文件时的迁移逻辑」,不是写路径的豁免名单。 照抄第一方插件的写法,你的插件就会在注入消息时整轮失败。

// ✅ 正确 const SOURCE = { kind: 'plugin:dsh-memory' }
agent.inject(createUserMessage({ content: [...], source: SOURCE }))

本插件把这条规则固化成了回归测试(tests/source-format.mjs),另有一个 tests/audit-installed-plugins.mjs 可以扫描你已装的全部插件找同类问题。

十二、隐私红线

00-隐私红线.md 的规则已落成可执行代码(lib/privacy.js),写入前强制自检。

硬红线(不可绕过,命中即拒绝并脱敏)

身份证号、手机号、邮箱、银行卡号、API Key/Token/私钥、密钥赋值语句、内网 IP、门牌号、精确出生日期(仅在"出生"语境附近判定)、学号工号社保号。

软红线(默认整类不记录)

人际关系/家庭、医疗健康、生物特征、他人隐私、政治宗教性取向等敏感属性。

两个设计要点

1. 误报比漏报更危险。命中即脱敏的机制会让正常内容被替换成占位符,而用户和模型都无从察觉。真实事故:早期密钥规则的"两字母前缀 + 12 位以上" 把普通英文驼峰命名(skipGlobalCheck)误判成密钥,静默替换掉一句完整的技术说明。
现在收紧了形态约束(必须带分隔符且含数字),并列出被替换的具体片段,让误报可见、可纠正。

2. 脱敏后没有实质内容就拒绝写入,而不是往库里塞一句空话。

自定义规则

规则表在 lib/privacy.js 顶部的 PATTERNS(硬红线)与 SOFT_RULES(软红线)。
加一条硬红线: {
id: 'my-rule',
category: '凭证与密钥', note: '公司内部工单号', re: /TICKET-[0-9]{6}/g, }

/memory/rules 可以导出当前全部规则,便于核对。

十三、可靠性:14 套测试与 8 个真实事故

14 套测试(540+ 断言)

node tests\run-all.mjs # 全部

| 测试 | 守什么 |
| selftest.mjs | 存储层、解析、隐私、锚定、归档、检索、配置 |
| integration.mjs | 真实挂载 apply() 与全链路闭环 |
| schema-check.mjs | 工具定义通过 DSH 真实校验器 |
| source-format.mjs | V4 会话格式:消息来源必须合法 |
| late-mount.mjs | 插件延迟挂载时端口不漏建 |
| privacy-precision.mjs | 隐私自检双向精度:正常内容零误报 + 真实密钥全拦截 |
| duties-gate-poll.mjs | 四项职责 / 归档闸门 / L1 轮询 + 死循环回归 |
| tool-output-json.mjs | 工具返回值必须是无损 JSON |
| task-rotation.mjs | 连续多个任务每个都被锚定 |
| integrity.mjs | 条目落点、归档不覆盖、解析不截断、边界不误判 |
| l1-location.mjs | L1 库落点(四种环境)+ 自动建库 + 不覆盖已有内容 |
| audit.mjs | 审计发现全部工作区 + 精度 + 纯只读 |
| routes.mjs | 全部 HTTP 诊断端点 |
| loadtest.mjs | 从真实安装位置加载 |

开发中抓出并修复的 8 个真实事故

这些不是假想问题 —— 每一个都是先造成损害、后被发现的:

| # | 事故 | 后果 | 现在的防线 |
| 1 | 用退役的 {kind:'plugin'} 作消息来源 | 整轮失败(V4 格式拒绝) | source-format.mjs |
| 2 | 插件在会话开始后才挂载 | L2/L3 静默消失 | late-mount.mjs |
| 3 | 工具返回值带 undefined | 真实调用报 not lossless JSON | tool-output-json.mjs |
| 4 | 归档后下一个任务不再被锚定 | 长会话里 L3 彻底失效 | task-rotation.mjs |
| 5 | 新条目追加到文件末尾 | 23 条条目落进「备注」区 | integrity.mjs + 迁移脚本 |
| 6 | 同日同目标归档同名覆盖 | 归档文件静默丢失 | integrity.mjs |
| 7 | 隐私规则误报普通英文词 | 正常内容被静默脱敏 | privacy-precision.mjs |
| 8 | 闸门拒绝归档却推进了任务边界 | 无限拒绝,永远归档不了 | duties-gate-poll.mjs |

一条经验

mock 测试全绿 ≠ 真实可用。

上面 8 个里有一半(1、3、7)只有走真实调用路径才会暴露;另一些(5、6)是真实数据已经被改坏了才发现。

所以每修一个,都补一个能复现该事故的回归测试,并且验证过「回退修复后测试确实会变红」 —— 测试本身也要被测试。

十四、文件结构

dsh-memory/
├── package.json 插件清单 ├── cordis.patch.yml bundle 层:insert 一行即可挂载 ├── install.ps1 安装/卸载脚本(支持 -DryRun) ├── README.md 本文档 ├── LICENSE MIT ├── docs/ │ └── architecture.png 架构总览图(README 顶部引用) ├── lib/ │ ├── index.js 插件入口:事件接线、注入编排、诊断路由 │ ├── config.js 配置模式与补全(默认路径保持中立) │ ├── store.js 四层存储:原子写、字节安全截断、小节操作、 │ │ 索引同步、新库引导 │ ├── brief.js 简报与目标锚点组装(决定「注入什么」) │ ├── harvest.js 会话轨迹采集、任务锚定、L1 写入检测 │ ├── audit.js 跨工作区审计(班主任视角) │ ├── privacy.js 隐私红线自检(可执行的红线清单) │ ├── source.js 消息来源判定(V4 格式合规) │ └── tools.js memory_read / search / write / audit ├── tools/ │ └── migrate-misplaced-entries.mjs 一次性修复:搬回错位的条目 └── tests/ 13 套测试

开发

node tests\run-all.mjs # 全部测试
node tests\integrity.mjs # 单个测试

改完代码后需要重新安装并重启 DSH:

powershell -ExecutionPolicy Bypass -File .\install.ps1

十五、常见问题

Q:装完没反应? A:插件只在 DSH 启动时加载。先重启 DSH,然后跑 /memory/ping 确认。

Q:/memory/ping 404? A:说明插件没加载。检查三处部署是否都在(plugins/、node_modules/、 package.json 的 bundles 列表),详见第六节。

Q:记忆库会在哪里? A:默认 <DSH_HOME>/memory(Windows 通常是 C:\Users\<你>\.dsh\memory)。
想在别处就在配置里写 memoryRoot。

Q:会不会泄露隐私给模型? A:注入的内容只有索引与摘要,且写入前会过隐私红线自检。
但请注意:注入的内容会进入模型上下文,这是「让 AI 懂你」的必要代价。
敏感信息的设计原则是「不落盘」,而不是「落盘了但不上传」。

Q:能跨机器同步吗? A:插件不管同步。但记忆库就是一堆 Markdown,放进 Git / 网盘目录即可,注意多机同时编辑可能会冲突。

Q:会不会很费 token? A:注入上限 6000 字节(约 1500–2000 token),只在会话开始/压缩后/每 N 轮。
机械采集零 token。唯一额外花 token 的是沉淀提醒,可以用 steerOnHarvest: false + l1PollEveryTurns: 0 完全关掉。

Q:支持多语言吗? A:界面文案是中文,但记忆内容与代码注释不限定语言。
中文字符的字节计算与截断已专门处理(不会切断多字节字符)。

十六、设计取舍

写这个插件时做过几个刻意的选择,这里说明理由:

为什么不用向量库?

记忆是要保留十年的东西,它不应该依赖任何会过期的基础设施。

向量库能提供更好的语义检索,代价是:需要 embedding 服务或本地模型、数据变成不透明的二进制索引、卸载后难以迁移、调试时看不到「它到底记住了什么」。

本项目选择关键词逐行打分(memory_search)。记忆库在几百到几千条时,关键词检索的实际效果足够好,而且:你随时可以用编辑器打开看、用 grep 搜、用 Git 做版本管理。如果哪天你的库大到关键词不够用,store.search() 是唯一需要替换的方法,其余部分不受影响。

为什么坚持纯 Markdown?

同上。另外还有一个理由:可审计性。
当 AI 说「我记得你说过 X」时,你应该能打开文件确认它记的到底是不是 X。
向量库里你做不到这件事。

为什么注入这么少?

因为注入得多 ≠ 效果好。研究结论(第五节)显示聚焦的小输入优于全量注入。
更重要的是:全量注入会鼓励「什么都往里塞」,最后变成一个没人维护的巨型文件 ——这是 CLAUDE.md 类方案最常见的失败模式。

为什么要做闸门这么一个「会拦人」的机制?

因为实测发现模型不会自觉沉淀跨工作区经验。
这不是模型的错 —— 它的注意力在「完成当前任务」上,而「把经验写到另一个目录」是一件没有即时反馈的事。

闸门把这个动作变成流程必经点,并且给了体面的跳过路径 (skipGlobalCheck: true),避免「确实没内容」时被卡住。

为什么提示词用中文?

因为开发者的母语是中文,而提示词是要被维护的。
让维护者能一眼看懂、随时改,比「看起来更国际化」更重要。
代码注释同样。

许可

MIT — 随便用,包括商用。

致谢

- 架构灵感来自 Claude Code 的分层记忆设计 (managed / user / project / local),但把「全量注入」换成了「索引 + 按需检索」
- token 效率的设计参考了 Chroma 的 Context Rot 研究与 Lost in the Middle
- 同类项目的思路借鉴(并刻意做出差异):mem0、 Letta/MemGPT、 tigerless-labs/agent-memory、 Cline Memory Bank
预览分享卡片长什么样 ↓jiachenleo9-create/dsh-memory
分享 · DeepSeek Harness Hub
jiachenleo9-create/dsh-memory

自动记住你的偏好与目标,跨会话不再失忆

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部