dsh-mem0-plugins
August 29, 2026 · View on GitHub
把 hermes 版 mem0 记忆插件的「全自动记忆」移植到 DeepSeek Harness (dsh),做成标准
bundle 插件:dsh plugin add 安装、dsh plugin remove 卸载,不改任何 dsh 源码。
只支持自托管 Mem0 server(HTTP + X-API-Key),不做 cloud/OSS 模式。
它会自动做什么
| 能力 | 触发时机 | 说明 |
|---|---|---|
| 自动召回(工具驱动) | 模型回答前 | usage 节强引导模型先调 mem0_search——UI 工具卡即召回动作的可见呈现;长查询先蒸馏提炼意图再搜索 |
| 使用引导 | 常驻 | 系统提示中注册使用说明节,引导模型对用户相关的问题主动调 mem0_search(多角度多跳) |
| 自动写入 | 每轮对话结束 | 把「用户消息 + 助手回复」交给服务端 LLM 抽取事实(infer: true);纯 JSON 的工具输出会被替换成占位符防污染 |
| 潮浪并忆 | 写入时 | 同一会话的短对话按 user 分桶合并:空闲 5s / 窗口 15s / 5 轮 / 4000 字符任一达标即合并为一次批量写入,摊薄抽取调用;超长消息(>2000 字符)走快速直写 |
| 上传脱敏 | 写入时 | user/assistant 文本交给抽取 LLM 前过纯函数密钥闸(sk- 风格 key、AWS key、Bearer/X-API-Key 头、PEM 块、password= 键值、.env 形态折叠),命中替换为 [REDACTED:label];redactEnabled 可关 |
| 反馈闭环 | update/delete 后 | best-effort 上报 /evolve/feedback(correction/useless),参与服务端 salience 进化 |
四个模型工具
| 工具 | 用途 |
|---|---|
mem0_search | 语义搜索用户记忆(支持 top_k / rerank 覆盖) |
mem0_add | 逐字存储持久事实(不走 LLM 抽取) |
mem0_update | 按 ID 改错(上报 correction 反馈) |
mem0_delete | 按 ID 遗忘(上报 useless 反馈) |
安装 / 卸载
# 安装(web profile;安装后重启 dsh 生效)
dsh plugin --profile web add ./plugins/dsh-mem0-plugins
# 卸载
dsh plugin --profile web remove dsh-mem0-plugins
装好即默认启用(enabled 默认 true,指向本机 server 时零配置可用);
设置页改动即时生效,无需重启。要关闭记忆,在卡片里关掉「启用插件」开关——
卡片描述行实时显示 已启用/未启用 + host,一眼可见。
设置项
默认值:enabled=true(schema 默认,patch 不覆盖——配置即启用)、
host=http://127.0.0.1:8888、apiKey=''(本机 server 无鉴权时零配置可用)。
设置页保存的值落在用户层,优先级更高。
连接与身份
| 字段 | 默认 | 说明 |
|---|---|---|
enabled | true | 总开关,默认开启;关闭后不再召回/写入,工具调用提示未启用 |
host | http://127.0.0.1:8888 | 自托管 server URL |
apiKey | 空 | 以 X-API-Key 头发送;AUTH_DISABLED 部署留空 |
userId | dsh-user | 记忆归属 user_id,跨会话共享同一份记忆 |
agentId | dsh | 写入附带的 agent_id |

自动召回
| 字段 | 默认 | 说明 |
|---|---|---|
forceRecallStep | true | 方案 B:每轮第一步注入『必须先调 mem0_search』提醒(琐碎轮跳过,plugin-source 显示为系统注记不写记忆);关闭则只靠 usage 引导 |
topK | 10 | 每次召回最大条数(1–50) |
rerank | false | 开启则以全深度模式请求重排(服务端需配置 reranker) |
distillEnabled | true | 长文本查询蒸馏总开关(见下方「查询蒸馏」) |
distillMinChars | 500 | 不超过该长度的消息原样直查,零损失零开销 |
distillInputMaxChars | 8000 | 送入蒸馏模型的原文截断上限 |
distillBaseUrl | (空) | 蒸馏端点(OpenAI 兼容);留空跳过蒸馏直查原文 |
distillApiKey | (空) | Bearer 鉴权;端点留空时蒸馏自动跳过 |
distillModel | Qwen3.5-9B | 蒸馏模型(本地部署) |
distillTimeoutMs | 30000 | 蒸馏单次超时 |
distillRetryAfterMs | 20000 | 双飞触发阈值:首请求无响应超过该时长即并发第二请求,先完成者胜出 |


