drscrewdriver/dsh-prime-memory

dsh-prime-memory

分层记忆插件,面向 Agent 暴露 10 个工具:高权限写入(memory_add / memory_delete / memory_import)、反刍控制(memory_ruminate / _cancel / _status)与记忆图谱(memory_search_graph / memory_expand_graph_node),底层为 L0–L3 蒸馏管线,并在每步模型调用前召回注入相关记忆。

未分類deepseek-harnessdshdsh-bundle

dsh-prime-memory

DeepSeek Harness 的分层蒸馏记忆插件:对话在后台自动完成 L0 捕获 → L1 原子记忆 → L2 场景整合 → L3 画像蒸馏,模型每一步前自动把相关记忆注入上下文。

English · 最新发行版 · 反馈问题

🌐 语言 / Language

  • 中文 README
  • English README
  • 日本語 README
  • 한국어 README
  • README en français
  • README auf Deutsch
  • README in italiano
  • README на русском
  • README en español
  • 安装指南(中文)
  • Installation guide (English)
  • 日本語インストールガイド
  • 한국어 설치 안내
  • Guide d'installation (français)
  • Installationsanleitung (Deutsch)
  • Guida all'installazione (Italiano)
  • Руководство по установке (Русский)
  • Guía de instalación (Español)
  • 更新日志(中文)
  • Changelog (English)
  • 日本語 changelog
  • 한국어 changelog
  • Changelog en français
  • Changelog auf Deutsch
  • Changelog in italiano
  • Changelog на русском
  • Changelog en español

DSH 版本兼容矩阵

DSH 版本 · settings 注册 API · 状态 0.1.1-rc.2 · settings.register()(live scope) · ✅ 已验证 0.1.2-rc.1 · settings.register()(回退可用) · ⚠️ 按框架文档推断,未实测 0.1.3-rc.1 · settings.register()(回退可用) · ⚠️ 未实测(0.1.3+ 命名空间已改字符串,本插件已兼容) 0.1.5-rc.2 · settings.register()(回退可用) · ⚠️ 未实测;Session V3 surface 语义与输入栏/设置槽位待回归 0.2.0-rc.1 · settings.register()(live scope) · ✅ 本次适配线(事件接线 agent/session-start → agent/created)

兼容机制:settings 注册走运行时三分支(register → installSection 桥接 → 恒开降级),
详见 CHANGELOG.md 的 0.11.0 条目。dsh.plugin.json 声明
engines.dsh 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc)。

快速开始

需要 Node ≥ 22.16。两种调用方式任选(npx 前缀可替换下面任何 dsh 命令):

# 方式一:npx 直接跑官方 CLI(无需预装 dsh;可 pin 版本,如 dsh-prime-memory@0.8.4)
npx -y @deepseek-ai/dsh plugin --profile web add dsh-prime-memory

# 方式二:已装 dsh CLI(dsh 是 pnpm 转发器,未装 pnpm 时先 npm i -g pnpm)
dsh plugin --profile web add dsh-prime-memory

# 包源备选:GitHub 仓库 / 本地路径(开发调试,link: 指向仓库,npm run build + 重启 dsh 即生效)
dsh plugin --profile web add https://github.com/drscrewdriver/dsh-prime-memory
dsh plugin --profile web add /path/to/dsh-prime-memory

让 Agent 安装(推荐)

如果当前 Agent 可以执行终端命令,把下面这段话完整发送给它:

请为 DeepSeek Harness 的 web Profile 安装 dsh-prime-memory 插件。

只执行下面两条命令,不要修改其他 Profile:
dsh plugin --profile web add dsh-prime-memory
dsh --profile web --dump-config

确认输出中出现 dsh-prime-memory 后告诉我安装结果。
不要替我关闭或重启正在运行的 DSH;安装完成后提醒我手动重启 DSH Web Host。

Agent 应当返回安装结果,并明确告诉你配置中是否已经出现 dsh-prime-memory。

