- Home
- Plugins
- Usage & Billing
- dsh-reasoning-distill
dsh-reasoning-distill
huhu23333/dsh-reasoning-distill
Distill over-long model reasoning into its useful core, replay the compressed version on every later request, and report each session's cost and savings. Disabled by default: select one rewrite backend first. derive needs no install and works on packaged DSH; in-place needs 14 source patches and a rebuild (recommended for source checkouts); message-edit needs a third-party plugin and is experimental only.
Install
dsh plugin --profile web add github:huhu23333/dsh-reasoning-distillREADME
dsh-reasoning-distill
把过长的模型思考压缩成核心内容,之后每次请求都重放压缩版,省下重复发送的 token;同时给出每个会话的开销与节省报告。
⚠️ 适用场景
已实测确认:之前轮次的思考内容会随之后的每一次请求重新发送,并且模型能看到它们。原因是 DSH 的请求一般情况下始终携带 tools,而这种带 tools 的请求会把之前轮次的 reasoning 一并拼接进上下文。因此一段被压缩的思考不只在产出它的那一轮里节省,而是会在之后所有仍携带该消息的请求中持续节省,直到宿主的上下文压缩把这条目标淘汰。(该结论在 DeepSeek 路由上实测;其他 provider 是否会回传历史 reasoning、以及是否计费,取决于其 adapter,报告中的节省始终是估算值。)
收益最集中的仍是 「单轮次、多步工具调用的超长单轮对话」:同一段压缩后的思考在每一步都要重发,节省累积最快。「多轮问答」同样会持续节省(跨轮次的重放也计入),只是每轮通常只有少量请求;如果压缩版很快被上下文压缩淘汰,它可能只被重放少数几次,未必抵得上一次蒸馏的开销。是否划算取决于压缩版还能被后续请求重放多少次。
总开关只停止新的蒸馏:已经生效的压缩版仍会继续替换(这是刻意语义,避免中途改变已发前缀);要真正回到原文,需停用/卸载插件,或删除对应会话的 sidecar 记录(in-place 已写进日志的改写需回退宿主补丁并从日志恢复)。
实验依据:deepseek-reasoning-experiment(API 行为实验、计费实验、复现脚本,以及 DSH 实际发送路径的源码审计与代理抓包验证)。
插件默认关闭,装好后需要在「设置 → 思考压缩」里选中一个改写后端并手动打开总开关。
版本与安装方式(先看这里)
- 可能适配的 DSH 版本:
0.2.0-rc.1~0.2.1-rc.3。其中0.2.1-rc.2与0.2.1-rc.1的补丁目标文件、公开 API catalog 逐字节相同;0.2.1-rc.3已在更新后的宿主机上实际运行 in-place 后端(补丁--check输出PATCHED)。明细见下文「经过测试的 DSH 版本」。- 已知可以正常运行 in-place 后端的版本:
0.2.1-alpha.1、0.2.1-alpha.5、0.2.1-rc.3。- 想要全部功能与最佳体验,请使用从源码构建的 DSH(clone 官方仓库后从源码运行或构建)。从 npm 直接下载的版本和第三方打包版(例如 dsh-desktop)无法给宿主源码打补丁,in-place 后端用不了,优先改用无写入的
derive;message-edit 仅实验性,不推荐。
一、它做什么
- 监视每次模型输出里的思考内容(reasoning),并估算其 token 数。
- 某一步的思考超过该模型的触发阈值(默认 4000 token)时,把这一步的思考(可选附上工具调用与结果)交给蒸馏模型(默认
deepseek-official/deepseek-flash,思考强度 off)改写成更短的版本。压缩的是措辞和冗余,不是推导过程:有效、正确的思考步骤必须保留,不能直接跳到结论。 - 压缩发生在下一步请求之前,下一步会等它。等待上限由该模型的超时决定:到点就放弃这一次压缩(原始思考不动;这次尝试的蒸馏开销仍会以失败记录出现在报告里);填 0 表示不设限、一直等到出结果。
- 只有压缩结果至少能省下最低节省(默认 600 token)时才真正采用,否则只花钱、不替换。
- 被采用的压缩版会替换"模型看到的思考内容",因此之后每个请求都少带这些 token;会话日志里的思考原文保持不动,本插件的账本存放在会话日志旁边的 sidecar 文件里。
- 由宿主 Fork/复制出来的会话会继承父会话账本中位于复制前缀内的改写;分支后端创建的副本也一样。否则换了 session id 的副本没有账本,
derive模式会退回原文。 - 「思考压缩」标签页显示:触发次数、蒸馏开销、已采用次数、当前单次请求减量、历史累计节省、净收益,以及最近一步"为什么没有触发"。有压缩正在运行时,还会显示它当前所处阶段(准备蒸馏 / 蒸馏模型生成中 / 保存压缩记录 / 写回交接)和在该阶段停留的时长;在"写回/交接"之前可以点「取消」手动中止这次压缩。
三种会话有各自独立的开关:主对话、可续聊子代理(例如队友)、一次性子代理(跑完即结束的委派)。默认只对主对话开启;可续聊子代理、一次性子代理、附带工具调用结果、压缩最终回答轮默认都关。
关于"缓存断裂":改写被放在该思考块第一次被重放之前,所以正常情况下这一步本来就是缓存未命中,不额外产生缓存断裂开销,报告里的 cacheBreakTokens / cacheBreakCost 恒为 0。少数回退路径(sidecar 读失败后恢复、写回失败留给轮询补写、插件停用后宿主仍持有压缩版)会让改写点之后的整段重新按未命中计费,这时报告会高估净收益。
二、助手消息改写后端:三选一
本插件只负责"算出压缩版";把压缩版交给会话需要一个改写后端。三个后端里选中一个,否则总开关会被强制关闭并锁定;其中 derive 不需要任何安装或补丁。
怎么选:
- 能打补丁、也愿意给 DSH 源码打补丁 → 优先
in-place:最干净,不新建会话、不产生分支。 - 不能或不想打补丁(例如打包版 dsh-desktop)→ 用
derive(无写入):不需要安装,只在本插件内存里替换,重启后靠 sidecar 记录继续生效。 message-edit仅作实验性场景,不推荐:它是分支型后端,会缩小可用场景(不能承接委派、子代理开关会被锁、有后台工作的会话不压缩),每压缩一次还多一个分支会话。
下面按这个推荐顺序说明:derive、in-place、message-edit。
无写入后端 derive(仅内存替换)
- 不需要安装任何东西,也不需要宿主补丁或第三方插件:它直接使用本插件在把历史交给模型前的那层派生消息包裹器,在内存里把思考块换成压缩版。
- 好处:打包版 DSH(例如 dsh-desktop)也能用;不改会话日志、不建分支,也不在会话里留下写入痕迹。
- 压缩记录照旧保存在会话日志旁边的 sidecar 文件里,重启不会丢:插件重新加载记录后,会继续在每次请求前把思考块替换成压缩版。只有插件被停用、卸载或记录被删除时,才没有东西执行替换,模型才会回到原文。
- Fork/复制会话会继承父会话的侧车账本:只复制落在 fork 前缀里的改写,目标消息 id 和 seq 在副本里保持不变,所以副本里的同一段思考也直接是压缩版,不会因为换了 session id 而退回原文。
- 对话页面显示的是会话日志里的原文:该模式不写历史,所以对话页面/原生对话界面里看到的始终是原始思考,压缩后的内容只出现在本插件的「思考压缩」报告与账本里。但模型每次请求实际收到的是压缩版,页面上的原文不等于模型看到的内容。
- 最常见的退回原文情况:冷启动时 sidecar 读不出来。插件不会因此阻塞对话,该会话的请求会暂时带原始思考(日志里会明确警告),记录恢复可读后自动重新应用。另外,目标思考被别的插件改写/投影、或被宿主压缩淘汰时,这一条改写也会按“不再生效”处理。
- 报告、节省统计、触发规则、上下文占用闸门等其余功能与其它后端一致。
内置原位后端(in-place)与宿主补丁(首选)
- 不需要安装任何包;它的前置条件是给 DSH 本体打补丁(
scripts/dsh-inplace-patch.mjs)。快速安装里的 in-place 就是打这个补丁。 - 补丁给会话加了两样能力:在不改变日志长度、seq、消息 id 的前提下,替换某条助手消息里的思考块;以及让持久化层能就地改写已存的记录。共 14 处编辑(其中 1 处带两份版本锚点,见下)。
- 好处:不新建分支、不产生额外会话,对话列表和归档列表保持干净。
- 风险:这是修改 DSH 本体源码的补丁。DSH 跨版本升级很容易出问题——补丁按字面锚点匹配,任何一处对不上就整体拒绝,不会写一半。升级 DSH 前建议先回退,升级后再用
--check复查、必要时重打;打不上就用--checkout <DSH 源码目录>指路,不要手工改宿主源码。 - 打完补丁需要重启
dsh web才生效。回退:node scripts/dsh-inplace-patch.mjs --revert --build。 - 打包版 DSH 用不了这个后端:像 dsh-desktop 这类把 harness 装成只读、只有
node_modules而没有源码的安装,没有可写的源码树可以打补丁;这类安装请用derive或 message-edit。
经过测试的 DSH 版本
分三档看,别把"补丁能打上"当成"整套在真实会话里跑过":
| 档位 | 覆盖的版本 | 做到了什么 |
|---|---|---|
| 已知可运行 in-place | 0.2.1-alpha.1、0.2.1-alpha.5、0.2.1-rc.3 | alpha.1 是本插件开发机(补丁已长期在真实会话中使用);alpha.5 是反馈该问题的用户所在版本,补丁与插件均确认可用;rc.3 是更新后的宿主版本,实际使用 in-place 后端完成改写,补丁 --check 输出 PATCHED |
| 完整启动 | 0.2.1-rc.1 | 独立 clone 全量构建后装入插件并启动 web,插件的安装页与报告页路由都能正常应答 |
| 补丁 + 类型 + 语义 | 0.2.0-rc.1、0.2.0-rc.2、0.2.1-alpha.1~0.2.1-alpha.5、0.2.1-rc.1 | 独立 clone 上逐版本 --apply → --check → --revert(回退后工作树逐字节干净)、打过补丁的包 tsc -b 通过、持久化探针 scripts/probe-inplace-durability.mjs 通过(none 与 zstd)、插件依赖的宿主 API 兼容探针通过 |
| 等价核对 | 0.2.1-rc.2 | 6 个补丁目标文件与公开 API catalog 和 0.2.1-rc.1 逐字节相同,故上一行对 rc.1 的全部结论直接适用 |
- 也就是说:在 0.2.x 范围内,in-place 补丁与插件的宿主 API 都有逐版本实测依据;其中
0.2.1-alpha.1、0.2.1-alpha.5与本次更新后的0.2.1-rc.3已知可正常运行 in-place,完整启动验证过的是0.2.1-rc.1。其余版本请先在可回退的环境里试。 - 版本差异最大的一处:
packages/session/session-persistence-jsonl/src/storage.ts的install()从0.2.1-alpha.3起改成了 generator effect + 闭包变量(writers取代this.writers,在 generator 内部this已不是那个实例)。补丁脚本为此处带两份锚点,会按宿主实际形态自动选择匹配的那份。 scripts/probe-inplace-durability.mjs同时适配了 jsonl 后端的两种导出形态:0.2.1-alpha.2及以前 default export 提供者类,0.2.1-alpha.3起是name+apply的 Cordis 插件。
旧后端 message-edit(实验性,不推荐)
- 这是其他开发者发布的第三方插件:https://github.com/Moeblack/dsh-message-edit。
- 本仓库在开发初期引入它,仅作为实验性后端保留:它会让可用场景反而变少,不推荐日常使用。
- 它的做法是每次压缩都新建一个分支会话。由此带来几个限制:
- 每压缩一次就多出一个分支会话,很快会堆满对话列表或归档列表,需要自己清理。
- 它是分支型后端,不能承接委派:选中它时两条子代理开关会被强制关闭并锁定;并且在有运行中的后台任务或子代理时不会压缩(新分支无法带走原会话的后台工作)。只有分支后端有这个限制,
derive/in-place不检查后台任务,会照常压缩。 - 分支创建成功后,原会话不会被“搬空”:即使因为关闭归档(
archiveSuperseded: false)、归档失败或客户端没跟上分支而继续使用原会话,它也会继续重放同一份压缩版,不会退回原文。 - 当前测试不充分,行为不保证。
- 本仓库通过
vendor/dsh-message-edit-0.2.3-patched4.tgz加scripts/patch-message-edit.py来安装与修补它;装完同样要重启dsh web。 - 打包版 DSH(例如 dsh-desktop)优先用无需安装的
derive;message-edit 只作为实验性备选。
(旧)message-edit 后端安装流程
本仓库验证过的完整流程是 scripts/install-backend.sh message-edit(官方 CLI 装包 → 打补丁 → 逐字节校验),等价于下面三步:
cd <DSH 源码目录> # 或用 DSH_CHECKOUT 指定
pnpm dsh plugin --profile web add <本插件目录>/vendor/dsh-message-edit-0.2.3-patched4.tgz
DSH_PLUGIN_ROOTS="$DSH_HOME/profiles/web" python3 <本插件目录>/scripts/patch-message-edit.py
# 校验:解出 vendor 包,与 $DSH_HOME/profiles/web/node_modules/dsh-message-edit/ 下的
# index.mjs、client.js 逐字节比对(cmp)
需要本机有 pnpm 与 python3。装完重启 dsh web 生效(客户端半边硬刷新即可)。
三、安装
1. 安装本插件
前置条件:Node >= 20;DSH 本体能正常启动(插件需要会话持久化 sessionPersistence 服务)。
从 npm 安装:
dsh plugin --profile web add dsh-reasoning-distill
也可以直接从 GitHub 装源码。pnpm 会要求你允许它执行构建脚本 prepare:第一次 add 会失败并打印出包名,把包名加进 profile 的 pnpm-workspace.yaml 的 allowBuilds 后重试即可(这等于授权该包在安装时执行代码,请确认信任来源):
dsh plugin --profile web add github:huhu23333/dsh-reasoning-distill
本地开发(从本仓库源码以 link: 方式装进 profile):
cd dsh-reasoning-distill
npm install
npm run build
scripts/install.sh web
装完重启一次 dsh web(bundle 元数据要重启才会重新扫描)。
scripts/install.sh 做三件事:构建插件、把 profile 共享的 @deepseek-ai/* 运行时软链进插件、用官方 CLI 把本插件加进 profile。注意:之后只要重跑过 npm install(任何依赖变化),脚本建的软链会被清掉,需要重新执行一次 scripts/install.sh。
2. 装好并选中一个后端(选 derive 可跳过安装)
如果打算用 derive,不需要安装任何东西,直接在设置里选中即可。否则打开「设置 → 思考压缩 → 快速安装后端」,选好后端后可以:
- 用脚本安装:走本仓库验证过的固定流程,可复现、有逐步进度、随时取消,装完自动校验;
- 让 agent 安装:会把对应的安装提示词填进一个新会话的输入框,发不发由你决定。
脚本安装会使用宿主当前运行的 profile(不再硬编码 web),并在安装 message-edit 前校验 vendor/*.tgz.sha256;取消会终止整个安装进程组(5 秒后 SIGKILL 兜底)。打包版安装 message-edit 时若定位不到 DSH checkout,请设置 DSH_HOST_CHECKOUT 指向安装目录。
也可以手动执行。in-place 后端:
node scripts/dsh-inplace-patch.mjs --locate # 只定位 DSH 源码目录,不改文件
node scripts/dsh-inplace-patch.mjs --apply --build # 打补丁并构建校验
node scripts/dsh-inplace-patch.mjs --check # 打全了输出 PATCHED
# 然后重启 dsh web
--checkout <DSH 源码目录> 可显式指定宿主源码位置;脚本找不到时会列出所有试过的路径。
3. 启用
在「设置 → 思考压缩」里:选中一个后端(derive 无需安装,选中即用)→ 打开「启用思考压缩」。之后按需调整下面的配置。
四、配置项
所有配置都在「设置 → 思考压缩」里。下面按面板的分组说明。
总开关与后端
| 选项 | 含义 |
|---|---|
启用思考压缩(enabled) | 总开关,默认关。没有选择后端时强制关闭并锁定。 |
助手消息改写后端(rewriteBackend) | 单选,只列出可用的后端;再次点击已选中的那一项可以取消选择。in-place 需要宿主补丁,message-edit 需要第三方插件,derive 不需要任何安装(仅内存替换,不写回历史)。 |
规则(分为"默认规则"和"逐模型规则")
逐模型规则是稀疏的:没写的字段继续跟随默认规则;没有单独列出的模型一律使用默认规则。
| 选项 | 含义 |
|---|---|
对主对话启用(enabled) | 该模型在主对话里是否压缩。 |
对可续接子代理启用(continuableSubagents) | 是否也压缩可续聊子代理(如队友)。默认关;需要时再打开。 |
对一次性子代理启用(oneShotSubagents) | 是否压缩跑完即结束的一次性委派。默认关,因为它的最终回答之后没有任何请求会重放这次压缩。 |
最大生效深度(continuableMaxDepth / oneShotMaxDepth) | 两个子代理开关各自带一个深度上限:比该深度更深的子孙代理不再压缩,0 表示不限制。 |
触发阈值(thresholdTokens) | 一步思考估算超过多少 token 才触发,默认 4000。 |
按上下文占用限制触发(contextCap / maxContextPercent) | 默认开、60%。该模型的上下文占用超过这个比例时,即使单步思考达到阈值也不再压缩——否则压缩刚生效、没几轮就被宿主内置的上下文整体压缩收走,白花一次蒸馏的钱。占用比例用宿主自己的 token 计量与上下文窗口计算,和内置上下文压缩触发读的是同一个值,整段压缩后会自动变短。关闭时不看占用比例(与旧行为一致),比例输入框会变灰。 |
最低节省(minSavedTokens) | 压缩结果至少要比原文省这么多 token 才采用,默认 600;未达到时原文保持不变,但这次蒸馏的开销照样计入。 |
附带工具调用结果(includeToolResults) | 交给蒸馏模型的上下文里是否附上该步工具调用的结果;工具调用本身始终附带。默认关(刚安装的默认规则与新建的逐模型规则都是关的)。 |
压缩最终回答轮(includeFinalTurns) | 是否压缩没有工具调用的收尾步(最终回答)。默认关(同上)。 |
超时(timeoutMs) | 蒸馏必须在这个时间内完成;到点就放弃这次压缩(原文不动,但这次尝试的开销仍以失败记录计入报告),下一步只等这么久。0 = 不设限,一直等到出结果。 |
背景块长度上限(maxInputChars) | 交给蒸馏模型的每个上下文块(工具调用参数、该步可见文本、每条工具结果)的字符上限,0 = 不限。推理本身始终整段发送——它是被改写的对象,截断或跳过会让压缩结果失真。 |
蒸馏结果长度上限(maxOutputChars) | 实际采用并重放的压缩结果字符上限,0 = 不限。 |
蒸馏服务商 / 蒸馏模型 / 思考强度(distiller.provider / model / effort) | 用哪个模型做压缩;思考强度选 off 表示不让蒸馏模型自己再思考。默认 deepseek-official/deepseek-flash + off。 |
三种会话都关掉时,该规则的其他项不会生效,面板会把它们锁住。
分支后端专用选项(只有选中 message-edit 时出现)
| 选项 | 含义 |
|---|---|
分支超时(branchTimeoutMs) | 宿主等待分支型后端建好分支的时限;超时就当什么都没发生,继续在原会话里跑。0 = 永不超时。 |
建分支后自动归档原会话(archiveSuperseded) | 分支继续的是同一件工作,所以新分支显示出来后,把被替换的原会话收进归档(仍可从归档找回)。默认开。关掉或归档失败时原会话仍可使用,此时它也会继续重放压缩版,不会发回原文。 |
蒸馏提示词
| 选项 | 含义 |
|---|---|
蒸馏提示词(prompt) | 替换内置的压缩指令;留空 = 使用内置提示词(可点"预览内置提示词"查看)。内置提示词要求保留原思考中正确且有效的推理过程:可以压缩措辞、合并重复,但不能省掉推导步骤直接给结论;还要保留被否定的方向及其原因("X 被否决,因为 Y"),让后续轮次不会重新走进同一条错误路线。 |
模型价格与峰谷时段
价格只影响报告里算出来的金额,不影响是否触发压缩。
| 选项 | 含义 |
|---|---|
模型价格(prices) | 按模型配置,每项三列:命中(cache hit)、未命中(miss)、输出(out),单位是"元 / 百万 token"。只有打开"使用峰谷两栏计价"(peakPricing)时才使用第二栏谷时价。内置 DeepSeek 模型出厂就带两栏价:即使你只改了其中一栏或某个字段,未被覆盖的字段与"是否分两栏"仍沿用内置默认;其他模型默认没有条目、按 0 计算(它们的节省会显示为 0),需要时手动添加。 |
时段规则来源(peakSource) | 二选一。builtin:北京时间工作日 9–12、14–18 为峰时,夜间、周末与用户节假日表全天谷价。whale:时段与节假日都读取当前 profile 中安装的 dsh-whale-widget 的常量(此时用户节假日表不参与);任一常量解析失败或读不到时自动回退到内置规则。 |
节假日(holidays) | YYYY-MM-DD 列表,这些日期全天按谷价。只在「内置固定时窗」来源下使用;「whale」来源的节假日由 widget 提供。两个来源二选一、不叠加,所以选中 whale 时这个编辑框会隐藏。可一键恢复内置节假日表。 |
报告里的几个数字
- 当前单次请求减量:下一次请求会少带的估算 token,是存量而不是累计;它包含所有仍在生效的改写——不论来自哪一轮,只要目标还没有被宿主上下文压缩淘汰。改写被淘汰后相应减少,全部淘汰归零。用户发新消息不会让它归零,因为下一次请求仍会发送并重放之前轮次的思考。
- 历史累计节省:永不重置,统计所有重放过改写的已应答请求,不限轮次(跨轮次的重放同样计入),再加上已被 compaction 冻结的 epoch。
- 净收益 = 历史累计节省 − 蒸馏开销 − 缓存断裂开销。
- 最近一步未触发的原因:面板会直接给出(总开关关、未选择后端、规则关、未到阈值、上下文占用超过上限、这一步没有思考、有多个思考块、有后台工作在跑(仅分支后端)等)。
- 压缩会话:每次蒸馏都会开一个旁路会话,用来查看这次压缩的提示词与回答。它只存在于内存里、不写盘:本次运行期间可以点开,重启后自动过期,报告里会显示"会话已随上次运行结束(内容见下方明细)"——完整内容本来就在明细里。插件自身不会把这些旁路会话计入会话记账;宿主仍会在进程内保留它们,因此超长运行、压缩次数极多时会占用一定内存。
Related plugins
DeepSeek-Balance-Whale-Widget
meteornox/deepseek-balance-whale-widget
dsh-context
bowenliang123/dsh-context
dsh-cost-meter
han-1413141/dsh-cost-meter
dsh-damage-pulse
wssfk12138/dsh-damage-pulse