自动写入
| 字段 | 默认 | 说明 |
|---|---|---|
syncEnabled | true | 每轮结束写入总开关 |
coalesceEnabled | true | 潮浪并忆合并写入;关闭则逐条直写 |
coalesceIdleMs | 5000 | 桶内空闲冲刷阈值 |
coalesceWindowMs | 15000 | 桶窗口冲刷阈值 |
coalesceMaxTurns | 5 | 桶内轮数上限 |
coalesceMaxChars | 4000 | 桶内字符上限 |
fastpathChars | 2000 | 单轮超过该长度直接落库 |
sliceThreshold | 8000 | 单条消息超过该长度按段落切片(服务端分块按消息粒度、单条不拆,超长单条会撑爆抽取窗口) |
slicePieceChars | 2000 | 切片后每片字符上限(实测服务端单条安全值 ≈2000);切片全量保留、服务端分块提取后合并 |
maxBucketAgeMs | 1800000 | 潮浪桶存活上限(30 分钟):超龄且「服务端明确拒绝过」(HTTP 状态码)才丢弃;连接级失败(宕机/超时)不计龄 |
redactEnabled | true | 写回载荷上传前脱敏(命中替换为 [REDACTED:*] 标记;可关) |
feedbackEnabled | true | update/delete 成功后上报 evolve 反馈(可关) |

可靠性与超时
| 字段 | 默认 | 说明 |
|---|---|---|
queueMaxLen | 50 | 待写队列上限,满时丢最旧 |
breakerThreshold | 5 | 连续失败达该次数熔断 |
breakerCooldownMs | 120000 | 熔断冷却时长 |
requestTimeoutMs | 420000 | 单请求总闸,search/add 共用(对齐 hermes httpx timeout=420.0) |

要改 profile 层默认值,在 ~/.dsh/profiles/web/cordis.patch.yml 追加:
- id: mem0
config:
enabled: true
host: http://mem0.internal:8888
apiKey: your-admin-api-key
召回形态