本包声明了 dsh.bundle 组合包层(cordis.patch.yml),安装后会自动挂载插件行—— 不需要再手改 $DSH_HOME/profiles/web/cordis.patch.yml。然后重启 DeepSeek Harness, 验证:~/.dsh/memory/ 下出现 conversations/ records/ scenes/ 目录和 memory.db 即插件 apply 成功;设置页出现"记忆"页面、输入栏出现档位 pill 即 client 半边就绪。

卸载:dsh plugin --profile web remove dsh-prime-memory + 重启。数据保留在 ~/.dsh/memory/,不需要时手动删除整个目录即可。

从源码开发

git clone https://github.com/drscrewdriver/dsh-prime-memory
cd dsh-prime-memory
npm install && npm run build
dsh plugin --profile web add .        # link: 安装,改代码后 npm run build + 重启 dsh 即生效
npm run smoke                         # 冒烟测试(先重编:见下方命令)
npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop

运行时数据流

插件挂在 dsh 原生事件上(session/event 捕获、agent/pre-step 注入),蒸馏调用复用宿主 ctx.llm。召回以消息侧注入呈现:相关记忆作为一条合成消息排在用户新消息之前,会话流里显示为"上下文注入 · memory"行(点开看命中内容)——用户能直接看到"记忆生效了";注入内容有长度预算与时间预算,超限截断/超时跳过,绝不拖慢对话。同会话去重:已注入过的记忆不再重复注入(模型上下文里已经有了,追问同类问题时省 token);上下文被 /compact 压缩或清空时自动重置,记忆可重新注入;被更新的记忆(内容变化换新 id)不受旧压制。时效加权:召回排序按 相关度 × max(0.5, 0.5^(距上次更新天数/30)) 软加权——相关度相近的候选之间新鲜记忆优先(名额自然轮转),相关度足够高的老记忆照常召回(地板保证最多损失一半排序分,长期事实不沉底);recall.decayHalfLifeDays 可调,0=关闭。

成本看板:每次蒸馏 LLM 调用(抽取/去重/L2/L3)的 token 成本按 provider/model 写入 SQLite 明细表(保留期可配置,默认 365 天,写入时滚动清理;记账失败只告警、绝不阻塞蒸馏), 设置页 → 记忆 → 成本 Tab 可视化:按模型分色的趋势折线(日/周/月粒度 + 近 N 天窗口 + L1/L2/L3 层级过滤)、层级 × 时间窗口表格(调用数 / 输出与思考 token / 均值 / 中位数)、 按模型累计——蒸馏开销一目了然。输入按字符计(dsh 流式 usage 不含输入 token), 输出与思考按 token 计。

记忆工具(3):

  • memory_search
  • conversation_search
  • memory_read_scene

真机实录:召回注入与工具调用在对话里的样子——"上下文注入 · memory"行先带出相关记忆,模型再按需调 memory_read_scene 读取场景块,凭记忆直接作答:

在只开放代码执行入口的受限会话中,模型经由 run_code 间接调用记忆工具(轨迹视图中的 SUBTOOL 嵌套):

分层记忆(L0–L3)

会话级记忆档位

  • 控件:输入栏内、模式选择器右侧的 pill(记忆·自动),点击在上方浮出档位滑块深浅主题自适应;
  • 悬浮板下半部是会话信息区:召回命中(命中/检索轮次与累计条数)、攒批进度

(本会话切片 x/生效阈值;关闭档显示挂起切片数)、本会话产出记忆条数、会话消息数, 外加异常状态行(存储降级 / 向量检索不可用)与全局摘要(待蒸馏条数、上次蒸馏时间); 数据走 dsh-memory/session-stats 端点(纯内存注册表 + 索引 COUNT,零文件 I/O), 打开期间自适应轮询(忙 2s / 静 5s),关闭即停;

  • 每会话的选择按 sessionId 持久化到 session-modes.json,重启/恢复会话不丢;

