# dsh-daoing-memory 设计说明 [English →](./DESIGN.md) 本文说明**这个插件是干什么的**、**结构背后的思路**,以及**治理它的理念**。 --- ## 1. 作用 LLM agent 在会话结束的瞬间就忘光一切。常见的补救——把对话灌进向量库,或让模型随手往键值块里写——都会很快退化:一个让信号淹没在噪声里,另一个让一次幻觉污染此后所有会话。 `dsh-daoing-memory` 的目标,是给 DSH agent 一套**随使用而变好、且始终可信**的持久记忆。具体来说它提供: - 一本 agent 在会话中随手写的**日记**(原始、廉价、低信任)。 - 从日记蒸馏出的**语义记忆**:关于用户的持久*事实*,以及用户在意的*关心事项*。 - **经验记忆**:带信任生命周期、可复用的 how-to 知识。 - 在未来的会话中**召回**相关经验。 - 一本**账本**,记录每一次变更,使记忆可审计、可回滚。 - 一个**工作台**,让人能阅读并治理以上一切。 全部记忆存放在一个**进程级全局**的 SQLite 库里,被所有会话共享——记忆随 agent 的整个生命周期累积,而不是按对话各自为政。 ## 2. 四个字:生 · 用 · 修 · 记 整套设计围绕四个字组织,每项能力都明确归属其一。 | 字 | 含义 | 能力 | | --- | --- | --- | | **记** | 先廉价地捕捉原始信号,暂不评判。 | `memory_fact`(追加日记)、账本。 | | **生** | 把原始信号蒸馏成结构化记忆。 | `memory_extract`(事实 + 关心事项)、`memory_ingest`(外部 → 经验)。 | | **用** | 把合适的记忆带进下一个会话。 | `memory_recall`、画像快照注入。 | | **修** | 当现实与记忆不符时修正它。 | `memory_report`、`memory_revise`、`memory_refine`、`memory_verify`、回滚。 | 这样划分很重要,因为每个字的信任姿态不同:记录廉价而宽松,提炼要有选择性,使用以读为主,而修订是唯一会*删除或降级*的路径——因此守卫最严。 ## 3. 两种记忆,刻意分离 一个核心决定:**语义记忆**与**经验记忆**是两种不同的“物质”,绝不混在一起。 **语义记忆(事实 + 关心事项)** 描述*用户及其世界*。它是陈述性的、变化缓慢、并被主动注入。事实归属于九个以用户为中心的类别之一;关心事项带一个 `kind`(todo / 思考 / 想法 / 问题 / 决定 / 承诺 / 其他)和一段**背景**场景,让 agent 知道用户*为什么*在意。 **经验记忆** 描述*什么管用*。每条经验是一个修订族(family),携带信任状态与使用记录。经验按相关性**按需召回**,而非整段注入。 把两者分开,治理方式才能贴合内容:事实需要去重与佐证,而经验需要靠使用证据来晋升与降级。 ## 4. 记忆必须靠挣 信任模型是整套设计的心脏。 - 一条经验**以候选身份诞生**(低信任)。它不会因为被写下来就自动“成真”。 - 每当 agent 使用一条经验并上报结果(`memory_report`),证据就累积一分。反复成功就**晋升**;上报失败就**降级**。 - 因此晋升是*从真实使用中挣来的*,绝不是被宣称的。一条听起来合理却没用的经验会停留在低信任,最终变冷。 - 同样的证据链意味着:一条被投毒或错误的经验可以被*降级并回滚*,而不是被默默信任。 这正是对“一次幻觉污染一切”失败模式的正面回答:**写入廉价,但信任昂贵且可收回。** ## 5. 事实:去重并累积佐证 当提炼出的事实与已有事实匹配(相同类别 + 键 + 值)时,存储**不会**新增一条重复,而是累加一个**佐证**计数、合并来源日记 id。于是反复被观察到的事实变得更坚实,一次性的保持轻量。这让事实表保持紧凑,也让画像快照更有意义。 ## 6. 每次写入都可审计 所有变更都追加进一本**只增不删的账本**(`memory_ledger` 查询、`memory_verify` 校验完整性)。账本里没有“就地修改”,更正本身就是一条新记录。这带来: - **归因** —— 能看到某条记忆由哪条日记/哪个会话产生。 - **漂移检测** —— 能察觉记忆是否被往某个方向“带”。 - **回滚** —— 因为先前状态仍在,一次坏修订可以被撤销。 可审计是一等设计目标,而非事后补丁:一套会自我修改的记忆,只有在其修改可被检视时才是安全的。 ## 7. 人始终在回路中 记忆是人机共享的资产。浏览器**工作台**提供: - **事实日记** —— 原始日记与蒸馏出的事实/关心事项(带筛选,关心事项的*背景*内联展示)。 - **经验** —— 带信任状态与使用记录的经验库。 - **账本** —— 审计轨迹。 - **人工运维** —— 手动晋升 / 降级 / 置顶 / 编辑 / 删除。 人工操作同样记入账本,因此人的编辑与 agent 的编辑共存于同一份可审计的历史。 ## 8. 召回:相关性,与可选的范围限定 `memory_recall` 按**关键词/情境相关性**对查询给经验排序。经验库是**进程级全局**的——默认情况下每条经验都是每个会话的候选。召回请求可以可选地传一个 `context`;一旦传了,候选就被限定为带该 context 或标记为全局的经验。这是*可选的收窄*,不是硬墙:不传 context 时什么都不过滤。 ## 9. 画像注入:无需发问就了解用户 每次运行时,插件构建一份精简的**画像快照**(头部事实 + 未了心事),并作为一个专门段落注入系统提示词。效果是:agent *本就已经知道*稳定的用户事实与未了事项,不必花一次工具调用去发现——而完整、细节的记忆仍可按需查询。 ## 10. 数据模型(schema v5) 存储是单个 SQLite 库(`memory.db`),本质上包含: - `diary` —— 原始条目(只增不删的基底)。 - `facts` —— 蒸馏出的用户事实(类别、键、值、佐证数、来源日记 id)。 - `concerns` —— 未了事项(kind、status、title、**background**、context、树形父节点)。 - `experiences` —— 经验库(family id + 修订号、信任状态、使用记录、context)。 - `ledger` —— 只增不删的审计轨迹。 - 一张 `schema_version` 表驱动**增量迁移**(v5 为关心事项新增 `background` 列)。 迁移只做加法(绝不破坏),因此升级插件绝不丢失记忆。 ## 11. 防投毒边界 几条规则让记忆不至于被轻易投毒: - 写入从**低信任**起步;信任靠挣、可收回(§4)。 - **账本**让每次写入可归因、可撤销(§6)。 - **提炼由 skill 引导**,推动 agent 记录“用户感知到的事实”与“未了事项”,远离臆测噪声。 - **人工运维**可以推翻任何东西,且推翻本身也被记录。 ## 12. 我们刻意*没做*的事 - **不做向量库。** 召回是在一个经过治理、可信的库上做关键词/情境相关性匹配——而不是在一堆无差别 dump 上做相似度。(向量辅助召回是扩展方向,不是基础。) - **不做自动删除。** 遗忘是显式的(人工或整合),绝不静默发生。 - **不做跨 agent 的共享语义。** 库是单进程全局存储;多租户隔离不在 v1 范围。 这些都是**以信任与可审计为先**、而非以检索规模为先的自觉取舍。扩展方向见 [STATUS.zh-CN.md](./STATUS.zh-CN.md)。 --- ## 13. 特殊通道:人工注入经验(memory_human_inject) 常规经验来源是 agent 在会话中通过 refine/ingest 生成。除此之外,还有一个**人工注入通道**,供作者把经核实的高价值经验直接写入,落地即 `live` 且记入账本。 ### 触发方式 在 DSH 会话里发一句提示词,让 AI **调用 `memory_human_inject` 工具**即可——**无需**找 HTTP/RPC 端点、**无需**读 client.js / remote-client。 ### 参数 `kind` / `family` / `gist` / `situation[]` / `path[{order,action}]` / `reasoning` / `limits[]` / `failureReason?` / `context?` / `reason`。 ### 落库语义 - `source=human`、`status=live`、信任地板(`alpha=5, beta=2`); - 每次写入 append 审计账本,`verifyLedger` 可校验。 ### 局限:无 globalFlag `memory_human_inject` 工具**没有 globalFlag 参数**(`humanAddExperience` 硬编码为 false)。因此: - 注入的**跨域(global)**经验默认只对当前作用域生效,必须注入后用 `humanEditExperience({ globalFlag: true })` 补设; - 补设后须再跑 `verifyLedger` 复核账本完整。 > 实测基准:0.1.19 已通过该通道成功写入三条经验,并满足 `verifyLedger {ok:true}`。