dsh-thinking-review · 先想清楚,再复盘
DSH 插件,四件事:
- 追问澄清(per-session 开关,带 Host 侧闸门):开了以后,你每发一条新需求,DSH 都得先提问把需求问清,问完就停——没提问就调用工具会被 Host 直接拦下,问完还接着动手也会被拦,不是只写在提示词里。你在回答它上一轮的提问时(它上一条以问号收尾),那一轮直接开工,不再重复追问。
- 复盘本会话(按钮):把这一轮问答、结论、成功经验整理成四块,再单独问你是否写入长期记忆;你同意哪几步,才写哪几步。
- 复盘经验(左侧导航新一栏):每个会话自动存成一页 PDF,后续复盘并进同一份(同样的段落只留一份),点开就能看,不用再翻对话记录。
- 经验库 + 经验优先(每三天整理一次):把复盘里的结论与经验抽成条目、去重合并;打开「经验优先」后,DSH 动手前先按本轮诉求在库里找相似场景,找到就引用编号与适用条件。
分类
| 项 | 值 |
|---|---|
| 类型 | 对话增强 / 记忆 |
| GitHub topics | dsh dsh-plugin thinking review clarify memory cordis |
| 依赖 | DSH 桌面端(web 客户端半)、cordis 插件树、Node ≥ 20 |
| 版本 | 1.8.1 |
| 仓库 | https://github.com/HoaXQuill/dsh-thinking-review |
安装
从 GitHub(无需 npm)
dsh plugin add github:HoaXQuill/dsh-thinking-review
从 npm(发布后)
dsh plugin add dsh-thinking-review
或在桌面端「插件市场」里搜 dsh-thinking-review 安装,然后重启 DSH。
从本地目录(开发时)
dsh plugin add file:C:/Users/HoaXQ/Desktop/插件/dsh-thinking-review
等价于在 profile 的 package.json 里加:
{
"dependencies": { "dsh-thinking-review": "file:C:/Users/HoaXQ/Desktop/插件/dsh-thinking-review" },
"dsh": { "profile": { "bundles": ["dsh-thinking-review"] } }
}
插件由 cordis.patch.yml 插入插件树;Host 半与客户端半由包内 exports 自动发现:
| 字段 | 作用 |
|---|---|
main / exports["."] |
Host 半:lib/index.js |
exports["./client"] |
客户端半:lib/client.js(dsh.client.platform = "web") |
dsh.bundle.patch |
插件树补丁:cordis.patch.yml |
用起来
对话输入框下面多一行:
[● 追问澄清:开/关]—— 只对本会话生效,状态存$DSH_HOME/dsh-thinking-review/state.json,刷新页面、重启 DSH 都还在。开着时带闸门:每条新需求没提问就调工具会被拒,问完还接着动手也会被拒(见下)。[● 经验优先:开/关]—— 只对本会话生效:开了以后 DSH 动手前先去经验库匹配相似场景;与「追问澄清」互相独立,可以只开一个。[复盘本会话]—— 点一下会向当前会话发一条复盘指令(不发到别的会话,也不改你的草稿)。
闸门:开着就先问再动
提示词管不住模型(实测:开关开着,仍有会话 161 次工具调用、0 次提问)。所以从 1.7.0 起多一层真闸门,1.8.0 起改成「每条新需求都必须先问、问完必须停」:
- 插件用
ctx.get('tools').guard(...)注册一个全局守卫,宿主在每次工具调用分发前同步调用它;返回字符串 = 拒绝这次调用,模型收到Error: <理由>。 - 什么样的用户消息算「新需求」:你上一条助手消息没有以提问收尾(判据:最后出现的问号之后最多只剩 ≤40 字的收尾话),且你这次没有叫停提问、也不是「收到 / 继续 / ok」这类回执。
- 叫停提问不锁字面:约 70 条同义说法都算(「不用确认了 / 直接来 / 动手吧 / 你定 / 看着办 / 就按默认 / 我信你 / 交给你了 / 少废话 / 不用再问了 / ok 直接干 / just do it」…),带插入词的宽松式(「不用再问」「无需确认」「不必讨论」)也算,反问句(「你觉得呢 / 你说怎么办 / 还有要问的吗 / 你还有问题吗」)同样算——问回来就是让我按自己的判断开工。
- 新需求回合要过两道:① 没提问就调工具 → 拦(理由「先提问,再动手」,附提问格式);② 提问之后还在同一轮里调工具 → 拦(理由「问完就停」)。所以模型这一轮只有一种走法:发一条 1–3 条编号问题的消息,然后停住。
- 你回答之后那一轮是答案回合:直接按答案开工,不再逼问——不会出现「回答一次就被反问问个没完」。
- 「复盘本会话」由按钮发出的请求不触发闸门。
- 上限:同一个回合连着被拦 8 次就放行,宁少拦一轮,也不把会话卡死。
- 子代理、没开这个开关的会话一律放行。
GET /dsh-thinking-review/gate看每个会话「要不要问(armed)、问过没有(asked)、被拦几次(blocked)」。
追问逻辑(为什么这么问)
判据来自《高阶思维:核验、修正与重构》,核心一句:追问只为降低做错概率。
- 信息价值为零就不问:如果所有可能答案都指向同一个做法,问了也不改变行动,直接做。
- 先找决策:这次请求改变的是哪个决定或交付物?说不出,就是没听懂——那是最该问的一条。
- 问了就停住等:问题发出即结束这一轮,不写代码、不改文件、不自己填默认值往下走。用户一直不回就一直等——沉默不等于同意,也不反复催问(同一轮问题只发一次)。带超时的问询卡超时≠同意,仍然停住等。只有用户明确说「按默认 / 别问了 / 直接做」才开工,并把采用的假设列出来。
- 先盘工具,再问装不装:把这件事要用的 CLI / 插件 / MCP / skill 列出来,对照手头工具清单逐项确认有没有(真去查 package.json、配置、技能目录,必要时联网搜)。缺的那个非它不可,就在提问里加一条:工具名 + 用途 + 为什么替代不了 + 装的代价(联网 / 装包 / 权限 / 体积 / 重启),问「装 / 换替代 / 先不做」。同意就装,装到项目本地优先,装完立刻最小验证并贴结果;装失败说清卡在哪,不许假装装好了。不装或装不了 → 给替代方案:现有工具组合绕过 / 降级交付 / 换实现,并把「因为缺 X,所以改成 Y」写进复述和边界行。能手拼的步骤不推销安装。
- 先扫十个「不清晰」面:目标 / 交付物与格式 / 验收标准 / 范围与不做 / 约束 / 环境与权限 / 数据与来源 / 时间与优先级 / 可逆性 / 既有约定。哪一面答不上来、且答案会改变做法,就主动提问;能读文件查到的先自己查。
- 再做一次多维扫描:同一件事在六个维度上各过一遍——对象(谁用 / 谁维护 / 谁受影响 / 谁验收)、尺度(一处 / 一模块 / 一系统)、时间(现在 / 三个月后 / 回滚)、因果(为什么做、不做怎样、真瓶颈在哪)、反证(什么证据会证明这做法是错的)、二阶(会让什么原本成立的变不成立)。每个维度都要产出一条「若成立就改变做法」的判断;产不出判断的维度,就是理解还浅、该问的地方。
- 提问门槛:默认问,不问要举证:只有当你能论证「所有可能答案指向同一做法、代价也相同」时才不问。不清晰的面 ≥ 2 条必须先问;正好 1 条也补一条轻量确认(目标 / 验收 / 范围这三面任何一条含糊都问)。拦路(不问必做错)、分岔(做法不同)、塑形(影响观感与后续维护成本)三档都算该问,不要只问第一档。用户给了新信息、换了目标、进了新模块,就重扫一遍再判断。每条问题都要能说出「答错会差在哪」,说不出的删掉。
- 至少 3 种合理解读:包括「用户没说全,是我信息不足」,每种都给一条能区分彼此的预测。
- 怎么问:问题 1–3 条(上限 5),按「答错的代价 × 不确定性」从高到低排,编号、每条一句背景 + 可选项 + 默认值,允许一句「回 defaults」;一次提问尽量覆盖不同维度,别三条都问同一个面。只是措辞级的分岔不问。
- 答前只读侦察:不边问边答、不自问自答、不给最终方案。
- 答前复述:1–3 句 spec + 「什么会让你改主意」,然后再开工。
- 交付带边界:一行写清适用范围与推翻条件。
- 叫停即开工:你说「别问了 / 直接做 / 停」,马上停,编号列出假设与边界。
子代理会话不挂这段提示词。
复盘产出
点「复盘本会话」会得到四块:
- 会话摘要(做了什么、结论是什么)
- 结论与决定(含被否决的方案与原因)
- 成功经验(可复用的做法,写清适用条件)
- 候选长期记忆 3–8 条(每条一句,可直接
remember)
最后单独一行问:全部写入 / 只写入第几条 / 不要。你明确同意后才逐条写;「不要」就停,不反复劝。
复盘经验(左侧导航)
左侧导航多一行 复盘经验,点开是本机所有会话的复盘档案:
- 一个会话 = 一条档案 = 一份 PDF。不用点任何按钮:Host 订阅
session/event,每轮把「用户诉求 + 最近回答」写进这个会话档案的「最近进展」段(覆盖式,只留最新一轮)。 - 点「复盘本会话」产出的完整复盘,作为独立一段追加进同一份档案;同一段文字再复盘一次只会更新时间,不会堆出重复段落。
- 每条显示:更新时间、会话标题(拿不到标题就显示会话 id 前 8 位)、段数(单段时显示字数)、文件类型(PDF / MD / 生成中)、摘要。
- 打开在新标签页里看那份 PDF(浏览器阅读器直接渲染)。
- 展开看合并后的全文,复制一键复制,删除要点两次确认(同时删掉文件)。
- 刷新重读列表;索引来自 Host 的
$DSH_HOME/dsh-thinking-review/reviews.json,文件在$DSH_HOME/dsh-thinking-review/reviews/<id>.pdf(<id>=session-<会话 id 尾段>,所以永远是同一个文件),重启不丢。
合并规则(防止重复与膨胀):
kind: 'latest'(最近进展)每轮覆盖,只有一段;kind: 'review'(复盘)按文字指纹去重:归一化后相同的段落只保留最新那份;- 一条档案最多留 1 段最近进展 + 11 段复盘(共 12 段)、正文硬上限 80000 字,超出丢最旧的段。
PDF 怎么来的:Host 自己渲染 HTML(微软雅黑、A4、@page 页边距),再用本机 Edge/Chrome 的无头模式打印成 PDF(--headless=new --print-to-pdf),不联网、不装任何依赖。生成是异步的,不拖住那一轮回复;打印期间内容又变了会自动重打一次,保证磁盘上是最后一版。
已知限制:
- 找不到 Edge/Chrome(或
--print-to-pdf被安全软件拦住)时自动退回<id>.md,列表显示「MD」,打开照样能看纯文本,功能不丢。 - 排 PDF 走的是本机浏览器进程:若把 DSH 装在限制子进程的环境里(例如 AppContainer),打印会失败并退回 MD。
- 一页只有 160 字以上的输出才会进档案(更短的闲聊不存档);1.1.0 之前的会话没有捕获,不会补录。
- 老会话的标题读不到(DSH 只对加载过的会话给标题),显示会话 id 前 8 位。
- 档案数上限 500 条(按会话),超出丢最旧的。
经验库(每三天整理,可以手动)
「复盘经验」页顶部有一张经验库卡片:
- 整理:启动时检查一次,之后每 30 分钟看一次上次整理时间,超过 3 天且已有复盘就重新整理;也可以点「立即整理」。
- 抽什么:只认每份复盘里「结论与决定 / 成功经验 / 候选长期记忆」(也认「结论 / 经验 / 长期记忆」)标题下的列表项,8–240 字的条目才会进库。
- 怎么去重:文字归一化后做相似度(汉字二元组 + 英文词)Jaccard ≥ 0.55 视为同一条——命中次数 +1、保留更长的表述、合并来源会话、更新时间。所以同一个教训在十个会话里出现,只有一条,命中 10 次,排前面。
- 排序:先按命中次数降序,再按最近时间;编号
l1..lN,上限 300 条。 - 落盘:
$DSH_HOME/dsh-thinking-review/lessons.json(程序读)+lessons.md(人读,方便你自己翻或让别的工具检索)。 - 检索:卡片里有输入框,回车按关键词过滤(走
GET /lessons?q=),排序 = 相似度 + 命中次数加成。
整理是规则抽取,不是让模型总结:Host 半拿不到模型,所以只做确定性的抓取、归一化与合并——不会写出复盘里没有的结论。
经验优先(per-session 开关)
打开后,本会话额外挂一段提示词(order 89960,与追问澄清的 89950 各自独立):
- 四条规则:①先在这份经验库里找相似场景,再看当前情况;②经验是先验不是证据,与当前事实冲突时以事实为准,并在回答里说明冲突;③不要为了用经验而套——只有真的相似才引用,引用时带编号与适用条件;④经验库里没有相似场景就直接说没有,不许编。
- 选哪些:按「最近一条用户消息 + 会话标题」与条目做 token 相似度排序,取前 8 条(每条截断 160 字);空库时明确写「经验库是空的,不要编造经验」。
- 收尾自检:回答末尾检查一遍——引用的经验是否都写清了适用条件、有没有把经验当事实、发现新经验要不要建议复盘。
子代理会话同样不挂这两段提示词。
HTTP 接口
Host 半注册在 /dsh-thinking-review:
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /dsh-thinking-review/state?session=<id> |
{ok, session, enabled} |
| POST | /dsh-thinking-review/state |
body {session, enabled},写入并立即挂载/卸载 |
| GET | /dsh-thinking-review/text[?session=<id>] |
当前进程实际生效的提示词(诊断用;带 session 时含经验优先那段) |
| GET | /dsh-thinking-review/mounted |
已挂载的会话列表、状态文件路径、复盘条数、闸门状态 |
| GET | /dsh-thinking-review/gate |
闸门现状:每个会话 {armed, asked, blocked} + 两段拒绝文案(ask / stop) |
| POST | /dsh-thinking-review/reviews/request |
body {session},登记「这一轮要收进复盘」 |
| GET | /dsh-thinking-review/reviews |
复盘列表(不含全文),附正在等待的会话 |
| GET | /dsh-thinking-review/reviews/item?id= |
单条复盘全文 |
| GET | /dsh-thinking-review/reviews/file?id= |
复盘文件本体(application/pdf 或 text/markdown,?download=1 改成下载;文件还没生成完返回 409) |
| POST | /dsh-thinking-review/reviews/delete |
body {id},删一条 |
| GET | /dsh-thinking-review/experience/state?session=<id> |
{ok, session, enabled},经验优先开关 |
| POST | /dsh-thinking-review/experience/state |
body {session, enabled} |
| GET | /dsh-thinking-review/lessons?q=&limit= |
经验库列表(updatedAt / lastDigestAt / digestCount / total) |
| POST | /dsh-thinking-review/lessons/digest |
立即整理一次经验库 |
开发
node test/smoke.mjs # Host 半:路由、挂载、卸载、判据关键字
node test/client-smoke.cjs # 客户端半:slot 注册、按钮、指令落到会话
node test/smoke.mjs && node test/client-smoke.cjs # 或 npm test
两个脚本都不依赖 DSH 运行时:Host 半用假 ctx(agents / webServer / effect / interval),客户端半用假 window.__ModuleLoader__ 与极简 React shim。
改完代码要生效:重启 DSH(改 .js 不会热重载;桌面端点插件市场里的「立即重启」)。
兼容与备注
- 状态文件与旧名
dsh-clarify兼容:新文件不存在时读$DSH_HOME/dsh-clarify/state.json,下次写入即迁到新路径。 - 只对主会话生效,子代理一律跳过。
- 卸载不会删你的状态文件;想清空就删
$DSH_HOME/dsh-thinking-review/state.json。 - 提示词优先级最低(order 89950),不会盖住项目自己的 AGENTS.md 或系统提示。
No comments yet. Be the first to write one.