与全局开关叠加(全局是总闸);L2/L3 完全分类,分类内容不渗透。

  • 只写不读(#38):悬浮板内「注入」三态开关(跟随全局 / 开 / 关)——设为「关」

即只写会话:捕获与蒸馏照常(对话照常沉淀为 L0→L1→L2/L3),但不向本会话注入 任何记忆(召回注入、画像/导航稳定区、工具指南一并停止;memory_search 等读工具 返回只写提示)。pill 面文换作 记忆·只写 提示状态;覆盖按会话持久化,切回 「跟随全局」即清除、跟随设置页召回开关;适合调试/评测/敏感会话「只吸收不干扰」。 与 off 档正交:off 仍是完全隐身(连捕获都关),只写保留「进」关「出」。

界面预览

实测对比(DSH-MemBench:自动化基准)

图文回答"长什么样",这一节用自动化基准的实测数字回答"开了到底有什么用"(bench/,一条命令可复现)。方法:同场景库、逐字相同输入,A 组(记忆开)跑 3 次取合并值,B 组(记忆关)跑 1 次(无记忆的长任务每场景要吞数倍 token,成本护栏);对话赛道只跑 A 组(B 组会话独立无记忆必然失败,对照无信息量,已下线)。对话赛道环境:DeepSeek 官方 deepseek-v4-flash、插件 0.8.5(判卷与被测同源,答案原文全部留痕可人工复核)、Windows;题型设计借鉴 LongMemEval / LoCoMo / AMB,扩展题型与生命周期赛道参照 MemoryAgentBench / GoodAI LTM / BEAM。

对话赛道为 0.8.5 新基线(修复版插件 + 修正后的判卷口径);工作流赛道数字仍为 0.8.3 存档(0.8.5 起场景库扩至 8 个,新增前瞻记忆场景,重跑待做)。

对话赛道(20 场景 × 10 题型 × 3 次 = 420 题):答得准吗

0.8.5 基线(A 组数据;对话赛道 B 组已下线,只跑 A 组)。

召回双通道(A 组):被动注入召回率 78.1%(该题要点出现在召回注入中,281/360),其余多数由模型主动调用记忆工具查回——106 题主动查询、75 题靠工具兜底答对;端到端 95.2% 是两通道 + 模型利用的合成结果。记忆库跨场景全程累积下,探针召回注入混入其他场景记忆 295 次(已如实计数),总准确率反而前段 92.8% → 后段 97.7%——抗干扰能力经受住了膨胀记忆库的考验(离线灌水再灌 600 条合成噪声,检索层 recall\@5 也只降 2.8pp)。

分层看短板:检索层离线指标(recall\@5 受控复现)总 73.3%,其中事件排序 0%、场景回忆 50%——端到端仍 93%+ 靠的是注入邻近记忆后模型的鲁棒性;效率三角(记忆的开销):注入非但不加延迟(注入轮响应比无注入轮平均快 210ms)、注入占每轮输入约 10.3%,蒸馏全链路摊到每条捕获消息 ≈2727 输入 / 240 输出 token(1172 次调用 0 失败)。

工作流赛道(0.8.3 存档 · 7 场景版 · A 组 3 次 / B 组 1 次,真实工具沙箱):做得对、做得省吗

探针段完成度 85.5% vs 43.5%(+42pp):教学/变更段两组都有现场上下文,探针段(新会话延续任务)才是纯记忆窗口——A 组三个新考法场景(流程知识更新 / 双胞胎消歧 / 风格规范延续)全部 12/12 满分且三轮一致;B 组在风格规范场景探针 0/4(命名/结构/千分位/页脚约定只存记忆,沙箱探不出来),在流程更新场景则能靠读脚本逆向(判别力受沙箱可供性限制,已如实标注)。

长任务成本:B 组每场景输入 token 是 A 组的 6.8 倍(1.81M vs 266k)——无记忆时 agent 靠重新探索前进,high 思考档下甚至会自建工程去探测本可用一条脚本约定完成的流程;输出 token 3 倍(46.2k vs 15.4k)、步骤 +70%。这正是记忆的核心价值:省掉的不是任务难度,是无谓的往返与重复探索。

方法论与复现

node bench/harness/run.mjs --arm A --repeats 3 --provider deepseek-official --model deepseek-v4-flash   # 对话赛道(只跑 A 组)
node bench/harness/run.mjs --track workflow --arm AB --repeats 3 ...                                  # 工作流赛道(A/B 双组并行)
node bench/harness/run.mjs --track lifecycle --arm A ...                                              # 生命周期赛道(门控/off/rebuild/遗忘)
node bench/harness/report.mjs --latest [dialog|workflow]                                               # 汇总报告
node bench/harness/retrieval-metrics.mjs <runDir> --flood 200,600                                     # 检索层指标 + 灌水曲线
  • 判分:contains-all 程序判 + 判卷模型按要点判(答案原文与判分理由全部留痕 result.json 可人工复核);带 stale 的题(更新/连锁/遗忘)"旧值当作现状陈述"才判负、拒答题允许引用真实背景解释"不知道被问点";工作流完成度为产物文件 + 关键内容程序化校验(四型判据:正检查/禁词/产物缺席/存在性);
  • 指标面:准确率总表(6 核心 + 4 扩展题型)之外,自动产出检索层离线指标(recall\@5 / 注入精度 / 作废泄漏)、效率三角(注入开销差分 / 注入占比 / 蒸馏记账摊到每消息)、规模位置分析(库容膨胀下的准确率/污染)与生命周期赛道专属节(分族门控矩阵 / off 双断言 / rebuild 保真 / 遗忘);
  • 实时进度:跑基准时自动拉起本地进度面板并打开浏览器(--no-panel 关闭)——A/B 双臂场景/阶段/消息粒度进度、心跳与活动新鲜度(直判"卡住 vs 进程挂了")、累计成本随跑随涨;
  • 指标全部来自供应商上报 usage(输入含缓存命中拆分)与会话事件折叠;稳态缓存率剔除每会话首请求(0.8.5 基线:89.1%——记忆注入不伤缓存);
  • 回归用途:改插件前后各跑一遍,compare.mjs 出对比表(环境头校验含 gitSha + B 组对照组漂移告警 + 检索层指标对比);
  • 局限(诚实声明):单机;A 组 ×3 合并、B 组 ×1(成本护栏,噪声更大);判卷与被测模型:对话 0.8.5 基线同源、工作流存档跑为异构(glm-5.3 判 v4-flash);作者自建场景库(倾向记忆优势场景,欢迎自行复现);沙箱文件的可供性会部分泄露流程(B 组可读脚本逆向,判别力受限处已如实标注);工具审计双档(严格违规判负/宽松提示),实测双方 0 违规。

完整报告与逐题数据:bench/baseline/。

存储布局

向量能力默认关闭(纯 FTS)。DSH 的 ctx.llm 无 embeddings 端点,语义检索由 三态嵌入源提供(关闭 / 远程 / 本地),设置页可运行时切换——见下节。

语义检索(嵌入源)

设置页(记忆 → 概览 → 语义检索)选择嵌入源,即时生效、无需改配置重启:

三种嵌入源:关闭(默认,纯 BM25 关键词检索)、远程(自备任意 OpenAI 兼容 /embeddings 服务,embedding.* 四件套配齐才可选)、本地(内置模型目录选一款, ONNX 量化 CPU 推理——无需 API Key,数据不出本机)。本地模型目录是插件内置 白名单(每款锁定 revision + 每文件 sha256,不可下载任意仓库)。

  • 下载:模型卡一键下载(默认镜像 hf-mirror.com,断点续传 + sha256 完整性

校验;直连不可达时可走代理——默认自动探测 HTTPS_PROXY/ALL_PROXY 等环境 变量,见 embedding.proxy)。单文件失败自动重试且换缓存键(?dshmem-retry=N, 绕开镜像 CDN 偶发的坏缓存对象),校验失配从零重下、网络错误保留断点续传; 落盘数据目录 models//,不用了随时在设置页删除;

  • 按需运行时:首次切换本地档才安装推理运行时(transformers.js,约 100\~200MB,

装进数据目录 runtime/——不进插件依赖树,不碰插件安装目录);模型加载与推理在 独立 worker 线程执行,不冻结宿主事件循环(嵌入计算期间对话与页面交互照常);

  • 活切换:一键换源——自动后台全量重嵌(进度可见、可取消,期间检索自动降级

关键词,不影响对话;维度变化时向量表按新维度重建);切换失败保持旧源,重启仍按原源运行;

  • 生效规则 = 部署上限 AND 运行时选择:embedding.allowLocalModels=false 可整体

禁用本地档、未配 embedding.* 四件套则远程档不可选(企业部署可收口),状态持久 化在 embedding-source.json。

配置

覆盖配置写在 profile 自己的 cordis.patch.yml,用顶层裸 patch 条目(直接 id:, 不要包在 insert: 里——insert 与 bundle 层同 id 追加会导致 duplicate loader entry id 启动失败):

- id: dsh-memory
  name: dsh-prime-memory
  config:                    # 键按行整体替换(不深合并),按需写全要保留的键
    family: auto             # 新会话默认档:auto | chat | work
    llm:                     # 蒸馏模型静态路由(双字段齐 = 部署 pin,优先于设置页路由链;
      provider: ''           # 留空则跟随设置页路由链主路由或当前默认模型)
      model: ''

字段 · 默认 · 说明 family · auto · 新会话默认记忆档位:auto(双族自动)\ · chat(个人)\ · work(工作);会话内可用输入栏控件临时切换 dataDir · $DSH_HOME/memory · 数据目录 capture.enabled · true · L0 捕获 capture.stripCodeBlocks · true · 助手消息剥离代码块 capture.maxMessageChars · 4000 · 单条消息最大字符数 capture.redactSecrets · true · 载荷脱敏:捕获写入即把 8 类密钥(PEM/Bearer/JWT/Cookie/厂商 API key/邮箱/长号/高熵 ID)替换为 [REDACTED:] 占位符,覆盖 L0、蒸馏输入与手动写入;false 回明文(开启后 L0 原文不再可逆) trace.enabled · true · 结构化追踪:召回/蒸馏事件按天 JSONL(/trace/),设置页"日志"Tab 可切换查看 trace.retentionDays · 14 · 追踪事件保留天数(0 永久) trace.captureContent · false · true 才存召回 query 原文(默认只存长度 + sha256) extract.enabled · true · L1 抽取 extract.minMessages · 6 · 稳态触发阈值:单会话攒够 N 条新消息跑一次 L1 抽取。起步阶段生效阈值从 1 翻倍爬坡到此值(首轮即出记忆,随后自动攒批省调用) extract.idleSeconds · 300 · 闲置兜底:会话静默 N 秒后把未蒸馏切片落袋(接住"没攒够阈值用户就离开");0 关闭 extract.backgroundMessages · 10 · 抽取时附带的背景消息条数(按会话从 L0 现查,会话间互不污染) extract.candidatePool · 5 · 去重候选池大小 l2.enabled · true · L2 场景整合 l2.minNewMemories · 5 · 距上次 L2 整合的新记忆阈值 l2.maxScenes · 12 · 场景块数量上限 l2.sceneContextLimit · 3 · L2 prompt 附带的相似场景全文上限 l3.enabled · true · L3 画像蒸馏 l3.interval · 20 · L3 蒸馏间隔(新记忆条数) recall.enabled · true · 自动召回 recall.maxResults · 5 · 每条新用户消息前注入的 L1 条数上限 recall.maxCharsPerMemory · 500 · 单条注入记忆的字符上限(超限截断并提示用记忆工具查全文);0 不限 recall.maxTotalRecallChars · 2000 · 整轮注入总字符上限(超限按相关性丢尾部);0 不限 recall.timeoutMs · 5000 · 召回总预算(ms):超时跳过本轮注入、不阻塞对话;0 不限时 recall.includePersona · true · 系统提示注入画像上下文(`,稳定区) | recall.includeSceneNav | true | 系统提示注入场景导航(<scene-na