dsh-recall
Conversation history recall for DSH: three-layer (literal/fuzzy/semantic) retrieval over every past session's original text, fully local & offline — AI never forgets what you told it. One-command install via `dsh.bundle.patch`, semantic layer runs in a worker thread.
Install
dsh plugin --profile web add dsh-recall
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-recall
🌏 [English](README.md) · 中文
<div align="center">
对话历史回忆插件 —— 给 DeepSeek Harness 的 agent 一座"记忆迷宫"




</div>
AI 再也不会"忘记"你说的话了。
DeepSeek Harness (DSH) 原生插件:给 agent 一座记忆迷宫——为你们的每一段对话筑起走廊与房间。它记得你们之间发生过的一切:一个决定、一条设定、一次讨论、一句随口提的需求。你问"我们上次说到哪了",它走进迷宫,把当时的对话原样带回,再像聊天一样自然融进回答——你甚至察觉不到它"想了一下"。
对话历史回忆 · 三层检索(字面 / 模糊 / 语义)· 完全本地离线 · 压缩免疫
- 运行中,只在角落里安静地亮起一束扫动的光:
- 完成时,不留痕迹:
适合谁使用
- 长会话的重度用户——一场对话跨数天、几百轮,翻不到头
- 写作者 / RP / 酒馆玩家——设定、伏笔、人物关系散落在几个月前的对话里
- 代码与文档维护者——当时拍板的理由、踩过的坑,压缩后只剩一句摘要
- 任何说过"我们上次不是聊过吗"的人——它把原话找回来,而不是让你重讲一遍
反过来:如果你的会话都很短、随时能翻,你大概用不上它——它专为"历史太长、记忆被压缩"的场景而生。
快速开始
dsh plugin --profile web add dsh-recall@0.2.2
一条命令即可:包自带组合补丁(bundle 层),插件与它所需的全文搜索会自动接线。重启 dsh web 即可。没有额外步骤:模型随包预置(完整版约 37MB),首次搜索自动建立索引,随后在后台安静完成语义预热(几分钟,对你的使用无感知)。
也可以在 dsh-extension-hub 的插件管理页 「附加功能」 区块里一键安装/停用/卸载本插件。
从源码安装(git 克隆):
dsh plugin --profile web add git+https://github.com/Relistencode/dsh-recall.git
仓库已跟踪模型文件(models/model_merged.onnx)与内置推理运行时:git 安装完全离线可用,无构建步骤、无需 allowBuilds 配置。可选依赖 dsh-recall-models 仍会尝试从 npm 拉取;拉取失败时自动改用仓库内模型——两种情形语义层都可用。所有路径经 $DSH_HOME(默认 ~/.dsh)解析,harness 主目录在哪个位置安装效果完全一致。
可选配置
- id: recall
name: dsh-recall
config:
semantic: false # 关闭语义层(只保留字面 + 模糊,包体更小)
warmup: gentle # 慢速预热,降低后台 CPU 占用(仅预热期间占用,后续使用 0 占用)
它不是什么
- ❌ 不是上下文工程 —— 不把全部历史硬塞进模型窗口
- ❌ 不是提示词工程 —— 不靠 prompt 让模型"装作记得"
- ❌ 不是 memory 文档系统 —— 不需要手动维护 MEMORY.md / 备忘录
- ✅ 是真正的回忆能力:按需检索对话原始记录——包括已被压缩掉的历史(压缩只是摘要,原文永远可搜)
能力概览
能力 · 实现
三层混合检索 · 字面 / 模糊 / 语义自动合并,覆盖率门控(≥90%)+ 静默降级链
渐进披露 · 默认轻量粗召回(标题 + 片段 + 事件,约 100–800 tokens);需要时 detail 下钻原文——命中窗口 / 精确原文 / 分页翻阅
事件聚合 · 同一主题的多次提及合并为事件([startSeq..endSeq],文本块间隔 ≤5)——一次拿到完整片段集,而非零散碎片;事件全文仍是一次 detail 下钻之遥
自动调用 · agent 自主在需要时回忆(压缩后、缺细节时主动调用),无需用户开口;用户也可主动要求
自动回忆层 · 用户消息到达时的宿主确定性门控(流程命令 / 回指词 + 模糊索引确认的旧片段)静默注入相关历史——无额外 LLM 调用、无 UI
压缩锚点 · 监听 compaction/summary,压缩后自动注入一次轻量锚点(摘要 + 关键原文片段,3 轮过期)
作用域控制 · 默认仅当前会话;workspace / all 只在用户明确要求时使用
压缩免疫 · 索引覆盖全量历史,含 shadowed(压缩遮蔽)事件
增量索引 · live 会话走 ctx.sessions,持久化走 sessionPersistence,append-only 增量
后台预热 · worker 线程嵌入(~10 条/秒),host 事件循环零阻塞
无感知 UI · 「回忆中…」光波 → 「回忆完成」一行,结果不进 UI、由 agent 自然呈现
完全本地离线 · 零 npm 运行时依赖;无外部模型 API;断网也能用
架构
<img src="docs/assets/recall-architecture.svg" width="100%" alt="dsh-recall 架构:顶部回合生命周期,下方能力层">
- 回合生命周期(顶部):一次回忆是一条直线——用户提问、agent 调用
recall工具、三层检索、命中按会话聚合成事件、agent 按需拿到轻量粗召回或下钻窗口。 - 检索层:三条独立的检索通道(字面 / 模糊 / 语义),在覆盖率门控下合并(见[三层混合检索](#三层混合检索))。
- 索引与数据:全部走官方服务(
ctx.sessions/ctx.sessionPersistence/ctx.sessionQuery)读取——不解析 .zstd、不碰私有格式。插件自有的recall-index.db(SQLite)存放模糊索引、向量与 trigram FTS。 - 治理与作用域:作用域红线(默认当前会话)、覆盖率门控、降级链、token 预算都在这一层。
- 自动层:两条静默监听——
compaction/summary把每次压缩变成一条轻量锚点(历史被折叠后 agent 依然有方向感);自动回忆门控盯住用户消息,当用户提到更早的讨论时静默注入相关历史。
核心机制
三层混合检索
层 · 技术 · 解决
字面 · 官方 FTS5 全文索引 · 精确命中原词
模糊 · 自建 trigram + 字符二元组索引(零依赖) · 记不清原话、只记得片段、换字漏字
语义 · 本地 bge-small-zh 模型(int8,24MB 预置) · 换词、意译、"大概意思"也能想起来
<img src="docs/assets/recall-retrieval.svg" width="100%" alt="三层检索:查询扩散到字面/模糊/语义,经覆盖率门控合并">
- 模糊层是主路径(它已覆盖字面层的能力且容错更强);官方 FTS5 是兜底;语义层只在覆盖率 ≥90% 时才参与混合——否则保持沉默,绝不让排序变差。
- 任一层失败都静默降级到下一层——语义 → 模糊 → 字面,永不报错。
recall永远有答案。 - 推理在 worker 线程运行(WASM 放主线程会阻塞 host 事件循环;实测 ~9.6 条/秒零阻塞)。
- 全部本地运行、完全离线——无外部模型 API、无网络。
渐进披露
回忆分两阶段,第二阶段只在 agent 真正需要时触发:
阶段 · agent 拿到什么 · 成本
1 — 粗召回(默认) · 会话标题 + 片段 + 同主题事件,分组排序 · 最多 10 个会话约 100–800 tokens
2 — detail 下钻 · 会话命中列表 / 精确原文窗口(readEvent)/ 分页翻阅 · 约 300 tokens/会话(如 ±3 事件窗口)
实机实测:粗召回比旧版全量上下文窗口省 ~80% token(10 会话命中:2500–3000 → ~600,聚合前)。事件聚合保持同样的纪律——只带片段,事件全文一次下钻之遥——粗召回单次仍在 ~800 tokens 以内。无关内容从不进上下文——而需要时,原文永远一次下钻之遥。
压缩锚点
压缩是记忆最容易丢失的地方——harness 生成摘要,原文被遮蔽。dsh-recall 监听 compaction/summary,立即为被压缩会话注入一条轻量锚点:
- 内容:LLM 摘要 + 最多 3 条关键原文片段(优先用户消息,再取最长文本块)。
- 过期:3 轮组装后自动消失——它是路标,不是拐杖。
- 逃生口:精确原文随时
detail下钻,永远可还原。 - 实机端到端验证:真实
/compact后,锚点在下一轮组装中注入,内容正确,3 轮后自动过期。
自动回忆层
agent 自行决定何时调用 recall,但模型无法可靠判断「我是不是缺细节」——这一层补的正是这个缺口。每条用户消息到达时,宿主运行一个本地确定性门控(lib/auto-gate.js):
- P——流程命令(「继续」「我重启了」「runtime 恢复」):自动回忆上一轮话题——实测:占手动触发语境 56%,普通消息误报仅 3.6%。
- A——回指词(「之前说」「记得吗」「搜索历史」…)且其指代片段(当前轮不可见的字符二元组连续段)确实命中模糊索引——这个词真的在更早出现过,才放行。
门控命中后,一次轻量当前会话检索静默发生,命中以不可见方式注入 agent 系统提示(3 轮过期;会话恢复场景 1 轮;注入有效期内不重复触发=内置防抖)。agent 像一直知道那样作答——无感、无额外 LLM 调用、零网络。
门控基于真实手动触发语料校准(19 会话 / 18 语境,scripts/analyze-triggers.mjs):P+(A∧B3≥0.6) 覆盖 89% 手动触发、误报 8.9%(A|P 单独:100% 覆盖 / 18.9% 误报)。成本 ≈ 每轮平均 +190~400 tokens(触发率 9~19% × 3 轮 × ~700)。
作用域与隐私
- 默认作用域是仅当前会话——跨会话(
workspace)、跨项目(all)只在用户明确要求时使用。 - 呈现层无感知:一声安静的「回忆中…」光波、一行「回忆完成」,别无其他。结果不进 UI——由 agent 自然呈现。
- 数据留在本机:无外部 API、无遥测、无网络。
实测数据
token 收益(v0.2.1 实机)
指标 · 结果
粗召回成本(默认) · 每次调用约 100–800 tokens
旧版全量上下文窗口(10 会话) · 约 2500–3000 tokens——多花 3–4 倍
detail ±3 窗口 · 约 300 tokens/会话
压缩锚点 · 实机验证:真实 /compact → 锚点下一轮注入,内容正确,3 轮自动过期
语义预热 · worker 线程 ~10 条/秒,host 事件循环零阻塞
检索质量(黄金评测集)
合成 4 会话语料(32 条文档)+ 23 条人工标注查询(精确 / 模糊错字 / 意译 / 跨会话),内存运行、真实模型——复现:node eval/run-golden.mjs:
变体 · recall@5 · MRR · nDCG@10
仅字面(模拟官方 FTS5) · 0.196 · 0.217 · 0.201
仅模糊 · 0.587 · 0.652 · 0.579
仅语义 · 0.533 · 0.609 · 0.529
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::5,最后更新 2026-08-21