- 显式工具链路:不做后台静默预取(dsh 平台在消息回显后无内容注入钩子,
详见
docs/COMPARISON.md平台时序约束);模型按 usage 引导先调mem0_search, 工具卡让「召回中」对用户可见,蒸馏/超时/熔断全套在工具内部生效; - 第一步强制提醒(方案 B,默认开):每轮第一步经
agent/pre-step注入 plugin-source 提醒「必须先调 mem0_search」(form:'notice'注记——UI 消息区显示 「上下文注入 · dsh-mem0-plugins · 【记忆提醒】回答前必须先调 mem0_search」, 折叠行即直接可见,展开可见模型侧全文;不写记忆、琐碎轮跳过、 开关forceRecallStep可关)——把「先搜再答」从模型自觉升级为流程默认。 - 琐碎输入跳过(
src/guards.js):纯问候/确认/斜杠命令词表三分类等价, 只整串匹配、带正文永不误伤。守卫只拦「注入提醒」,拦不住模型自愿搜索—— 常驻 usage 节的「先搜再答」硬命令会让模型在「好的/继续」轮照样调工具 (2026-08-24 实测缺陷)。修复(方案 A):usage 节与mem0_search工具描述 同步写入同一词表标准的豁免条款——整串仅为应答/问候/推进时明确豁免搜索, 携带任何实义内容(如「继续帮我看看那个报错」)立即恢复强制; - 中断轮不入记忆:被打断的半截回复不会写进 mem0(部分输出不是持久对话真相, 对齐 hermes #15218)。
查询蒸馏(防长文本打爆服务端)
移植自 hermes agent/memory_manager.py::_distill_query,只作用于召回查询,
不碰写入路径:
- 消息 ≤500 字符:原样直查——零语义损失、零额外调用;
- 超长消息(贴日志/代码):截断前 8000 字符送本地小模型提炼成「2–4 关键词或
一句检索意图」再去
/search,embedding 与检索不再吃整段噪音; - 语言漂移防护:中文输入的蒸馏结果若出现越南语重音字符或非拉丁非 CJK 文字(聚合网关路由漂移到多语小模型的实证症状),判为污染即回退;
- 并发双飞:首请求 20s 无响应即并发第二请求(首个不取消),先完成者胜出;
- 全部失败/超时:回退原始 query,检索永不静默丢失。
真机记录(2026-08-23,Qwen3.5-9B @ 本地蒸馏端点):
原文长度: 4250 → distilled 4250 -> 17 chars (6480 ms)
蒸馏结果: mem0 服务端部署端口和内网地址
可靠性设计
- 熔断器:连续失败 ≥5 次(可配)暂停所有 mem0 调用,冷却 120s 后自动恢复; 404/not found 类客户端错误不计入熔断。
- 连接级重试:连接拒绝/DNS 类失败自动重试一次(此时请求大概率没到达服务端, 不会造成重复写入)。
- 有界队列:待写队列满(默认 50)丢最旧,防止服务端长时间不可用时内存膨胀。
- 兜底冲刷:插件 dispose 时冲刷全部合并桶,记忆不丢失。
可观测(潮浪收益与卫生计数在哪里看)
潮浪并忆与写路径卫生的计数不打到浏览器,落在 dsh 宿主进程日志:
- 日志通道:插件
info/warn双通道——ctx.logger(dsh 内部日志,默认不透出 stdout)+console.log/warn直出宿主进程 stdout。systemd 部署看journalctl -u dsh.service -f,非 systemd 看 dsh 进程的 stdout 输出。 - 每次合并冲刷(info 级)打一条,含累计 totals:
[dsh-mem0] mem0 coalesced 3 turn(s) into 1 write (session=<id>, saved 2 call(s), chars=512, trigger=idle; totals: batches=12 savedCalls=34 dropped=0 jsonSanitized=3 redacted=1 sliced=0)
- 计数含义:
| 字段 | 含义 |
|---|---|
savedCalls | 累计省下的服务端 LLM 抽取调用数(合并 N 轮 = 省 N−1 次) |
dropped | 队列满(默认 50)丢最旧待写条的次数,同时打一条 warn |
jsonSanitized | 被剥除的纯 JSON 消息条数(防键名/工具输出当「事实」入库) |
batches / direct | 批量合并写入次数 / 快速直写次数(超长或合并关闭时) |
队列丢最旧(warn):[dsh-mem0] mem0 sync queue full (50), dropped oldest pending turn;
JSON 剥除与快速直写为 debug 级。熔断开合、直接写在失败时均有 warn。
超时分层(与 hermes 同步)
| 层级 | 默认值 | 说明 |
|---|---|---|
HTTP 总闸 requestTimeoutMs | 420s | 插件→server 单请求上限;server 内 LLM 三层兜底最坏 360s,正常召回摸不到总闸 |
| 召回形态 | 工具驱动 | 不再做后台预取注入;模型先调 mem0_search(内部蒸馏+搜索),工具卡在 UI 即召回动作 |
| 工具级额外限時 | 无 | 有意不设——只有总闸一层,与 hermes 行为一致 |
本地验证
cd plugins/dsh-mem0-plugins
node test/smoke.mjs # Host 半:apply 全链路 + 工具(含蒸馏)+ 写入链路 + 强制提醒 + 卫生(81 项)
node test/client-smoke.mjs # Client 半:bundle 加载 + locale/slot 注册 + 表单 save 真链(28 项)
真机联测记录(2026-08-23,本机 mem0-dev 栈):
Mem0Client.search OK in 2121 ms; hits: 1; breaker failures: 0
no-auth rejected as expected: Mem0HttpError | HTTP 401
排障
| 现象 | 处置 |
|---|---|
| 工具返回「插件未启用」 | 设置页打开 enabled 并确认 host 已填 |
| 「circuit breaker open」 | 服务端连挂多次触发熔断;检查 server 后等冷却或调低阈值 |
| HTTP 401 | apiKey 缺失或错误(非 AUTH_DISABLED 部署必须填 ADMIN_API_KEY) |
| 「server unreachable」 | curl http://<host>/openapi.json 先确认可达性 |
| 记忆没被召回 | 该 user_id 下无相关记忆(GET /memories 查看);模型未调 mem0_search(检查 forceRecallStep 提醒是否被 UI 注记与工具卡跳过) |