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

忆取记忆 zzdhsxk/dsh-recollect

DeepSeek Harness
zzdhsxk34 天前有提交已提供中文文档扫描:无法判定

常驻极小画像,其余记忆按需检索并过闸门入档

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

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

自动兼容检查未通过:仓库缺少 package.json,无法用 dsh 插件安装命令安装。以下命令仍可尝试,但可能失败。
无法用 dsh 插件命令安装(仓库内无 dsh 插件清单)
git clone https://github.com/zzdhsxk/dsh-recollect.git
按该仓库 README 的原生方式安装;若作者另行发布了 DSH 插件包,请以其文档为准

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · chat
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 34 天前
档位由哪些信号合成

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

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/11/4) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库缺少 package.json,无法用 dsh 插件安装命令安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-recollect(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/8 09:41:40

安全扫描自动 · 静态分析源码
v2.7.0
⚪ 扫描:无法判定尚无人工评估
展开查看扫描说明与证据 ↓

已尝试扫描但取不到可分析的源码:仓库或包不存在、已删除,或为非 JS/TS 实现、未随包发布源码。无法判定,不代表安全。

  • · 取源不可用(Error: github tarball HTTP 404 @ https:
  • · api.github.com
  • · repos
  • · zzdhsxk
  • · dsh-recollect
  • · tarball)
扫描于 2026/11/4(0 天前)

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

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh@deepseek-ai/dsh-tools@deepseek-ai/dsh-llm
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 常驻极小画像
  • 按需检索记忆
  • 写入过闸门

dsh 记忆 / 用户画像 / 按需召回插件:常驻极小画像、其余按需检索、写入过闸门、可镜像进 Obsidian

README

由 DeepSeek 最新模型翻译生成
dsh-recollect(忆取) 英文:README.en.md · 变更:CHANGELOG.md DeepSeek Harness 的记忆 + 用户画像 + 按需召回层:常驻注入极小画像、其余一律按需检索;写入过闸门;批准的记忆可镜像进 Obsidian vault,供你直接阅读和编辑。 为什么不是“又一个记忆插件” | 问题 | 常见做法 | dsh-recollect | | 注入成本 | 每轮把记忆塞进上下文(越长越贵,还破坏前缀缓存) | 常驻只放画像 + 置顶,文本固定;其余走 memory_search 按需取;空存储 0 字节 | | 谁写长期记忆 | agent 直接写 | 闸门:默认进候选队列,你批准才入档;每次决策 append-only 可审计 | | 重复条目 | 越记越多 | 相似标题自动取代(旧条目归档并记 superseded_by,不删除) | | 知识库 | 记忆和卡片混在一起 | 只写 60_Memory(vault 内),10_Cards 归你的编译流水线独占;知识库只读检索 | | 数据可迁移 | SQLite 黑盒 | Markdown 为准,索引可重建;直接拿 Obsidian/编辑器改都行 |
展开完整文档(README 剩余 1 节)
dsh-recollect(忆取)

英文:README.en.md · 变更:CHANGELOG.md

DeepSeek Harness 的记忆 + 用户画像 + 按需召回层:常驻注入极小画像、其余一律按需检索;写入过闸门;批准的记忆可镜像进 Obsidian vault,供你直接阅读和编辑。

为什么不是“又一个记忆插件”

| 问题 | 常见做法 | dsh-recollect |
| 注入成本 | 每轮把记忆塞进上下文(越长越贵,还破坏前缀缓存) | 常驻只放画像 + 置顶,文本固定;其余走 memory_search 按需取;空存储 0 字节 |
| 谁写长期记忆 | agent 直接写 | 闸门:默认进候选队列,你批准才入档;每次决策 append-only 可审计 |
| 重复条目 | 越记越多 | 相似标题自动取代(旧条目归档并记 superseded_by,不删除) |
| 知识库 | 记忆和卡片混在一起 | 只写 60_Memory(vault 内),10_Cards 归你的编译流水线独占;知识库只读检索 |
| 数据可迁移 | SQLite 黑盒 | Markdown 为准,索引可重建;直接拿 Obsidian/编辑器改都行 |
| 上游依赖 | fork 上游跟随更新 | 只抄机制,UPSTREAM.md 记账 + scripts/upstream-radar.mjs 雷达 |

安装

本地开发(改代码即时生效)
dsh plugin --profile web add link:~/dsh_workspace/plugins/dsh-recollect
或从 GitHub
dsh plugin --profile web add github:/dsh-recollect

配置(profile 的 cordis.patch.yml,顶层覆盖,不要手动 insert —— bundle patch 已自动注册):

- id: dsh-recollect
config:
rootDir: ~/.dsh/memory # 记忆存储根(默认就是它;刻意与 vault 分开) vaultDir: ~/dsh_workspace/obsidian-kb # 填了才开镜像 vaultFolder: 60_Memory # 只写这个目录 vaultCardsDir: 10_Cards # 只读检索用 injectMaxBytes: 3072 # 常驻注入硬预算(0 = 完全不注入) residentTopEntries: 8 # 常驻块里最多列几条置顶 autoApprove: false # true = agent 写入直接入档(跳过候选队列) enableTools: true enablePanel: true

用法

面板:侧栏底部「忆取」→ 概览 / 记忆 / 候选 / 画像 / 体检 / 知识库 / 同步 / 设置(搜索、读全文、归档、批准、编辑画像;体检页给整理建议、知识库页做只读提炼、同步页预演/导入/一键裁决冲突)。

Agent 工具(按需召回的真入口):

| 工具 | 作用 |
| memory_search | 搜记忆(可选一并只读搜知识库卡片) |
| memory_read | 按 id 读全文 |
| memory_remember | 写回一条(默认进候选) |
| memory_forget | 归档(不硬删)并撤 vault 镜像 |
| memory_profile | 读/写画像(user = 关于你,soul = 你自己的约定) |
| memory_candidates | 候选队列:列出 / 批准 / 驳回 |
| memory_status | 存储路径、条目数、注入字节数、vault 状态 |
| memory_sync | 跨机同步:status / preview / apply / resolve(冲突永不自动合) |
| memory_kb_learn | 从 Obsidian 知识库提炼记忆(只读;产物进候选) |

HTTP API(/recollect/api):status · entries · entry?id · search?q · profile · candidates · resident · index + POST remember · approve · reject · forget · profile · reindex。

存储布局

~/.dsh/memory/
├─ profile/user.md 画像(常驻注入,可直接手改) ├─ profile/soul.md AI 自己的长期约定 ├─ entries//.md 记忆(scope: user|project|lesson|knowledge) ├─ candidates.jsonl 候选队列(append-only,可审计) ├─ archive/ 被取代 / 被遗忘(永不删除) ├─ state/ 会话记账 └─ MEMORY.md 人可读索引(可删可重建)

vault 侧只出现 60_Memory//-.md 与 60_Memory/INDEX.md。

测试

npm test # core 8 + vault 6 + host 7 + client 3 + radar 7 = 31 项断言
npm run test:host # 假 ctx 走完 apply():路由/注入段/批准/镜像/卸载
npm run radar # 上游雷达(需 GITHUB_TOKEN;--self-test 可离线)

后续(还没做的)

- npm 公开发布(代码已就绪:npm pack --dry-run 通过;缺的是登录 npm login)
- 面板体检页/知识库页的人工目视验收(契约测试已覆盖渲染)
- 向量检索在条目很多时的召回质量调参

本机向量服务(ollama + 外置盘)向量只是加分项:embedUrl 为空 / 服务没起 / 超时 / 返回畸形 → 检索自动退回纯关键词,绝不报错、绝不阻塞。

本机实测可用的搭法(2026-09-30):

brew install ollama # 0.35.0
模型放外置盘,用 launchd 托管(KeepAlive + RunAtLoad → 开机自启、不随终端退出) ~/Library/LaunchAgents/com.dage.ollama.plist EnvironmentVariables: OLLAMA_MODELS=/ollama/models OLLAMA_HOST=127.0.0.1:11434 launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.dage.ollama.plist
node scripts/embed-live.mjs # 自检:维度 / 耗时 / 中文语义温差

插件配置(profile 的 cordis.patch.yml,顶层覆盖,不要 insert):

- id: dsh-recollect
config:
embedUrl: http://127.0.0.1:11434
embedModel: batiai/qwen3-embedding:0.6b # 1024 维;中文语义实测 Δcos≈0.45 embedWeight: 0.5 # 最终分 = 关键词分 + 0.5 * max(0, cos)

★ 这台机器上 ollama pull 会失败(真实坑,已绕过)

代理软件(Clash 类)fake-IP 模式下,registry.ollama.ai 与 CDN 解析到 198.18.x.x(保留网段), ollama 的 SSRF 护栏判定"非公网 IP"直接拒绝下载:

Error: redirect target not allowed: .r2.cloudflarestorage.com resolves to non-public 198.18.10.72

绕过办法(curl 自己下 blob,按 ollama 磁盘布局摆好;blob 内容寻址,断点可 -C - 续传):

M=/ollama/models
curl -sL "https://registry.ollama.ai/v2///manifests/" -o /tmp/m.json # 拿各层 digest/size
curl -L -C - "https://registry.ollama.ai/v2///blobs/sha256:" \
-o "$M/blobs/sha256-" # 逐个 blob shasum -a 256 "$M/blobs/sha256-" # 必须校验:半成品会留下 -partial 假名(长度对、哈希错)
mkdir -p "$M/manifests/registry.ollama.ai//"
cp /tmp/m.json "$M/manifests/registry.ollama.ai///"
ollama list # 认出来了就成了

宿主 peer 申报规则(dsh 0.2 硬规则,2026-09-30 真机踩过)

凡 lib/ 里 import 的 @deepseek-ai/dsh-,必须写进本插件 package.json 的 peerDependencies,否则导入静默失败。

机制(dsh-app-boot/lib/index.js 的 routeLinked):link: 装进来的插件在解析裸包名时,只有当插件自己目录的 package.json 把该名字列为 peerDependency(readPeerNames),解析才会放行到宿主那份副本;否则走原生解析 → 插件目录外没有 node_modules → ERR_MODULE_NOT_FOUND。

踩坑实录:只申报了 @deepseek-ai/dsh-tools(defineTool 解析成功),没申报 @deepseek-ai/dsh-llm → createUserMessage 拿不到 → pre-step 永久降级 shadow。
插件看起来一切正常,实际功能是残的,且 catch {} 吃掉了错误。

防线:test/peers.test.mjs(11 项断言 + 突变检查)。删掉任一 peer 立刻红。

KV 缓存安全性(2026-09-30 实测 + 代码核对)

两个注入点对前缀缓存的影响不同,这是设计时就分开处理的:

| 注入点 | 内容是否固定 | 位置 | 对前缀缓存的影响 |
| 常驻段(systemPrompt.section) | 固定:只含画像 + pinned 记忆 | system 尾部 | 只要画像/置顶不变就零影响;实测新增 3 条 lesson 后仍恰好 814 字节不变量 |
| pre-step 注入(on 模式) | 每轮可变 | 追加到消息列表末尾 | 旧请求 token 序列仍是新请求前缀 → 缓存继续命中;只多付新增那 ≈120~200 token 的 prefill(一次性) |

判定方法(实证,不是推断):
- 常驻段:代码里 pinned = listEntries(...).filter((e) => e.pinned),非置顶条目不进常驻;写 3 条后 injectBytes 仍为 814 → 固定文本成立。
- pre-step:lib/prestep.js 里 messages: [...decision.messages, message](tail-append)+ source.form = "snapshot",与宿主自带 dsh-time-context 同款写法。

前提:上游必须真的返回缓存指标。实测(2026-09-30):deepseek 官方 cached_tokens=1024 稳定命中; rjk66/deepseek-v4-flash 在 1024 与 0 间抖动;默认模型 rjk66-1/deepseek-v4.1-flash 的 prompt_tokens 恒为 67 (前缀 104→5296 字符均不变)→ 该链路缓存不可观测,不要在此链路上做缓存收益结论。
vault 文件名规范(0.1.2)

镜像文件名 = 日期_短id_标题截断.md,例如 20260930_0bda49_判定上游缓存指标是否可信.md。

- 旧命名 -.md 会把 id 里已有的 slug 再重复一遍(实测最长 90+ 字符),已废弃;
- 短 id = id 末尾 6 位随机段(唯一性够用,人工扫目录更清爽);
- 一键迁移(幂等、不覆盖、不改内容,只改名;只动 vaultFolder 之内):

node scripts/vault-rename.mjs # dry-run
node scripts/vault-rename.mjs --apply # 真改

unmirror(forget 时)对新旧两种命名都能找到文件;兜底还会按 frontmatter 的 id 反查。

会话结束蒸馏(P1-3,0.2.0)

会话终局自动把"值得跨会话记住的事实"变成候选(仍要你批准才入档)。三条纪律:

1. 不阻塞会话:终局钩子只记一笔然后异步跑,异常全吞(做记忆的插件不该搞崩宿主);
2. 宁缺毋滥:条数上限 + 置信度门槛 + 与已有条目/候选去重(跨 scope 比标题,同 scope 比 bigram 相似),宁可 0 条;
3. 可核查:每次蒸馏写 append-only 审计(含模型原始输出片段):~/.dsh/memory/state/distill-audit.jsonl。

钩子面(读宿主代码确认):session/event(累积 user/message+assistant/message)→ session/disposed / workspace/session-stop 触发。
为什么自己缓冲而不是读会话日志:日志路径编码是宿主私有约定,跟着写等于和实现耦死;监听事件只依赖公开事件面。

- id: dsh-recollect
config:
distill: on # off | shadow(只写审计)| on(建候选) distillMinBytes: 2000 # 对话太短不蒸馏,避免为一句「继续」白花一次调用 distillMaxItems: 3 distillProvider: rjk66 # 用便宜的非思考模型 distillModel: deepseek-v4-flash distillMaxTokens: 2048 # 要留够:思考模型会先吃掉 reasoning 预算 distillMinConfidence: 0.6

运维:GET /recollect/api/distill 看模式/统计/审计尾部;distill: shadow 可先只看"本来会记什么"。

跨机同步(P2,0.3.0)

策略:vault 就是同步通道,不引入第二套传输。 理由是你已经有 vault 的 Git/Gitea 备份与多机可见性,而且人在 Obsidian 里改过的镜像天然就是"对方版本"——不需要再造一条同步链路。

- 本机热记忆(~/.dsh/memory)仍是本机真相;批准的记忆镜像进 60_Memory,带 origin(机器名)与 revision(内容指纹);
- 另一台机器读同一份 vault → POST /recollect/api/sync 导入;
- 三方比对(本地 × 镜像 × 上次同步基线):对面新增 / 只有对面改 → 导入;两边都改 → 报冲突、绝不自动合并;本地独有 → 永不删除;
- 覆盖前留 .bak-sync-;{"dryRun": true} 可先看会改什么,再决定。

curl -s http://127.0.0.1:3080/recollect/api/sync # 看状态与上次报告
curl -s -X POST -H "content-type: application/json" \
-d '{"dryRun":true}' http://127.0.0.1:3080/recollect/api/sync # 预览
curl -s -X POST -H "content-type: application/json" \
-d '{}' http://127.0.0.1:3080/recollect/api/sync # 真导入(非冲突部分)

记忆是长期资产:自动合并 = 自动丢信息,所以冲突一律留给人。

- memory_sync — 跨机同步:status(概况)/ preview(会改什么)/ apply(导入非冲突部分)/ resolve(裁决一条冲突)。

冲突裁决(P2-2,0.4.0)

两边都改过的条目不会被自动合并。裁决方式二选一(agent 用 memory_sync {action:"resolve", id, take},人用 API):

保留本地(并把本地版本推回 vault,让对面看到这次裁决)
curl -s -X POST -H "content-type: application/json" \
-d '{"syncResolve":{"id":"mem_...","take":"local"}}' http://127.0.0.1:3080/recollect/api/syncResolve
用 vault 版本覆盖本地(覆盖前留 .bak-sync-resolve-*)
curl -s -X POST -H "content-type: application/json" \
-d '{"syncResolve":{"id":"mem_...","take":"remote"}}' http://127.0.0.1:3080/recollect/api/syncResolve

基线分别记两侧指纹:所以"保留本地"不会被下一次同步悄悄推翻(这是测试抓出来的真 bug)。

观测(0.4.0) /recollect/api/status 的 prestep 段现在带计数:checks / hits / injected / missNoHit / skipShort / skipCooldown / errors,并真的实现了 prestepCooldownSteps(此前它只是个没人读的配置项)。prestepLogMisses: true 可把“没命中”也写进审计。
自动同步(P2-3)

- id: dsh-recollect
config:
syncOnStartup: true # 启动后自动同步一次(只导入非冲突部分) syncIntervalMinutes: 0 # 定时同步(0=关);同样只导入非冲突部分 syncStartupDelayMs: 3000 # 启动同步延迟,不阻塞 apply

语义:自动同步只做“安全的那一半”——导入对方新增/单方面修改的条目;冲突永远留给人(自动合并=自动丢信息)。

补齐镜像:POST /recollect/api/remirror

镜像只发生在“批准那一刻”,所以镜像功能开启之前批准的记忆不会出现在 vault 里。这个端点把全部在档记忆重新镜像一遍(幂等):

curl -s -X POST http://127.0.0.1:3080/recollect/api/remirror # {"mirrored":7,"total":7}

回合级蒸馏(P1-4,默认关)

session/disposed 触发很稀(可能只在会话销毁/关机时),所以加了更频繁的入口:

distillOnTurnEnd: false # 打开=每个够长的回合都可能多花一次 LLM 调用(成本先想清楚) distillTurnCooldownTurns: 3 # 回合级触发的最小间隔

触发条件是“自上次蒸馏以来又攒够 distillMinBytes 的对话”——蒸馏成功后会清空缓冲,所以它不会重复蒸同一段。

用量观测(“注入了但用上了吗”)

/status 的 prestep 里有 useObserved / useReferenced / useRate:注入之后,看 agent 的消息里有没有提到那条记忆的 id (或把 id 带进 memory_read/memory_search 的参数——tool-call 参数也在消息里,一次扫描就够)。

这是代理指标,不是因果结论:它只能告诉你“命中的东西有没有被碰到过”。但比只看注入次数强得多——如果 useRate 长期很低,说明门槛/排序需要调,或者那类记忆根本不该被注入。
运行时开关(面板「设置」页,0.6.0)

有些开关是“用的时候才读”的,改它们不需要重启:面板「忆取」→「设置」直接改,存在插件自己的 state/overrides.json(不动你的 cordis.patch.yml)。优先级:运行时 override > YAML > 默认值。

| 键 | 说明 |
| distillOnTurnEnd | 回合级蒸馏(默认关:每个够长的回合都会多花一次 LLM 调用) |
| prestepLogMisses | 把「没命中」也写进审计(默认关) |
| prestepMinScore | 注入命中门槛(分数量纲≈关键词 0~1 + 向量 0~0.5) |
| prestepMinQueryChars | 最短提问字数(短于此按续话处理) |
| distillMaxItems | 单次蒸馏条数上限 |
| injectMaxBytes | 常驻注入字节预算 |

纪律:白名单只放这类键。prestep / distill 的 off·shadow·on 模式是在接线那一刻决定的(off 直接不注册钩子),放上来改而不生效就是骗人 —— 它们仍走 YAML + 重载宿主。

curl -s http://127.0.0.1:3080/recollect/api/config # 看白名单/当前值
curl -s -X POST -H "content-type: application/json" \
-d '{"key":"distillOnTurnEnd","value":true}' http://127.0.0.1:3080/recollect/api/config
curl -s -X POST -H "content-type: application/json" -d '{"reset":true}' http://127.0.0.1:3080/recollect/api/config
事件通知:需要你行动的事,推到 QQ(0.7.0)

为什么:冲突待裁决、蒸馏产出候选这类事,以前只有打开面板才看得到 —— 记忆类工具最怕“静默失效”。

| 事件 | 触发时机 |
| conflict | 同步时发现“两边都改过”的条目(启动同步 / 手动同步 / 面板导入) |
| candidates | 蒸馏产出候选,等你批准 |
| syncError / distillError | 同步或蒸馏失败 |

防刷屏纪律:同类事件 30 分钟冷却、全插件每小时最多 5 条、只发“需要人行动”的事件;投递是 fire-and-forget(绝不拖住同步),失败只记 stats 与日志。开关在面板「设置」里一键改(notify)。

渠道默认用本机实测打通的 QQ(契约来自 im-notify 技能;微信渠道 2026-09-30 起停用,见仓库注释)。要换/加渠道就配 notifyChannels:

notify: true
notifyPort: 3080
notifyChannels:
- { name: QQ, botId: qq_..., targetId: tgt_... }

/status 与 /overview 里都有 notify 段(sent / failed / skipped / lastError),发不出去一眼能看见。

概览健康摘要(一个端点看全:GET /recollect/api/overview)把“记忆层健不健康”压成几行:注入质量(判定/命中/真注入/用上率/错误)、同步(vault 条数/待导入/冲突)、蒸馏(模式/产出候选/上次失败)、通知(已发/失败/跳过)。面板「概览」页直接显示这几行。
预览分享卡片长什么样 ↓zzdhsxk/dsh-recollect
分享 · DeepSeek Harness Hub
zzdhsxk/dsh-recollect

常驻极小画像,其余记忆按需检索并过闸门入档

这是你的仓库?认领条目

回到顶部