Aik358/dsh-memory-fitting ↗★ 1
@a9i5k4/dsh-memory-fitting
Intent fitting for DSH: the agent predicts several directions first, asks a batch of clarifying questions each round, narrows the distribution until one converges, then proposes it for your confirmation. Bottom-right floating panel, local JSONL archive, and both context injection and memory writes behind independent opt-in switches. 记忆拟合:AI 先预定若干方向(预测你的意图),每轮批量提问,轮间思考并展示方向可信度,收敛后提案待确认。右下角悬窗 + 本地留档;上下文注入与记忆写入各自独立开关,默认关闭。 适合希望AI在执行前先澄清需求、减少误解并沉淀本地记忆的用户。
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Aik358/dsh-memory-fittingドキュメント
README 全文を読む ↗先问清楚,再动手 · 记忆拟合
dsh-memory-fitting — It asks before it acts.
中文 你先别急着说清楚,让它先猜。猜错了你纠正,比从头描述便宜得多。 EN The agent predicts a few directions first, then asks in batches until one converges.
这是什么
大多数时候,卡住我们的不是"不会做",是"说不清要什么"。
你丢给 AI 一句「帮我把这块弄好一点,感觉不太行」,它只能靠猜。猜对了是运气,猜错了就是一轮返工。空转的 token 和你的时间,都花在猜上。
记忆拟合把顺序换了一下:
不让 AI 猜,让它先立靶子,再问你。
它先写下 3-5 个"你可能想要的方向",然后针对这些方向之间还分不开的地方批量提问。你每答一轮,它就重算一次各方向的可信度,并把更新后的方向列表摆在你眼前。收敛到足够清楚时,它给出提案:「我理解你要的是 X,对吗?」
你不需要描述需求,只需要纠正它的猜测。 而纠正的成本,远低于从头描述。
它是怎么工作的
① 预判 AI 先写下 3-5 个"你可能想要的方向"
(每个方向都写清:它是什么、如果成立会有什么表现)
↓
② 出题 针对"方向之间的差异"设计本轮 2-4 个问题
不问已知的;问题要能分开当前还分不开的方向
↓
③ 问一批 await ctx.userQuestions.ask({ questions: [...] })
一次问一批,一次拿回全部答案
↓
④ 思考 消化本轮全部回答 → 更新方向(升降 / 淘汰 / 新增 / 合并)
【并展示给用户】← 这一步不能省
↓
某一方向明显领先且稳定?
│ │
否 是
│ ↓
└──► 回到 ② ⑤ 提案:我理解你要的是 X(附上落选方向)
↓
⑥ 你确认 → 归档
第 ④ 步的"展示"为什么不能省
| 没有展示 | 有展示 | |
|---|---|---|
| AI 的结论 | "我懂了"(不可验证的自我报告) | "我认为方向 3 领先,方向 1 已排除"(可验证) |
| 你要做的 | 等结果,错了才发现 | 一眼看出它想歪没有,当场纠正 |
把 AI 的理解摆在明处,是这个插件和"AI 随便问问然后说懂了"的唯一实质区别。
界面
右下角悬窗:设置页(默认)· 留档浏览 · 发起拟合。
位置策略:独立列,不与任何插件打架
DSH 的右下角本来就是一摞(dsh-cua 与 Ark9Canvas 都用"探测对方 FAB"来栈叠,但互不感知):
| 插件 | FAB | 面板 |
|---|---|---|
| dsh-cua | right:16 bottom:96 | right:16 bottom:152 |
| Ark9Canvas | right:16 bottom:96|148 | right:16 bottom:152|204 w-440 |
| 本插件 | right:16 bottom:16 | right:472 bottom:16 · 高 min(78vh,660px) |
本插件的 FAB 在摞的最底部;面板移到右侧那一列的左边,纵向拉满 —— 与 right:16 那一列完全错开,无论对方开不开面板都不会重叠。窄屏(-.jsonl 拟合全过程(append-only,绝不重写)
sessions/index.json 索引(可重建)
**过程存自己、结论进记忆。** 完整问答轨迹落在本地 JSONL,不受任何外部插件的容量整理影响;只有收敛结论才按 `writeMemory` 开关决定是否写进记忆插件。
> 这些留档不只是日志 —— 它们是**训练就绪**的样本。见 [训练路线图](https://github.com/Aik358/dsh-memory-fitting/blob/49cc88a64f27ba1294edce935a32655c17c56feb/docs/TRAINING.md)。
### 这些数据将来能干什么
每次拟合都在积累「同样的模糊输入下,模型给了 X,用户纠正成 Y」的样本 —— 这正是偏好优化(DPO / ORPO)最想要的形状。
悬窗「留档」页会显示**纠正率**:
- 纠正率高 → 模型经常猜错 → 样本含金量高
- 纠正率低 → 模型本来就猜对 → 样本接近噪声
**一键导出**:留档页点「导出偏好对」复制到剪贴板,或命令行 `npm run export`。
~~~bash
node scripts/export-training.mjs --intent-only --out pairs.jsonl
~~~
导出格式:
~~~jsonc
{ "prompt": "...", "chosen": "...", "rejected": ["..."], "verdict": "accepted", "scope": "intent" }
~~~
> `--intent-only` 不是可选项,是**必须**:训练时只能取 `scope=intent`。详见[训练路线图](https://github.com/Aik358/dsh-memory-fitting/blob/49cc88a64f27ba1294edce935a32655c17c56feb/docs/TRAINING.md)。
---
## ⚠️ 记忆写入安全带
`src/node/sanitize.js` 对**所有**要写进记忆插件的内容做**字符级改写**。
**背景**:dsh-auto-memory 的写入侧**不过滤**待写入正文(`appendAnchoredRecord` 只对已有文件内容跑 `parseAnchors`)。正文里一旦出现 HTML 注释形式的 memory 锚点起始序列,该文件其后**所有**记忆写入全部被 fail closed 拒绝 —— **整个记忆文件锁死**。
**关键:转义无效。** 反引号、代码块、HTML 实体统统不认。**必须改写措辞。**
因为拟合记录**天然包含用户原话**,本插件在归档前强制过 `guard()`。这也是"用户原话只进本地 JSONL、只有改写后才进记忆"的原因。
---
## 安装
```bash
dsh plugin --profile web add @a9i5k4/dsh-memory-fitting
或手动:把包链接到 profile 的 node_modules,并在 dsh.profile.bundles 里加上 @a9i5k4/dsh-memory-fitting。
改完 host 侧代码需要重新 node build.mjs 并重启 dsh web。
开发
npm install # 只有 esbuild 一个构建依赖
npm run build # → lib/index.js (node) + lib/client.js (browser)
npm test # 51 项回归
npm run verify # 产物依赖面与安全自检
设计上的几个硬约束
- 拟合只能由会话根代理发起:传了
agent的子代理会撞DELEGATED_CALLER。本插件把agent作为可选透传,走全局 waterfall 兜底。 ctx.userQuestions不写进inject:它是可选能力,缺失时应降级而不是整个插件加载失败。- 上下文注入用祈使式 + 触发条件,不是描述式。模型对"背景资料"与"必须执行的约束"处理深度不同,同样的 token 数后者影响大得多。
- node 侧零外部包依赖,client 侧零
require—— 彻底规避"漏一个 require 整个插件加载失败"。
缘起
这个插件移植自一个 SSVEP 脑机接口项目的「意图拟合」环节。
在那个场景里,用户是瘫痪人群,唯一能表达意图的通道是脑电——系统不能等他把需求说清楚,只能反复给出少量候选,靠每次选择反推意图,逐步收敛。
把它推广到日常:当一个人的输出带宽很低(说不清、没想明白、或者就是懒得说),而 AI 的先验又很宽时,"先立靶子再问"比"直接猜"要省得多。
License
MIT © Aik358