前言¶
给智能体加长期记忆,常见做法是让它在会话里多记一点:每轮结束后把对话存成一段摘要,下次开聊时塞回上下文。这种做法的麻烦不在存储,而在出问题之后——你看到记忆里写着一条判断,却不知道它从哪次对话来、和上一版有什么差别、被哪一次改写覆盖了。模型「记错了」的时候,通常没有任何地方留下痕迹。
下面介绍的 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,插件为此换来的是零依赖和不出站。
几点需要留意:
- 插件以当前 dsh 进程的权限运行,装之前先读一遍源码、确认许可证(MIT)与信任模型是否符合预期。
- 版本兼容性是逐版本声明的,
0.2.1-rc.4与0.2.2-alpha.2状态为 unknown,升级 DSH 前先对照 README 的兼容表。 - npm 包名(
@bangbang-03/dsh-memory)与仓库名(dsh-memory-portrait)不一致,装错或找不到包时先确认用的是哪个名字。 - 数据默认落在
~/.dsh/storages/dsh-memory,导出与镜像(.dsh-memory/MEMORY.md)是另一条通路,两者不要混用。 - 该项目是社区维护,与 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/