@ruqinhu/dsh-memory
English | 中文
给 DeepSeek Harness 提供字符上限可配置的长期记忆。
DSH 本身没有持久记忆包,会话之间会丢规则。本插件维护两份以 § 分隔的文档,并在每次装配时作为动态上下文注入。
为什么不用截断
截断是记忆文件悄悄出错的典型方式:写入看起来成功了,下一次请求却少了某条约束。超上限的写入会被拒绝,逼出一次真正的压缩。
参照场景:迁移前 Hermes 的 MEMORY.md 已涨到 3,687 字符,上限 2,200(超 68%);USER.md 涨到 2,748,上限 1,375(超 100%)。
安装
dsh plugin add @ruqinhu/dsh-memory
配置
| 键 | 默认 | 含义 |
|---|---|---|
memoryCap |
2200 |
MEMORY.md 字符上限 |
userCap |
1375 |
USER.md 字符上限 |
enableInjection |
true |
是否作为动态上下文注入 |
backupKeep |
12 |
保留的备份目录数 |
memoryDir |
~/.dsh/memory |
文档与备份目录 |
enableRecall |
false |
是否注册 memory_recall |
recallBudgetChars |
1500 |
单次召回注入的字符上限 |
上限做成配置项,是为了迁移期先把上限调高、压缩完再调回来。
注入策略
文档较小时整体注入。合计超过 6,000 字符后改为注入条目索引并提示调用 memory_search,避免记忆膨胀后静默挤占工作上下文。
检索与召回
分词对中文按二元组切分(止损怎么设 → 止损/损怎/么设)。这不是细节:整段保留时,查询必须恰好是条目的子串才能命中,于是 止损怎么设 对条目 止损 2.96/走弱 3.02 得 0 分,召回静默返回空 —— 和「记忆里确实没有相关内容」完全无法区分,正是这条路径曾让检索形同虚设。单字仍不切分(跌 保留),否则几乎匹配每一条。
memory_search 返回带分数与来源的条目列表,给模型自己看。
memory_recall(默认关闭)返回已排版好的上下文块加一行指示(🧠 召回 N 条记忆),按分数从高到低填充,直到字符预算耗尽;放不下的条目跳过而非截断 —— 半条规则读起来像完整的一条,比没有更糟。
为什么召回默认关闭:文档还在 6,000 字符以内时,整份记忆本来就常驻上下文,召回只会再注入一份。它要等文档涨过内联预算、注入转为索引之后才有价值。接口先定下来,是为了那时不用改结构。
指示行照搬 Hermes 的 describe_recall 理由:没有确定性指示时,「模型选择沉默」和「召回坏了」无法区分。这个部署在投递侧已经吃过一次同样的亏。
工具
| 工具 | 用途 |
|---|---|
memory_read |
读文档,含用量与条目数 |
memory_search |
关键词检索,按得分返回 |
memory_recall |
检索并排版成可直接使用的上下文块(enableRecall) |
memory_write |
整体替换(超上限拒绝) |
memory_append |
追加一条(超上限拒绝) |
memory_replace |
精确替换子串 |
memory_maintenance |
备份、轮转、报告用量 |
memory_replace 是压缩用的原语:原地改写过期规则,而不是重写整份文档。
每周维护
参考部署每周六跑一次压缩。把定时任务指向 memory_maintenance,再让 agent 用 memory_replace 合并或删除过期条目,直到用量回到上限内。
许可
MIT