Memory Portrait(dsh-memory-portrait):有证据、有版本、能解释变化的记忆

前言

给智能体加长期记忆,常见做法是让它在会话里多记一点:每轮结束后把对话存成一段摘要,下次开聊时塞回上下文。这种做法的麻烦不在存储,而在出问题之后——你看到记忆里写着一条判断,却不知道它从哪次对话来、和上一版有什么差别、被哪一次改写覆盖了。模型「记错了」的时候,通常没有任何地方留下痕迹。

下面介绍的 bangbang-03/dsh-memory-portrait 就是针对这一层的插件。它不追求记住更多,而是把记忆做成一份可查看的画像:每段判断挂证据、版本之间可以 diff、源失效了沿派生链标脏。用作者自己的话说,「不是记住更多,而是让你看见它怎么理解你」。

这是什么

Memory Portrait 是 DSH(DeepSeek Harness)的社区插件,维护者是 BangBang-03,npm 包名为 @bangbang-03/dsh-memory,仓库已改名为 dsh-memory-portrait(安装命令不变)。它解决的问题是:工作区级长期记忆的可解释性与可控性——记忆从哪来、被谁改过、能不能撤回。

当前版本 0.6.7,许可证 MIT,零运行时依赖(dependencies 为空,只用 fs 与回环 HTTP)。官方描述里明确列出的能力包括:索引简报省 token、轮末本地召回、红线 / 审批队列 / 版本链 / 注入审计,且不 shell、不读环境变量、不启子进程、不出站、不加载动态代码。

它属于 DSH 生态的第三方插件。社区目录是独立站点,与 DeepSeek / 幻方没有官方从属关系。

记忆在什么时机进出上下文

插件把记忆的通路拆成了几条,触发时机各不相同:

通路 触发时机 做什么
简报 会话开始 briefMode: index 时一行一条索引;正文按需用 memory 工具取
memory 工具 任何时候 save / search / sessions / promote / list / get / update / forget / stats
轮末召回 turn/end 对当轮用户消息做本地检索,命中项在下一轮尾部注入;纯本地,0 token
路径召回 工具触达 files 相关记忆在下一步尾部注入;优先级为全路径 > 目录后缀 > 同名
自动提炼 轮次结束(可选) 把对话提炼成结构化记忆;captureMode: draft 时先进审批队列
Dream / 画像 启动 + 轮末到期检查 合并重复簇、报告矛盾、报告过期;画像按小时自动刷新

简报的排序不读 useCount 与当前时间,日期戳只用 createdAt,并且会话级冻结。这样做的目的很具体:同一会话的系统提示不会逐轮变化,prompt 前缀缓存不会因为记忆更新而整段作废。

画像与账本

「画像」是主视图,不是一句总结。配套机制保证它不会退化成模型随手写的小抄:

机制 作用
红线 绝对禁令逐字置顶;模型不能删除或归档;改稿留 20 版历史,可回滚;保存前查冲突
审批队列 captureMode: draft 时草稿对简报 / 检索 / 镜像 / 导出都不可见,批准后才生效
版本链 supersedes 旧条归档不删除,新旧互指;支持一键回滚
注入审计 每次进 prompt 的正文 hash + 记忆 id + 被预算挤掉的条目,append-only
派生链 记忆 → 画像 → AGENTS.md 每层记录源快照,源失效沿链标脏
整库快照 每天首次写入与每次 Dream 前各备份一次,轮转 7 份
写入安全 密钥扫描脱敏(命中替换为 [REDACTED:*]);非 user 来源命中注入模式时隔离成草稿

几个刻意的取舍也写在 README 里:检索用本地 BM25F + 精确短语 + 同义词 + 路径召回,不引入向量服务;索引简报省 token,代价是模型要多一步 get;没有常驻定时器;Dream 只报告矛盾、不自动归档,避免词法误报。

安装与启用

官方给出的安装命令有两种。web profile 用一条命令即可,/latest/ 永远取最新稳定版,不需要 clone,也不需要 npm:

dsh plugin --profile web add "https://github.com/BangBang-03/dsh-memory-portrait/releases/latest/download/dsh-memory-latest.tgz"

npm 方式等价(npm 源与 Releases 同源;如果 npm view @bangbang-03/dsh-memory version 低于 Releases,用上面那条):

dsh plugin --profile web add @bangbang-03/dsh-memory

桌面端不能用 dsh plugin --profile desktop(desktop profile 由 Electron 独占),需要下载仓库里的 install.ps1,在任意目录执行:

pwsh -File install.ps1 -FromRelease -Channel stable

脚本会下载最新稳定版 tarball、解包到 ~/.dsh/plugins/dsh-memory,再完成垫片 / profile 清单 / junction 三步。更新就是重跑同一条命令;回滚执行 pwsh -File uninstall.ps1(记忆数据保留,-PurgeStorage 才会删 ~/.dsh/storages/dsh-memory)。

装好后打开设置 → 记忆。宿主路由是 /memory/api,只监听回环地址;客户端用 new URL("memory/api/…", document.baseURI) 解析,反代前缀或 dsh-app:// 外壳下也能到达。

兼容性

README 明确声明了逐版本兼容性,未测试版本不冒充 compatible:

DSH 版本 状态
0.2.0-rc.2 compatible
0.2.1-rc.3 compatible(当前桌面版)
0.2.1-rc.4 unknown(未测试)
0.2.2-alpha.2 unknown(未测试)

Node 要求 ^22.19.0 || >=24.0.0;DSH 范围 >=0.2.0-rc.2 <0.2.1-rc.4。DSH STORE 会按 dsh.compatibility.dshReleases 的逐版本声明判断安装资格。

配置与典型用法

面板里能改的项都落在 ~/.dsh/storages/dsh-memory/settings.json,cordis.patch.yml 里的 config 只是初值。常用开关如下(完整清单见 README 配置表):

键 默认 说明
enabled true 总开关
autoInject true 注入总闸:关掉后简报 / 轮末召回 / 路径召回都不进上下文,memory 工具照常读写
directory "" 数据库位置,空 = ~/.dsh/storages/dsh-memory
disabledWorkspaces [] 停用自动记忆的工作区(绝对路径),不注入、不自动提炼;事故排查时用它把一次性工作区摘出去
briefMode "index" index 一行一条;full 标题+正文摘录;portrait 全局画像全量 + 索引清单
briefingLimit 12 注入条数上限(1–50)
turnRecallLimit 3 每轮召回条数(1–10)
rewriteMode "direct" direct 直接落库;draft 先存待审稿,面板批准后才生效
captureMode "direct" 同上,控制自动提炼的入口
autoCapture false 轮次结束自动提炼
autoDreamDays 7 启动整理间隔;0 关闭
autoPortraitHours 6 自动刷新全局画像的间隔;0 关闭
dedupe true 保存时合并相似记忆
qualityGate true 低分条目(<30)直接归档,不进简报
redactSecrets true 写入时密钥扫描与脱敏
quarantineTainted true 非 user 来源命中注入模式时自动隔离成草稿
pathRecall true 路径 JIT 开关
sessionSearch true 每轮用户发言原文落 sessions.jsonl,action=sessions 溯源
compactionSalvage true 宿主压缩上下文时,把摘要照录进当天工作日志
captureSubagents false 子代理会话是否参与自动提炼;默认否,避免把派活的中间过程写成记忆
falsifierReviewDays 90 带失效条件的记忆默认多少天后进复审队列(1–3650)

HTTP 契约:/memory/api 前缀,成功 {ok:true,…},失败 {ok:false,error,detail?};请求体超 4MB 回 413 payload_too_large;显式传入的 workspace 必须是已注册工作区,否则回 400 invalid_workspace。

「只用工具」的用法是把 autoInject 关掉:上下文里完全不出现记忆,memory 工具仍然可以手动读写。排查事故时,用 disabledWorkspaces 把出问题的一次性工作区摘出去,也是同一思路。

如果你之前用的是 WorkBuddy / Qoder / Claude Code / Codex / Windsurf,可以在设置 → 记忆 → 从本机既有记忆导入里做只读扫描,按来源打标签;也可以直接粘贴 /export 的 JSON 或 Markdown。导入有新增时会后台触发一次画像重写(feedPortrait: false 可关)。

适用场景与注意

适合这几类人:已经在用 DSH 的工作区需要长期记忆、希望知道记忆从哪来的人;把记忆当作会变化的工程产物而不是黑盒的人;对「自动多记一点」不放心,想保留否决权的人。不适合想要语义检索的人——本地 BM25F 的语义泛化弱于 embedding,插件为此换来的是零依赖和不出站。

几点需要留意:

  1. 插件以当前 dsh 进程的权限运行,装之前先读一遍源码、确认许可证(MIT)与信任模型是否符合预期。
  2. 版本兼容性是逐版本声明的,0.2.1-rc.4 与 0.2.2-alpha.2 状态为 unknown,升级 DSH 前先对照 README 的兼容表。
  3. npm 包名(@bangbang-03/dsh-memory)与仓库名(dsh-memory-portrait)不一致,装错或找不到包时先确认用的是哪个名字。
  4. 数据默认落在 ~/.dsh/storages/dsh-memory,导出与镜像(.dsh-memory/MEMORY.md)是另一条通路,两者不要混用。
  5. 该项目是社区维护,与 DeepSeek / 幻方无官方关系,安装资格判断由 DSH STORE 按声明执行。

结尾

Memory Portrait 的价值不在于记得更多,而在于每一条被记住的东西都有来源、有版本、能解释、能撤回。如果你的痛点是「记错了找不到人」,可以从设置面板里的审批队列和注入审计看起。

  • 目录页:https://www.skillhub.cn/plugins/BangBang-03/dsh-memory-portrait
  • GitHub:https://github.com/BangBang-03/dsh-memory-portrait
  • 项目主页:https://bangbang-03.github.io/dsh-memory-portrait/
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