dsh-fast-mode 1.6.1 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BENCHMARK.md +123 -1
- package/CHANGELOG.md +48 -0
- package/README.en.md +10 -8
- package/README.md +10 -9
- package/client.js +90 -26
- package/docs/REFERENCE.md +37 -29
- package/index.js +74 -56
- package/package.json +2 -2
- package/src/config.js +18 -8
- package/src/deliberation.js +217 -0
- package/src/effort.js +7 -7
- package/src/state.js +17 -7
- package/src/usage.js +23 -0
- package/src/lazy.js +0 -220
package/BENCHMARK.md
CHANGED
|
@@ -5,6 +5,86 @@
|
|
|
5
5
|
> 1.4.4 把「第 10 步提醒收尾」设为默认时确实更快(下节 14 对中位 1.86×、正确性零损失),但它对**仍在推进的长任务**同样开火,这是 1.5.0 撤回该默认的原因。**以下 1.4.4 及更早的数字全部是历史与消融证据,不是 1.5.0 的速度声明**;`fl10` 就是那条退役默认的消融臂。1.5.0 默认在隔离环境下的干净重基线见下一节「1.5.1」(10 家族、30 个单元、总墙钟 0.72×;复现块 W5、W7 总量各 0.73×,对照块 W8b 逐格中位 0.717×;W3+W5+W7 合计 65 个有效单元 0.74×)。
|
|
6
6
|
>
|
|
7
7
|
> **口径(1.5.1 起)**:一个单元只在 `exit == 0 && 步数 ≥ 1 && 输出 > 0 && 判分完成 && 未泄漏` 时计数;运行崩溃的单元整格作废并点名,不算红、也不算快。所以「全绿」一律指**有效单元全绿**(1.5.1 29/29、W5 19/19、W7 17/17)。
|
|
8
|
+
> **1.7.0**:`lazy` 与它改 `reasoningEffort` 的那一半已删除,换成三个默认关闭的纯提示开关(`probeFirst` / `actBeforePlan` / `repeatNudge`)。第一次实测见下节「块 DP17」:三开 12 对 **0.647×**、CI95 [0.501, 0.893]、判分全绿;单开三臂都还没到显著。
|
|
9
|
+
|
|
10
|
+
## 块 DP19(2026-11-01):1.7.1 的回归复核——`actBeforePlan` 多带一条长度提醒后,`debugfix`+`migrate` 8 对 **0.701×**,判分 16/16
|
|
11
|
+
|
|
12
|
+
1.7.1 把「本回合思考写太长」的提醒合进了 `actBeforePlan`(不新增开关,面板仍七行)。要回答的问题是:这个臂在 `DP17` 的两族旧任务上曾经是 `debugfix` 0.582×、`migrate` 0.996×,多一个行为之后会不会退化。
|
|
13
|
+
|
|
14
|
+
**方法。** `debugfix`、`migrate` 各 4 对、共 8 对;两臂 `off` 对 `ab17`,ABBA 交替先后,16 次运行,判分 16/16 绿、零失败、零泄漏(`bench/results/suite-DP19.jsonl`)。
|
|
15
|
+
|
|
16
|
+
| 臂 | 汇总墙钟比 | CI95 | 更快 | 单对范围 |
|
|
17
|
+
|---|---|---|---|---|
|
|
18
|
+
| `ab17`(1.7.1,两个行为) | **0.701×** | **[0.516, 0.930]** | 6/8 | 0.33 / 1.24 |
|
|
19
|
+
|
|
20
|
+
分家族(逐对几何,括号里是同一族在 `DP17` 的 1.7.0 读数):`debugfix` **0.756×**(4/4 更快;`DP17` 0.582×)、`migrate` **0.649×**(2/4 更快;`DP17` 0.996×)。思考字符几何均值 `off` 28275 → `ab17` **17834**;步数 9.27 → 7.62。
|
|
21
|
+
|
|
22
|
+
**提醒确实在真实运行里发出了(翻会话记录数的,不是从代码推的):** 4 个 `ab17` 会话各收到 1–2 条长度提醒(每回合上限 2),4 个 `off` 会话 0 条;同批会话里每回合思考字符 5350–120897,4000 的门槛确实被越过。
|
|
23
|
+
|
|
24
|
+
**结论与局限。** 加长度提醒没有让这个臂在旧任务上退化:点估计 0.701×、CI 上界 0.930,比 `DP17` 同期两族(0.582× / 0.996×)没有变差的方向证据。但只有 8 对、`migrate` 只有 2/4 更快、单对区间 0.33–1.24×,**不足以说它更快**,更不足以把两个行为各自的贡献拆开——那需要一个只带长度提醒的独立 arm,本轮没做,也不打算为了拆账再加一个面板开关。
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## 块 DP18(2026-11-01):三族复核 1.7.0 的三臂,`trio17` 9 对 **0.491×**,CI95 [0.314, 0.788],判分全绿
|
|
28
|
+
|
|
29
|
+
`DP17` 只覆盖两族短任务,所以在三族更长的任务上复核同一批 arm。**这一块量的是 1.7.0 的代码**——长度提醒(1.7.1)还没上,所以 `ab17` 在这里只代表「先动手再解释」一个行为。
|
|
30
|
+
|
|
31
|
+
**方法。** 家族 `codeimpl`(14 项判分)、`ledger`(22 项判分)、`stategraph`;每族 3 对、共 9 对;四臂 `off` / `pf17` / `ab17` / `trio17` 按对轮转,同对内交替先后;共 36 次运行,全部单元判分与 `off` 逐格一致、零失败、零泄漏。
|
|
32
|
+
|
|
33
|
+
| 臂 | 汇总墙钟比 | CI95 | 更快 | 单对范围 |
|
|
34
|
+
|---|---|---|---|---|
|
|
35
|
+
| `pf17` | 0.719× | [0.492, 0.999] | 7/9 | 0.21 / 1.56 |
|
|
36
|
+
| `ab17` | 0.643× | [0.427, 0.920] | 6/9 | 0.21 / 1.39 |
|
|
37
|
+
| `trio17` | **0.491×** | **[0.314, 0.788]** | **8/9** | 0.18 / 1.97 |
|
|
38
|
+
|
|
39
|
+
分家族(逐对几何):`codeimpl` 上 `pf17` 0.953× / `ab17` 0.784× / `trio17` 0.869×;`ledger` 上 0.490× / 0.979× / **0.331×**;`stategraph` 上 0.797× / **0.346×** / 0.411×。思考字符(几何均值)`off` **71275** → `pf17` 59930 / `ab17` 44617 / `trio17` **32463**;步数 12.86 → 7.21 / 8.98 / 6.87。
|
|
40
|
+
|
|
41
|
+
**与 `DP17` 合池(21 对):** `pf17` 0.809× [0.643, 1.002]、`ab17` **0.708×** [0.558, 0.898]、`trio17` **0.575×** [0.444, 0.748]。两块方向一致:这三个臂不是「只对短任务有效」。
|
|
42
|
+
|
|
43
|
+
**读法。** 三点:
|
|
44
|
+
|
|
45
|
+
1. **`ledger` 与 `stategraph` 是这次收益来源。** `trio17` 在这两族 0.331× / 0.411×,`ab17` 在 `stategraph` 0.346×;思考字符从 71275 降到 32463,方向仍然是「少想,不少验证」——判分 36/36 与 `off` 相同。
|
|
46
|
+
2. **`ab17` 在 `ledger` 上不赚(0.979×)。** 与 `DP17` 的 `migrate`(0.996×、步数 11.0 → 15.7)同类:需要先列清单的任务被「先动手」推着绕路。所以它保持默认关,按任务形状自己试。
|
|
47
|
+
3. **`trio17` 在两块里都是唯一 CI 不跨 1 的臂**(`DP17` 0.647×、`DP18` 0.491×、合池 0.575×)。三开不是三个平均值,组合在两个方向上都不亏。
|
|
48
|
+
|
|
49
|
+
**局限。** 每族只有 3 对(单对区间 0.18–1.97×),比 `DP17` 的 6 对更薄;原计划 5 对,为了「同一时刻只跑一个块、不长时间占满 CPU」的纪律减到 3 对,代价是区间更宽。所以对外仍只说合池的 `trio17` 0.575× 与两块各自的点估计,不拿单族数字做承诺。`repeatNudge` 在 `DP17` 里只被触发 3 次(详见该块局限),这一块没再单独量它。
|
|
50
|
+
|
|
51
|
+
## 块 DP17(2026-11-01):三个纯提示侧开关,读一次事实 / 先动手 / 重复提醒;三开 12 对 **0.647×**,CI95 [0.501, 0.893],判分全绿
|
|
52
|
+
|
|
53
|
+
1.7.0 删掉了 `lazy` 与它改 `reasoningEffort` 的那一半(依据是 `LZ1` 里两臂对打 1.106×、CI 跨 1,见下文 `LZ1` 块),换成三个**只改提示、不改任何请求字段**的开关。这一块就是它们的第一次真测量。
|
|
54
|
+
|
|
55
|
+
**这一块量的是 1.7.0 的代码**(1.7.1 给 `actBeforePlan` 补了按思考长度的提醒,所以本块的 `ab17` 只代表「先动手再解释」一个行为)。
|
|
56
|
+
|
|
57
|
+
**方法。** 家族 `debugfix`、`migrate`;每族 6 对、共 12 对;五个 arm 配置(`off`、`pf17`=`probeFirst`、`ab17`=`actBeforePlan`、`rn17`=`repeatNudge`、`trio17`=三开)按对轮转,同对内的 `off` 与各臂交替先后。共 60 次运行,全部单元的判分与 `off` 逐格一致,零失败。比值 = 该臂墙钟 / 同对 `off` 墙钟,家族与合池都用逐对几何平均;CI 是 4000 次 bootstrap 的 2.5 / 97.5 分位。
|
|
58
|
+
|
|
59
|
+
| 家族 | 开关 | 墙钟比 | 更快 | 步数(几何均值) | 思考字符(几何均值) |
|
|
60
|
+
| --- | --- | --- | --- | --- | --- |
|
|
61
|
+
| `debugfix` | `pf17` | 0.993× | 3/6 | 4.8 / 5.3 | 7329 / 8249 |
|
|
62
|
+
| `debugfix` | `ab17` | **0.582×** | **6/6** | 4.2 / 5.3 | **3152 / 8249** |
|
|
63
|
+
| `debugfix` | `rn17` | 1.038× | 4/6 | 5.0 / 5.3 | 8792 / 8249 |
|
|
64
|
+
| `debugfix` | `trio17` | **0.632×** | **6/6** | 4.8 / 5.3 | 4241 / 8249 |
|
|
65
|
+
| `migrate` | `pf17` | 0.785× | 4/6 | 10.6 / 11.0 | 45499 / 61560 |
|
|
66
|
+
| `migrate` | `ab17` | 0.996× | 2/6 | 15.7 / 11.0 | 52268 / 61560 |
|
|
67
|
+
| `migrate` | `rn17` | 0.978× | 3/6 | 10.5 / 11.0 | 52945 / 61560 |
|
|
68
|
+
| `migrate` | `trio17` | **0.663×** | 4/6 | 11.3 / 11.0 | **34783 / 61560** |
|
|
69
|
+
|
|
70
|
+
| 合池(12 对) | 墙钟比 | CI95 | 更快 | 最快 / 最慢单对 |
|
|
71
|
+
| --- | --- | --- | --- | --- |
|
|
72
|
+
| `pf17` | 0.883× | [0.663, 1.176] | 7/12 | 0.31 / 1.99 |
|
|
73
|
+
| `ab17` | 0.761× | [0.578, 1.032] | 8/12 | 0.44 / 2.12 |
|
|
74
|
+
| `rn17` | 1.007× | [0.839, 1.227] | 7/12 | 0.62 / 1.90 |
|
|
75
|
+
| `trio17` | **0.647×** | **[0.501, 0.893]** | **10/12** | 0.30 / 2.44 |
|
|
76
|
+
|
|
77
|
+
**读法。** 三点必须一起说清:
|
|
78
|
+
|
|
79
|
+
1. **`actBeforePlan` 是这次真正对着「思考链过长」的那一刀。** `debugfix` 上它 0.582×、6/6 更快,思考字符(几何均值)8249 → 3152(**0.38×**),步数(几何均值)5.3 → 4.2。也就是说收益确实来自「少想」,不是少做验证——同族判分逐格相同。
|
|
80
|
+
2. **它不是通用加速。** `migrate` 上它 0.996×、2/6 更快,步数反而 11.0 → 15.7:该族要先列清单再动手,硬推「先动手」会绕路。所以它保持默认关,按任务形状自己试。
|
|
81
|
+
3. **`repeatNudge` 单开等于没变(1.007×),但也不拖后腿。** 单开 12 对里 7 对更快、CI 完全盖住 1;放进三开组合后合池 10/12 更快、0.647×,是这一版唯一 CI 不跨 1 的臂。它的价值在「组合里不亏」,不在单开收益;这一点如实写,不做成「重复提醒有效」。
|
|
82
|
+
|
|
83
|
+
**局限。** 每族 6 对、两族合计 12 对,`trio17` 的单对区间是 0.30–2.44×,尾部有反向格;`ab17` 的合池 CI 上界 1.032 仍然擦过 1。所以对外只说 `trio17` 这一条 0.647×(CI 不跨 1),单开三臂一律写成「方向一致、尚未单独显著」。更宽的三族复核(`codeimpl`/`ledger`/`stategraph`)已跑完,见上一节「块 DP18」。
|
|
84
|
+
|
|
85
|
+
**`repeatNudge` 的 1.007× 是「几乎没触发」的读数,不是「提醒无效」的读数。** 把 `rn17` 那 12 个会话的记录翻出来数原文:12 个会话里只有 2 个收到过提醒(合计 3 条),而且全部来自「连续结果内容相同」那条分支(观察到相同条数 3、7、7);「同一调用本回合已跑 ≥2 次」这条分支一次都没满足。离线回放同一批会话:`stale` 分支在 5 次 `debugfix` 关闭态会话里会触发,`migrate` 里 0 次;每回合 `signature` 最多重复次数均值 1.18、`digest` 最长连击均值 2.76。也就是说阈值对着「极端打转」而不是「日常长链」——所以 1.7.1 才在 `actBeforePlan` 里补了按思考长度触发的第二条提醒,而不是继续调这个阈值猜测。
|
|
86
|
+
|
|
87
|
+
|
|
8
88
|
|
|
9
89
|
## 提醒投递的稳定性(2026-10-29):压缩重入会让同一轮收到两条
|
|
10
90
|
|
|
@@ -1715,7 +1795,7 @@ python3 bench/suite-run.py --tasks debugfix,ledger,codeimpl --arms off,def15,bud
|
|
|
1715
1795
|
|
|
1716
1796
|
判据在跑之前就写死了:同一家族先看逐对方向是否一致,再合池;只要逐对方向随机就不给结论。这里 6 对里 3 对更快、3 对更慢,几何 1.014 与 1.0 无法区分,输出 token 只少 5 % 也没换来墙钟 ⇒ **`shapeGate` 不是速度杠杆**,与上面的分解一致(省时只能靠少输出/少轮次,而 gate 的输出变化不稳定)。因此它保持默认关闭;它的价值只在「形态约束」本身,不在速度。
|
|
1717
1797
|
|
|
1718
|
-
**全语料复核宽度引导本身(251 个已录会话,离线读 transcript,0 成本)。** 上面测的是 `shapeGate` 这个开关;再往下问一层:**请求形状判定的宽度建议,到底有没有让模型真的并行**?做法是把每个 run 目录的会话 transcript 反解出来,取第一条 `user/message` 文本喂给 `classifyEntry()`,再数第 1 步真实的 `tool/call` 事件数。结果:251 个会话里判定为宽(width>1)只有 **24** 个,而这 24 个里 **22 个第 1 步只发了 1 次调用**(只 2 个 ≥2);反过来判为 native 的 227 个里也只有 2 个第 1 步 ≥3
|
|
1798
|
+
**全语料复核宽度引导本身(251 个已录会话,离线读 transcript,0 成本)。** 上面测的是 `shapeGate` 这个开关;再往下问一层:**请求形状判定的宽度建议,到底有没有让模型真的并行**?做法是把每个 run 目录的会话 transcript 反解出来,取第一条 `user/message` 文本喂给 `classifyEntry()`,再数第 1 步真实的 `tool/call` 事件数。结果:251 个会话里判定为宽(width>1)只有 **24** 个,而这 24 个里 **22 个第 1 步只发了 1 次调用**(只 2 个 ≥2);反过来判为 native 的 227 个里也只有 2 个第 1 步 ≥3 次。按「任务、对」把 `off` 与开档臂配对看,**24 对里 23 对第 1 步调用数完全相同**,剩下 1 对是关闭档更多:宽度建议在语料里**没有可测行为效果**。原因不是判定错了,而是这套基准语料是「读一个仓库、迭代修改」的串行型任务,本来就不该扇出(这也和前面 90.7% 的步是单调用互相印证)。所以:收益**不来自批量**,只来自步数与输出长度;宽度引导作为「形态约束」保留,但不能再被当成提速机制来讲。
|
|
1719
1799
|
|
|
1720
1800
|
这也顺带说明 1.5.10 那个接线 bug 的影响面:旧块里 `bud8`/`sg15`/`gateonly`/`gate15` 的分支数据一律标 **untested**,不能当机制证据;上面这张表是修复后的第一次真测量。
|
|
1721
1801
|
|
|
@@ -2562,4 +2642,46 @@ metrics 242400 steps written, caches trimmed
|
|
|
2562
2642
|
- 能说:在 12 对同题同配的对照里,打开 `lazy` 后 11 对更快,几何 0.39–0.43×,判分与输出正确性没有任何一格变红;机制是「步数变少 + 每步推理字符变少」,两侧同时发生,不是纯粹少说话。
|
|
2563
2643
|
- 能说:**收益主要来自提示文字那一半**。把两臂直接对打:`laz16 / lazt16` 的逐对几何是 **1.106×**(95 % CI [0.682, 1.792],12 对里 5 对更快)——也就是说「降 `reasoningEffort`」这一半在这条路由上**没有测出额外收益,也没测出明显代价**。这与本文件早先的记录一致:这条路由的 usage 里 `reasoning` token 一直是 0,`reasoning_effort` 是否被上游当真从未被证明;`lazy` 的第二通道(流式推理字符)就是为这件事加的,读数显示两臂推理字符同量级(0.372× 对 0.418×)。
|
|
2564
2644
|
- 不能说:这不是「所有题都变快 2.6 倍」。样本是这两族短任务、单机、单路由,`def15` 本块的中位偏慢侧(历史上 `codeimpl` 中位 161 s、`ledger` 649 s,本块 174.9 s 跨两族),逐对设计吸收了基线漂移,但换模型/换路由后倍数会变。也不要说 `lazy` 提高质量:它只做到「没把质量弄坏」——216/216 与 `def15` 持平,不是更好。
|
|
2645
|
+
- **这一块的臂已经不存在了,读数也只复现了一部分。** `lazy` 在 1.7.0 被整个删掉(连同改 `reasoningEffort` 的那一半),所以 `def15`/`laz16`/`lazt16` 三个 arm 现在只能从 git 历史里取回。后续用同一批家族做纯文本变体对照时(`LZ2` 的 `v2 / v1` 几何 **0.699×**、`LZ3` 几何 **0.822×** 但中位 1.014×),都没有复现出这里的 0.39–0.43×,只落在 0.70–0.82× 一带;所以本块的 0.39× 只能当**一次性读数**引用,不能当「这个提示的稳定收益」。引用它时必须同时说这两件事。
|
|
2565
2646
|
- 一块**退役 0.9.x 教训**的验证:降档不跨轮、不跨会话、每步最多一次、每轮最多两次、工具报错后两步内不降、地板 `low`、从不升档,且每个请求都以「用户此刻选的档位」为基准重新计算(`agent/request` 读的是刚解好的 `reasoningEffort`)。所以用户中途换档,下一次请求就是用户的档,不会像 0.9.x 那样把会话钉在低档上。
|
|
2647
|
+
|
|
2648
|
+
**降档确实在真实运行里发生了(机器证据,不是推理):**跑完后翻宿主的计量文件 `~/.dsh/fast-mode-metrics.jsonl`,`laz16` 臂的 8 个会话里有 **15 个步行**同时带着 `effort` 与 `effortBase`,全部是 `effort: 'low'` 对 `effortBase: 'medium'`——也就是用户选的是 `medium`,那一步因为推理字符超量被降了一档,行里两列同现就是证据(未降档的请求会显式清掉 `effortBase`,不会把降档归因到后来每一步)。同一批行里 `reasoningChars` 有非零读数(41 / 226 / 347 / 537 / 569 字符),说明第二测量通道也在工作,不是靠 provider 那个恒为 0 的 `reasoning` token。`lazt16` 与 `def15` 臂在这些会话里没有一条 `effortBase`——开关关掉就是真关掉。
|
|
2649
|
+
|
|
2650
|
+
## 结果:`LZ2`(`lazy` 的梯子文本 v1 / v2 / v3 三版对照,36 次运行)——v2 对 v1 **0.699×**,判分 648/648
|
|
2651
|
+
|
|
2652
|
+
`LZ1` 的结论是「收益来自提示文字那一半,降 `reasoningEffort` 那一半没测出额外收益」,所以下一个杠杆就是**文字本身**。这一块把 `lazy` 的梯子文本做成三个 bench 变体(`lazyVariant: v1|v2|v3`,隐藏字段,不进面板),三臂都开 `lazy: true` 且都关降档(`lazyEffort: false`),只看文字:
|
|
2653
|
+
|
|
2654
|
+
- `v1`:1.6.0/1.6.1 已发布的那份(762 字符,五条梯子 + 四类「绝不省略」)。
|
|
2655
|
+
- `v2`:`v1` 加两条——「不要重述任务或先解释计划」「下一步已经清楚就直接做,不要再权衡一遍不打算采用的方案」(973 字符)。
|
|
2656
|
+
- `v3`:同样规则的精简重写(629 字符),测「更短的提示能不能保住收益」。
|
|
2657
|
+
|
|
2658
|
+
`codeimpl` 6 对 + `ledger` 6 对,ABBA 交替,36 次运行,全部 `green`,判分 **648/648**(三臂同题同判,`bench/results/suite-LZ2.jsonl`)。
|
|
2659
|
+
|
|
2660
|
+
| 臂 | 墙钟合计 | 墙钟中位 | 步数合计 | 推理字符合计 | 输出 token 中位 |
|
|
2661
|
+
|---|---|---|---|---|---|
|
|
2662
|
+
| `lz2v1` | 1073.0 s | 80 s | 68 | 416 873 | 10 936 |
|
|
2663
|
+
| `lz2v2` | **727.8 s** | **41 s** | 63 | **268 806** | **6 802** |
|
|
2664
|
+
| `lz2v3` | 1132.5 s | 71 s | 68 | 401 247 | 8 884 |
|
|
2665
|
+
|
|
2666
|
+
逐对(各 12 对):`v2 / v1` 几何 **0.699×**,中位 0.597×,**9/12 更快**,输出 0.715×,步数 0.934×;`v3 / v1` 几何 0.997×,中位 0.848×,7/12 更快,输出 0.935×,步数 0.966×。机制和 `LZ1` 一致:`v2` 的推理字符是 `v1` 的 **0.645×**——省的是每一步里想的时间,不是步数。
|
|
2667
|
+
|
|
2668
|
+
**但这一块不能单独下结论。** 12 对里有两处大幅反向(`codeimpl` 第 2 对 2.15×、第 5 对 2.03×,`ledger` 第 2 对 4.41×),符号检验 9/12 并不显著,所以按预先约定再跑一块**换族**的确认块。
|
|
2669
|
+
|
|
2670
|
+
## 结果:`LZ3`(确认块:`debugfix` + `migrate` + `stategraph`,30 次运行)——几何 0.822×,**中位 1.014×**,短任务全慢
|
|
2671
|
+
|
|
2672
|
+
同一对臂(`lz2v1` 对 `lz2v2`),三族各 5 对,15 对 30 次运行,判分 **370/370** 全绿(`bench/results/suite-LZ3.jsonl`)。
|
|
2673
|
+
|
|
2674
|
+
| 臂 | 墙钟合计 | 墙钟中位 | 步数合计 | 推理字符合计 | 输出 token 中位 |
|
|
2675
|
+
|---|---|---|---|---|---|
|
|
2676
|
+
| `lz2v1` | 1459.5 s | 85 s | 108 | 429 822 | 10 011 |
|
|
2677
|
+
| `lz2v2` | 1070.8 s | 53 s | 88 | **310 316** | **6 737** |
|
|
2678
|
+
|
|
2679
|
+
逐对几何 **0.822×**、中位 **1.014×**、7/15 更快。分族看才是这块的重点:
|
|
2680
|
+
|
|
2681
|
+
- `debugfix`(小任务,5 对):**5/5 全慢**,1.08× / 1.21× / 1.22× / 1.22× / 1.23×。多出来的两句话在这种 2–3 步的任务上是纯成本。
|
|
2682
|
+
- `migrate`(5 对):0.46× / 0.60× / 0.53× 快,1.44× / 1.56× 慢,几何约 0.94×。
|
|
2683
|
+
- `stategraph`(长任务,5 对):0.32× / 0.51× / 0.81× / 0.49× / 1.01×,几何约 0.58×——长的、工具多的任务上收益最大(单次最长的三对合计从 690 s 降到 305 s)。
|
|
2684
|
+
|
|
2685
|
+
**决定:不换默认文本,`v1` 保持发布态。** 两轮合起来(27 对)几何约 0.765×,但分布是「长任务大赚、短任务倒亏」,而且 `LZ3` 的中位没有改善(1.014×)。把它设成默认等于拿所有短任务去换长任务,这一版不做这个交易。`lazyVariant` 保留在 schema 里(默认 `v1`、不进面板)仅仅是为了这些实验能被重跑;`v3` 的结论是「更短并不更好」(0.997×),也一并留档。
|
|
2686
|
+
|
|
2687
|
+
**质量口径:** 两块的判分与对照臂逐题完全一致(648/648、370/370),没有出现「更快但错得更多」的题;这两块不能用来宣称质量提升,只能说明换文本没把质量弄坏。
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.7.1(`actBeforePlan` 补上第二个信号:本回合思考已写多长;仍然只改提示词,不加面板行)
|
|
4
|
+
|
|
5
|
+
1.7.0 用 `repeatNudge` 去抓「没新信息还在想」,但本语料里模型很少把同一个调用原样重发第三遍:`DP17` 十二个会话只发出 3 条提醒,全部来自「连续结果相同」那条分支,「同调用 ≥2 次」一次都没满足。所以第二个信号换成本来就记在会话里的东西——**这一回合已经写了多少字符的思考**。
|
|
6
|
+
|
|
7
|
+
- **判定与文本。** `assistant/message` 事件里的 `reasoning` 块按字计数(`src/usage.js` 的 `readReasoningChars`),按回合累加(`noteReasoning`);到 `REASONING_CHARS`(4000)字符时,在下一步之前给一条通知,之后每再翻一个 4000 的台阶可以再来一条,每回合上限 `MAX_REASONING_NUDGES`(2)。文本写明它看到的字数并给两个出口:`You have written about N characters of reasoning in this turn. Past that length, more thinking about facts you already have rarely changes the next action: take the action the evidence supports, or read the one fact that is still missing.` 触发条件只有长度本身,所以文本**不断言**「没有新信息」。
|
|
8
|
+
- **它挂在 `actBeforePlan` 上,没有新开关。** 面板固定七行,加第四行会破坏「七行」这个说法;这条和「先动手再解释」是同一个方向(把计划和推理压到能动作为止),所以合在一个开关里。代价必须说清:`ab17` 从此同时量两个行为,读数只能按「两个行为一起」解释。
|
|
9
|
+
- **仍然一个请求字段都不碰。** 字数只读不写,`agent/request` 照旧原样返回 `resolved`。路由不吐 reasoning 块时读回 0,开关在那条路由上保持沉默——默认关闭的东西该有的失败方式。
|
|
10
|
+
- **`DP18` 复核的是 1.7.0 的读数**(长度提醒还没上):`codeimpl`/`ledger`/`stategraph` 三族各 3 对、四臂轮转、36 次运行,`trio17` **0.491×** [0.314, 0.788]、8/9 更快,`ab17` **0.643×** [0.427, 0.920]、6/9,`pf17` **0.719×** [0.492, 0.999]、7/9;与 `DP17` 合池 21 对后 `ab17` 0.708× [0.558, 0.898]、`trio17` 0.575× [0.444, 0.748](18/21 更快)。思考字符几何均值 `off` 71275 → `ab17` 44617 / `trio17` 32463,步数 12.86 → 8.98 / 6.87,判分全绿。计划里的 5 对减到 3 对是资源纪律(同一时刻只跑一个块、不长时间占满 CPU),理由与代价写进 `BENCHMARK.md`。
|
|
11
|
+
- 测试 334 → **337 全绿**(`test/deliberation.test.js` +2、`test/usage.test.js` +1)。动 `src/deliberation.js`、`src/usage.js`、`index.js`、两个测试文件。
|
|
12
|
+
|
|
13
|
+
- **`DP19` 回归复核(1.7.1 的代码,`off` 对 `ab17`,`debugfix`+`migrate` 各 4 对、16 次运行):** `ab17` **0.701×** [0.516, 0.930]、6/8 更快、判分 16/16 绿;`debugfix` 0.756×(4/4,1.7.0 时 0.582×)、`migrate` 0.649×(2/4,1.7.0 时 0.996×),思考字符几何均值 28275 → 17834、步数 9.27 → 7.62。提醒在真实运行里发出过:4 个 `ab17` 会话各 1–2 条(每回合上限 2),`off` 0 条;同批每回合思考字符 5350–120897。结论只到「加了它没让这个臂变差」,8 对不足以说更快,也没拆开两个行为各自的贡献。
|
|
14
|
+
|
|
15
|
+
## 1.7.0(删掉 `lazy` 与它改 `reasoningEffort` 的那一半;换成三个默认关闭的纯提示侧开关:`probeFirst`「不确定时先查一次」、`actBeforePlan`「先动手再解释」、`repeatNudge`「重复无进展时提醒」;12 对 5 臂 60 次运行里三开 0.647×,判分全绿)
|
|
16
|
+
|
|
17
|
+
这一轮的两件事是同一个决定的两面:**插件从此不碰任何请求字段**,**以及**把「别想太久」换成不改答案的做法。
|
|
18
|
+
|
|
19
|
+
- **`lazy` 整个删掉,不是关掉。** `src/lazy.js`、`test/lazy.test.js`、`lazy`/`lazyEffort`/`lazyVariant` 三个配置键、面板第六行、`bench/arms/laz*.yml`、以及 `agent/request` 里那处唯一的 `{ ...resolved, reasoningEffort }` 全部消失。删的原因是上一轮自己测出来的:`LZ1` 里只发文字是 0.389× [0.252, 0.600],文字加降档是 0.430× [0.273, 0.677],两臂直接对打 1.106× [0.682, 1.792]——**置信区间跨过 1,请求侧那一半没有测出任何额外收益**;而且它是全插件唯一会改变答案而不只是改变时延的机制。加上这条路由在所有 9678 行测量里 `reasoning` 用量都报 0,参数是否被上游当真从来没有被证明过。删掉之后「默认契约」升级成绝对承诺:**`agent/request` 原样返回 `resolved`,仓库里不存在任何构造 `reasoningEffort:` 的代码**,不存在「某个开关打开时会改」的例外。
|
|
20
|
+
- **三个新开关都是纯提示侧、默认关闭、逐会话、上屏可见。**
|
|
21
|
+
- `probeFirst`「不确定时先查一次」:入场步一条通知——拿不准的代码库事实去读一次(先 grep 再 read,先读区间再读全文),不要用推理去猜。
|
|
22
|
+
- `actBeforePlan`「先动手再解释」:第一个工具调用之前最多一行计划;下一步已经清楚就直接做。
|
|
23
|
+
- `repeatNudge`「重复无进展时提醒」:回合进行中才说话,条件是**本地证据**——同一个调用(工具名 + 稳定的 arguments 键)本回合已经跑过 ≥2 次,或最近三条相邻结果内容完全一致;提醒里写明观察到的次数。每回合上限 2 条,同一份证据不重复提醒,**报错结果永不算作循环、并清掉陈旧计数**(失败是信息,不是原地打转)。
|
|
24
|
+
- probe 与 act 共用**一条**通知和一条 `GUARD`(「信任边界、数据丢失、安全、可访问性上绝不跳过验证」),两个都开也只花一条消息。
|
|
25
|
+
- **机制在 `src/deliberation.js`,有界且不可能污染工具结果。** `createProgressWatch`/`beginTurn`/`noteCall`/`planRepeatNudge` 加常量 `MAX_REPEAT_NUDGES = 2`、`REPEAT_CALLS = 2`、`STALE_RESULTS = 2`;内存上限 `RUN_MAX = 64` 个会话、每回合 `HISTORY_MAX = 8` 次调用;全部调用都包在既有的 catch 里,检测失败只会丢一条提醒,不会改变任何一步工具结果。
|
|
26
|
+
- **实测(`DP17`,`debugfix` + `migrate`,每族 6 对共 12 对、五个 arm 配置按对轮转,共 60 次运行;比值 = 该臂墙钟 / `off` 墙钟,逐对几何平均,括号是 95 % bootstrap CI):**
|
|
27
|
+
|
|
28
|
+
| 开关 | 汇总墙钟比 | 更快 | 测试 |
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
| `probeFirst` | 0.883× [0.663, 1.176] | 7/12 对 | 全绿 |
|
|
31
|
+
| `actBeforePlan` | 0.761× [0.578, 1.032] | 8/12 对 | 全绿 |
|
|
32
|
+
| `repeatNudge` | 1.007× [0.839, 1.227] | 7/12 对 | 全绿 |
|
|
33
|
+
| 三个全开(`trio17`) | **0.647× [0.501, 0.893]** | **10/12 对** | 全绿 |
|
|
34
|
+
|
|
35
|
+
分家族看差别很大:`debugfix` 上 `actBeforePlan` 0.582×、6/6 更快,思考字符(几何均值)8249 → 3152(**这正对着「思考链过长」这个现象**);`migrate` 上它 0.996×、步数反而(几何均值)11.0 → 15.65,说明该族需要先规划,硬推会绕路。`probeFirst` 在 `migrate` 上 0.785×(思考字符 61560 → 45499),在 `debugfix` 上 0.993×。`repeatNudge` 单开等于没变,但它在组合里不拖后腿——三开 0.647× 是本次唯一置信区间不跨过 1 的臂。**所有臂、所有对,判分与 `off` 一致,零失败。** 更宽的三族验证(`DP18`)跑在 `codeimpl`/`ledger`/`stategraph` 上,结果补齐后写进 `BENCHMARK.md`。
|
|
36
|
+
- **`repeatNudge` 为什么单开等于没变:它基本没被触发。** 把 `rn17` 那 12 个会话的记录翻出来数提醒原文:12 个会话里只有 2 个各收到过提醒(`debugfix-p2` 一条、`p5` 两条),合计 **3 条**,而且全部来自「连续结果内容相同」那条分支(观察到的相同条数是 3、7、7);「同一调用本回合已跑 ≥2 次」这条分支**一次都没满足**。原因不是逻辑坏了,是阈值对着「极端打转」而不是「日常长链」:本语料里模型很少把同一个调用原样重发第三遍。所以 1.007× 的读数其实是「几乎没发生」的读数,不能当成「提醒没用」。这一条如实写在这里,下一轮要改就改阈值本身(不加开关、不加面板行),并用新的臂重测。
|
|
37
|
+
|
|
38
|
+
- **没有动的东西:** 默认值一个没改(`enabled: false` 仍是出厂态)、`d2`/`d2g`/`dr8` 仍然 HOLD、没有新增提醒时机或预算旋钮、没有新增任何请求字段或系统提示段落。
|
|
39
|
+
- 测试 338 → **334 全绿**(删 15 条 lazy 测试,新增 `test/deliberation.test.js` 10 条 + `test/plugin.test.js` 9 条集成)。动 `index.js`(删流式 reasoning 块、入场接线、`agent/request` 原样返回、版本号)、`src/deliberation.js`(新)、`src/config.js`(三键换三键,32 键)、`src/effort.js`、`src/state.js`、`client.js`(三行面板 + 两个白名单 + 四个写路径)、`src/lazy.js` 与 `test/lazy.test.js`(删除)、`test/{client,config,effort,metrics,plugin,state}.test.js`、`bench/arm-config.mjs`、`bench/suite-run.py`、`bench/arms/{pf17,ab17,rn17,trio17}.yml`(新)、`package.json`、两份 README、`docs/REFERENCE.md`、`BENCHMARK.md`。
|
|
40
|
+
|
|
41
|
+
- **`DP18` 补齐(三族复核,1.7.0 的臂):** `codeimpl`/`ledger`/`stategraph` 各 3 对、36 次运行,`trio17` **0.491×** [0.314, 0.788]、8/9 更快,`ab17` 0.643× [0.427, 0.920],`pf17` 0.719× [0.492, 0.999],判分全绿;与 `DP17` 合池 21 对:`ab17` 0.708× [0.558, 0.898]、`trio17` 0.575× [0.444, 0.748]。三个 arm 的方向在两族短任务(`DP17`)与三族长任务(`DP18`)上一致,`trio17` 是唯一在两块里 CI 都不跨 1 的臂。详见 `BENCHMARK.md` 的「块 DP18」。
|
|
42
|
+
|
|
43
|
+
## 1.6.2(修面板:`lazy` 那张卡以前点不开;标签改成能看懂的说法;lazy 的梯子文本做了三版对照,不换默认)
|
|
44
|
+
|
|
45
|
+
- **「过度思考时降档」以前点不开,是真的坏了。** `client.js` 里浏览器侧的 `sessions` 列有两处白名单:`sanitiseChoices` 和 `withOwn`,它们认识 `enabled/gear/discipline/stepBudget/map/batch` 六个字段,唯独没写 `lazy`。于是点击「打开」时写出去的会话条目里根本没有这个 key,宿主读回来是「没有条目」,面板再读一遍又画成「关」——看起来就是按钮没有反应。宿主侧 `src/state.js` 一直是认识 `lazy` 的,缺的只是浏览器这一半。两处都补上,并加了一条跨侧回归测试(`test/state.test.js`:浏览器序列化 → 宿主 `choiceFor` 读回 `{lazy:true}` → 浏览器 `parseChoices` 再读回 `true`;非布尔值仍被丢弃)。**旧版本里已经点过的人不会留下坏数据**,因为那次点击压根没写进去。
|
|
46
|
+
- **标签改名,说明手段而不是口号。** 面板第六行从「想太久就少想一点」改成 **「过度思考时降档」**(英文 `Cap over-thinking`),tooltip 写清条件与保证:「一步里推理超量时,下一个请求降一档;安全校验照旧」。旧说法是建议、听起来像文风;新说法说的是这个开关实际做的事,也交代了降的是什么。
|
|
47
|
+
- **`lazy` 的梯子文本做了三版对照(`lazyVariant`,只在 bench 里选,不进面板)。** `v1` 是 1.6.0/1.6.1 已经发布的那份文本;`v2` 在它后面加两条(「不要重述任务或先解释计划」「下一步已经清楚就直接做,不要再权衡一遍不打算采用的方案」);`v3` 是同样规则的精简重写(629 字符 vs 762)。两轮对照(`LZ2` 12 对 36 次运行、`codeimpl`+`ledger`;`LZ3` 15 对 30 次运行、`debugfix`+`migrate`+`stategraph`)的结论是 **不换文本**:`LZ2` 里 v2 对 v1 是 0.699×(9/12 更快),但 `LZ3` 里反过来是 0.822×、中位 1.014、7/15 更快,`debugfix` 五对**全慢**(1.08–1.23×)——短任务上多出来的两句话是纯成本。v3 在 `LZ2` 是 0.997×,等于没变。两轮判分都和对照臂完全一致(648/648、370/370),所以这不是质量换速度,是**只在长任务上划算、在短任务上倒亏**的取舍;默认仍是 `v1`,`lazyVariant` 保留为复现实验用的隐藏字段,面板上看不到。
|
|
48
|
+
- **没有动的东西:** 默认值一个没改(`enabled: false`、`lazy: false` 仍是出厂态)、`lazyEffort` 仍默认 `true`、`HOT_CHARS`/`NUDGE_CHARS`/降档上限全部照旧、`d2`/`d2g`/`dr8` 仍然 HOLD、没有新增任何提醒时机或预算旋钮。
|
|
49
|
+
- 测试 336 → **338 全绿**。动 `client.js`(两处白名单 + 标签)、`src/config.js`(`lazyVariant`)、`src/lazy.js`(`DIRECTIVES` 三版)、`src/effort.js`、`index.js`(版本号 + 传 `variant`)、`test/state.test.js`、`test/config.test.js`、`test/lazy.test.js`、`bench/suite-run.py`、`bench/arm-config.mjs`、`bench/arms/lz2v{1,2,3}.yml`(新)、两份 README、`docs/REFERENCE.md`、`BENCHMARK.md`。
|
|
50
|
+
|
|
3
51
|
## 1.6.1(1.6.0 的补包:npm 页面上那句「从不改 reasoningEffort」在 1.6.0 之后不准确了)
|
|
4
52
|
|
|
5
53
|
- 1.6.0 加了 `lazy`(默认关闭,唯一会改 `reasoningEffort` 的路径),但 `package.json` 的 `description` 还是旧话「Never changes reasoning effort, the model, or the request body」,npm 首页会照抄这句。这一版只改这一句:**默认**不改推理强度、模型与请求体,例外是默认关闭的 `lazy`(想太久时降一档)。行为、默认值、测试零改动(336 全绿)。
|
package/README.en.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
11
11
|
<b>DeepSeek Harness's own fast mode: a few configs that set how fast a task runs.</b><br>
|
|
12
|
-
Never changes the model,
|
|
12
|
+
Never changes the model, its reasoning effort, or any request field; it cuts redundant round trips and output through execution-strategy hints — the gain is fewer steps and fewer output tokens, not deleted narration. The switches added in 1.7.0 are all prompt-side and off by default; the switch is yours (1.7.1 adds a length-triggered notice inside `actBeforePlan`, still no request field touched).
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
@@ -40,11 +40,11 @@ A step costs round-trip overhead × steps + decode time × output tokens + tool
|
|
|
40
40
|
- **Output discipline.** Asks the model to skip call previews, restatements and progress reports, never to shorten the final answer. Honest scope: visible assistant prose is only **1.18 %** of the characters in (prose + tool arguments) (def15, 341 sessions / 3,327 messages / 3,569 calls, 51,366 prose vs 4,315,096 argument characters; excludes reasoning and tool results; recompute with `python3 bench/textshare.py --limit 0`), so the speedup cannot be attributed to deleted narration — it comes from fewer round trips and fewer output tokens (fewer repeat edits, re-reads and verification passes). That is not the same claim as "nothing about the work changes".
|
|
41
41
|
- **Stall watchdog.** Shell/script calls get a 120–300 s adaptive cap; a stuck call is cancelled and "change the approach" is written back into the context.
|
|
42
42
|
|
|
43
|
-
No model switch
|
|
43
|
+
No model switch and no request-field injection of any kind: `agent/request` returns unchanged, not one byte of `reasoningEffort` is written, no exceptions (`service_tier`, `max_tokens`, anything like them). While the mode is on, the model's input carries this plugin's own scheduling guidance and reminders — that is the mechanism; switch the mode off and they are gone. DeepSeek's official API, an OpenAI-compatible relay, a self-hosted gateway, Anthropic routes — all work the same.
|
|
44
44
|
|
|
45
45
|
## Three boundaries
|
|
46
46
|
|
|
47
|
-
- **The explicit promise**: the plugin does not change the model, does not inject request
|
|
47
|
+
- **The explicit promise**: the plugin does not change the model, does not inject any request field, and does not rewrite `reasoningEffort`. Since 1.7.0 that has no exception: the old "one rung down" half was removed together with `lazy`, because it measured no extra gain and was the only mechanism that could change an answer.
|
|
48
48
|
- **Honest mechanism**: execution-strategy hints cut redundant round trips and output. The evidence is falling steps and output tokens (whole-pool default arm: 0.806× steps, 0.818× output); no claim that the gain comes from deleting narration.
|
|
49
49
|
- **Quality boundary**: quality is judged by hidden tests and real evaluations, and behaviour is not claimed to be fully equivalent. When the quality gate fails, quality wins: experimental knobs ship off, and the default is only adopted from batches where both arms' hidden assertions match cell by cell.
|
|
50
50
|
|
|
@@ -103,19 +103,21 @@ Legacy `fast` / `turbo` / `max` / `ludicrous` values are read as `auto` with a d
|
|
|
103
103
|
|
|
104
104
|
## The switch
|
|
105
105
|
|
|
106
|
-
The bolt is the switch: one click writes on/off, per conversation, restored on reload. Right-click it for a
|
|
106
|
+
The bolt is the switch: one click writes on/off, per conversation, restored on reload. Right-click it for a seven-row panel — all seven affect this conversation only:
|
|
107
107
|
|
|
108
108
|
- **Less narration** — master switch for the step-4 reminder; with it off, long tasks take about 2.7x longer and write about twice as much. On by default.
|
|
109
109
|
- **Step cap** — `15` / `30` / off, off by default. At the cap it reports instead of truncating the task.
|
|
110
110
|
- **Workspace inventory** — before the turn's first tool call, one inventory notice (relative paths + byte sizes + visible test entry points) so the turn does not open with `ls`/`find`. Off by default; over 23 pairs it measured 0.927x geometric with a slower tail and 10% more steps, so it stays a switch to try rather than a default.
|
|
111
111
|
- **Read several files at once** — batches independent reads into one call. Off by default; the measured gain shows up when it is stacked with the inventory switch (below), not alone.
|
|
112
|
-
- **
|
|
112
|
+
- **Read one uncertain fact first** (`probeFirst`) — at turn entry, one notice: if a codebase fact is uncertain, read it once instead of reasoning about it. Off by default; 0.883x over 12 pairs (7/12 faster).
|
|
113
|
+
- **Act before explaining** (`actBeforePlan`) — at most one line of plan before the first action; act as soon as the next step is clear. Since 1.7.1 it also carries a length-triggered notice: once this turn has written 4000 characters of reasoning, the next step learns how much it wrote and gets two exits — act on the evidence, or read the one fact still missing (at most two per turn). Off by default; 0.761x over 12 pairs (8/12 faster) with reasoning characters 8249 → 3152 on `debugfix`; 0.643x over 9 pairs (6/9 faster) on three families in `DP18`, 0.708x [0.558, 0.898] pooled over 21 pairs.
|
|
114
|
+
- **Nudge on repetition** (`repeatNudge`) — when the same call has already run twice this turn, or three results in a row are identical, one line says how many times it repeated and asks for a different approach or a conclusion. Off by default; 1.007x alone, but it does not drag the three-switch combination down.
|
|
113
115
|
|
|
114
|
-
All
|
|
116
|
+
All seven rows take effect from the next request, per conversation. No dropdown, no multiplier estimate.
|
|
115
117
|
|
|
116
|
-
**Turn several on at once?** Yes, but only the measured pair. Defaults plus inventory plus batched reads is **0.742x** over 11 pairs; adding the step-2 reminder timing (not a panel row, still on HOLD) reaches **0.669x** over 22 pairs, CI95 [0.554, 0.799], 18/22 faster, hidden tests green. Each
|
|
118
|
+
**Turn several on at once?** Yes, but only the measured pair. Defaults plus inventory plus batched reads is **0.742x** over 11 pairs; adding the step-2 reminder timing (not a panel row, still on HOLD) reaches **0.669x** over 22 pairs, CI95 [0.554, 0.799], 18/22 faster, hidden tests green. Each of those two alone lands near 0.93x with a confidence interval that crosses 1 — the gain comes from each one cutting a different share of the same cost, not from any single switch. The other knobs (`batchVerify`, `preferPatch`, step budget, wider fan-out) all land at 0.96–1.10; do not stack them.
|
|
117
119
|
|
|
118
|
-
`
|
|
120
|
+
`probeFirst` / `actBeforePlan` / `repeatNudge` are the 1.7.0 additions; 1.7.1 adds a length-triggered notice inside `actBeforePlan` (no new switch, the panel stays seven rows). All three on (`trio17`) is the only arm whose interval stays below 1 in both blocks: **0.647x** [0.501, 0.893], 10/12 faster over 12 pairs in `DP17`; **0.491x** [0.314, 0.788], 8/9 faster over 9 pairs in `DP18`; **0.575x** [0.444, 0.748], 18/21 faster pooled over 21 pairs, grading green. `repeatNudge` alone is 1.007x and fired only 3 times across twelve sessions — that is "it almost never happened", not "it does not work"; `actBeforePlan` alone is 0.761x / 0.643x in the two blocks. None of them changes an answer or writes a request field, so they stay off by default.
|
|
119
121
|
|
|
120
122
|
The idea draws on `dsh-batch-tool-calls` and `dsh-ops` (batched calls, bounded execution), but their widths are static while this width comes from the conversation's own call evidence; do not install all three. Context-compaction plugins coexist.
|
|
121
123
|
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
11
11
|
<b>DeepSeek Harness 自己的快速模式:用几项配置控制任务的运行速度。</b><br>
|
|
12
|
-
默认不改模型、不改 reasoningEffort
|
|
12
|
+
默认不改模型、不改 reasoningEffort、不改任何请求字段;用执行策略提示减少冗余回合与输出——收益来自步数与输出 token 下降,不是删旁白。几个 1.7.0 新开关都是纯提示侧,默认关,开关在你手里(1.7.1 给 `actBeforePlan` 加了一条按思考长度的提醒,同样不碰请求字段)。
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
- **输出纪律**:提示模型不预告调用、不复述结果、不写进度报告,但**不缩短最终答案**。口径要说清:实测里可见助手正文只占「正文+工具参数」字符的 **1.19%**(def15 全量 385 会话 / 3,659 消息 / 4,007 调用,正文 57,101 / 参数 4,757,921 字符;不含 reasoning 与工具返回;`python3 bench/textshare.py --limit 0` 可复算),所以提速不能归因于删旁白——它来自回合数与输出 token 变少(少重复编辑、少回头读、少验证往返),这和「内容不受影响」不是一回事。
|
|
41
41
|
- **卡顿看门狗**:给 shell/脚本类调用设 120–300 秒自适应上限,卡住的调用被取消并把“换做法”写回上下文。
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
没有模型切换、没有任何请求字段注入:`agent/request` 原样返回,`reasoningEffort` 一个字节都不写,没有例外;开着时模型输入里会多出本插件自己的调度提示与提醒(这是机制本身),关掉后连这些也不存在。DeepSeek 官方 API、OpenAI 兼容中转、自建网关、Anthropic 协议 —— 走哪条路由都成立。
|
|
44
44
|
|
|
45
45
|
## 三条边界
|
|
46
46
|
|
|
47
|
-
-
|
|
47
|
+
- **明确承诺**:不改模型、不注入任何请求字段、不改 `reasoningEffort`。1.7.0 起这条没有例外——上一版那半个「降一档」因为测不出额外收益、且是全插件唯一会改答案的机制,已经连同 `lazy` 一起删除。
|
|
48
48
|
- **机制诚实**:靠执行策略提示减少冗余回合与输出。证据是步数与输出 token 下降(全池默认臂 0.806× 步数、0.818× 输出);不宣称收益来自「删旁白」。
|
|
49
49
|
- **质量边界**:任务质量以隐藏测试判分与真实评测为准,不宣称行为完全等价。质量门槛不过就优先保质量:实验性旋钮默认关闭,默认配置只在两臂隐藏断言逐格相同的批次里采用。
|
|
50
50
|
|
|
@@ -103,20 +103,21 @@
|
|
|
103
103
|
|
|
104
104
|
## 开关
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
闪电就是开关:点一下即开/关,按会话独立,重启按会话恢复。右键闪电是一块七行的面板(闪电自己就是开关,不占行),七行都只影响当前会话:
|
|
107
107
|
|
|
108
|
-
- **更快**:这个会话开不开快模式,和点闪电是同一件事。
|
|
109
108
|
- **少写过程**:第 4 步那句「省着写」提醒的总开关,关掉后输出会变长、耗时变慢(长任务约 2.7×),默认开。
|
|
110
109
|
- **最多几步**:`15` / `30` / 不限,默认不限。到上限只先汇报,不截断任务。
|
|
111
110
|
- **先列文件清单**:开启后,回合的第一次工具调用之前先收到一份工作目录清单(相对路径 + 字节数 + 可见的测试入口),省掉开头的 `ls`/`find` 探路。默认关;23 个配对实测几何 0.927×,尾部变慢、步数 +10%,没有达到进默认的门槛,只作为可试的开关。
|
|
112
111
|
- **一次读多个文件**:把互不依赖的读取合成一批发出,少几个来回。默认关;单独开测不到显著,和上一项一起开才有(见下)。
|
|
113
|
-
-
|
|
112
|
+
- **不确定时先查一次**(`probeFirst`):入场时提醒一句——拿不准的代码库事实去读一次,不要用推理猜。默认关;12 对实测 0.883×(7/12 更快)。
|
|
113
|
+
- **先动手再解释**(`actBeforePlan`):第一次动手前最多写一行计划,动作清楚就直接做;1.7.1 起它还带一条按思考长度触发的提醒——本回合思考写到 4000 字符(约 2000 汉字)后,下一步之前告诉你写了多少,并给「按证据动手,或去读那一个还缺的事实」两个出口(每回合最多两条)。默认关;`DP17` 12 对 0.761×(8/12 更快),`debugfix` 一族 0.582×、思考字符 8249 → 3152;`DP18` 三族 9 对 0.643×(6/9 更快),合池 21 对 0.708× [0.558, 0.898]。
|
|
114
|
+
- **重复无进展时提醒**(`repeatNudge`):同一调用本回合已跑过两次、或连续三条结果内容完全一样时,说一句「已重复 N 次,换方法或给结论」。默认关;单开 1.007×,但在三开组合里不拖后腿。
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
七项都写在本会话的条目里,对下一个回合生效;另一个会话开不开、写成什么样,互不影响。没有下拉,没有倍数估算。
|
|
116
117
|
|
|
117
|
-
**几个一起开会不会更快?** 会,但只有实测过的那几个。默认 + `workspaceMap` + `openBatch` 两开:11 对 **0.742×**;再把 `disciplineAfterSteps` 提前到 2(面板里没有这一项,属于 HOLD 的时点实验)三开:22 对 **0.669×**、CI95 [0.554, 0.799]、18/22
|
|
118
|
+
**几个一起开会不会更快?** 会,但只有实测过的那几个。默认 + `workspaceMap` + `openBatch` 两开:11 对 **0.742×**;再把 `disciplineAfterSteps` 提前到 2(面板里没有这一项,属于 HOLD 的时点实验)三开:22 对 **0.669×**、CI95 [0.554, 0.799]、18/22 更快、隐藏测试全绿。单独开其中任何一个都测不到显著(置信区间全跨 1)——所以增益来自它们各自省掉的是同一类成本的不同份,不是哪个开关本身。其余开关(`batchVerify`、`preferPatch`、步数预算、更宽并行)叠上去都是 0.96–1.10,没有理由跟着一起开。细节见 [BENCHMARK.md](BENCHMARK.md) 的「直接跑一次多个开关一起开」。
|
|
118
119
|
|
|
119
|
-
`
|
|
120
|
+
`probeFirst` / `actBeforePlan` / `repeatNudge` 三个是 1.7.0 新加的纯提示侧开关,1.7.1 给 `actBeforePlan` 补了一条按思考长度触发的提醒(不新增开关、面板仍是七行)。三开(`trio17`)在两块实测里都是唯一置信区间不跨 1 的臂:`DP17` 12 对 **0.647×** [0.501, 0.893]、10/12 更快;`DP18` 三族 9 对 **0.491×** [0.314, 0.788]、8/9 更快;合池 21 对 **0.575×** [0.444, 0.748]、18/21 更快,判分全绿。单开 `repeatNudge` 等于没变(1.007×,且十二个会话里只触发 3 次——这是「几乎没发生」,不是「无效」),单开 `actBeforePlan` 两块分别 0.761× / 0.643×。它们不改答案、不写请求字段,所以默认仍然关。
|
|
120
121
|
|
|
121
122
|
思路参考了 `dsh-batch-tool-calls` 与 `dsh-ops`(批量调用、有界执行),但它们的规则是静态的,这里的宽度来自会话自身的调用证据;不需要同时装。压缩类插件可以共存。
|
|
122
123
|
|
package/client.js
CHANGED
|
@@ -104,8 +104,12 @@ window.__ModuleLoader__.load({
|
|
|
104
104
|
'panel.mapTitle': '开局把目录里的文件交给模型,省掉先翻一遍目录',
|
|
105
105
|
'panel.batch': '一次读多个文件',
|
|
106
106
|
'panel.batchTitle': '把互不依赖的读取合成一批发出,少几个来回',
|
|
107
|
-
'panel.
|
|
108
|
-
'panel.
|
|
107
|
+
'panel.probe': '不确定时先查一次',
|
|
108
|
+
'panel.probeTitle': '拿不准的事实读一次,别用推理猜',
|
|
109
|
+
'panel.act': '先动手再解释',
|
|
110
|
+
'panel.actTitle': '最多一行计划,动作清楚就直接做',
|
|
111
|
+
'panel.repeat': '重复无进展时提醒',
|
|
112
|
+
'panel.repeatTitle': '重跑同一个调用或连续无新信息时提醒',
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
const en = {
|
|
@@ -131,8 +135,12 @@ window.__ModuleLoader__.load({
|
|
|
131
135
|
'panel.mapTitle': 'Hands the directory listing to the model up front, skipping a lookup',
|
|
132
136
|
'panel.batch': 'Read several files at once',
|
|
133
137
|
'panel.batchTitle': 'Batches independent reads into one call, fewer round trips',
|
|
134
|
-
'panel.
|
|
135
|
-
'panel.
|
|
138
|
+
'panel.probe': 'Read before guessing',
|
|
139
|
+
'panel.probeTitle': 'Look up the fact you are unsure of once; a guess costs more; safety checks stay',
|
|
140
|
+
'panel.act': 'Act first',
|
|
141
|
+
'panel.actTitle': 'At most one line of plan before the first call; act when the next step is clear',
|
|
142
|
+
'panel.repeat': 'Nudge on repeats',
|
|
143
|
+
'panel.repeatTitle': 'One line when a call runs again or several steps bring nothing new; safety checks stay',
|
|
136
144
|
}
|
|
137
145
|
|
|
138
146
|
const CSS = [
|
|
@@ -196,8 +204,12 @@ window.__ModuleLoader__.load({
|
|
|
196
204
|
inventory: false,
|
|
197
205
|
/** Batches independent reads into one call for this conversation. */
|
|
198
206
|
batch: false,
|
|
199
|
-
/**
|
|
200
|
-
|
|
207
|
+
/**
|
|
208
|
+
* The three deliberation switches: read the missing fact, one line of plan,
|
|
209
|
+
* one evidence line when the turn stops learning. All off unless this
|
|
210
|
+
* conversation turned them on.
|
|
211
|
+
*/
|
|
212
|
+
probe: false, act: false, repeat: false,
|
|
201
213
|
/** This conversation's step cap; 0 means no cap. */
|
|
202
214
|
stepBudget: 0,
|
|
203
215
|
/** The right-click panel is open. Store-backed, like every other paint. */
|
|
@@ -327,6 +339,9 @@ window.__ModuleLoader__.load({
|
|
|
327
339
|
if (Number.isFinite(entry.stepBudget) && entry.stepBudget >= 0) clean.stepBudget = Math.floor(Number(entry.stepBudget))
|
|
328
340
|
if (typeof entry.map === 'boolean') clean.map = entry.map
|
|
329
341
|
if (typeof entry.batch === 'boolean') clean.batch = entry.batch
|
|
342
|
+
if (typeof entry.probeFirst === 'boolean') clean.probeFirst = entry.probeFirst
|
|
343
|
+
if (typeof entry.actBeforePlan === 'boolean') clean.actBeforePlan = entry.actBeforePlan
|
|
344
|
+
if (typeof entry.repeatNudge === 'boolean') clean.repeatNudge = entry.repeatNudge
|
|
330
345
|
if (Number.isFinite(entry.ts)) clean.ts = Number(entry.ts)
|
|
331
346
|
if (
|
|
332
347
|
clean.enabled === undefined
|
|
@@ -335,6 +350,9 @@ window.__ModuleLoader__.load({
|
|
|
335
350
|
&& clean.stepBudget === undefined
|
|
336
351
|
&& clean.map === undefined
|
|
337
352
|
&& clean.batch === undefined
|
|
353
|
+
&& clean.probeFirst === undefined
|
|
354
|
+
&& clean.actBeforePlan === undefined
|
|
355
|
+
&& clean.repeatNudge === undefined
|
|
338
356
|
) continue
|
|
339
357
|
out[sessionId] = clean
|
|
340
358
|
}
|
|
@@ -383,7 +401,7 @@ window.__ModuleLoader__.load({
|
|
|
383
401
|
*
|
|
384
402
|
* @param {Record<string, any>} map
|
|
385
403
|
* @param {string|undefined} sessionId
|
|
386
|
-
* @param {{enabled?: boolean, gear?: string, discipline?: boolean|'late', stepBudget?: number, map?: boolean, batch?: boolean}} patch
|
|
404
|
+
* @param {{enabled?: boolean, gear?: string, discipline?: boolean|'late', stepBudget?: number, map?: boolean, batch?: boolean, probeFirst?: boolean, actBeforePlan?: boolean, repeatNudge?: boolean}} patch
|
|
387
405
|
*/
|
|
388
406
|
function withOwn(map, sessionId, patch) {
|
|
389
407
|
const next = { ...map }
|
|
@@ -397,6 +415,9 @@ window.__ModuleLoader__.load({
|
|
|
397
415
|
if (Number.isFinite(patch.stepBudget) && patch.stepBudget >= 0) entry.stepBudget = Math.floor(Number(patch.stepBudget))
|
|
398
416
|
if (typeof patch.map === 'boolean') entry.map = patch.map
|
|
399
417
|
if (typeof patch.batch === 'boolean') entry.batch = patch.batch
|
|
418
|
+
if (typeof patch.probeFirst === 'boolean') entry.probeFirst = patch.probeFirst
|
|
419
|
+
if (typeof patch.actBeforePlan === 'boolean') entry.actBeforePlan = patch.actBeforePlan
|
|
420
|
+
if (typeof patch.repeatNudge === 'boolean') entry.repeatNudge = patch.repeatNudge
|
|
400
421
|
next[sessionId] = entry
|
|
401
422
|
return next
|
|
402
423
|
}
|
|
@@ -543,9 +564,15 @@ window.__ModuleLoader__.load({
|
|
|
543
564
|
const seenBatch = own !== undefined && typeof own.batch === 'boolean'
|
|
544
565
|
? own.batch
|
|
545
566
|
: value.openBatch === true
|
|
546
|
-
const
|
|
547
|
-
? own.
|
|
548
|
-
: value.
|
|
567
|
+
const seenProbe = own !== undefined && typeof own.probeFirst === 'boolean'
|
|
568
|
+
? own.probeFirst
|
|
569
|
+
: value.probeFirst === true
|
|
570
|
+
const seenAct = own !== undefined && typeof own.actBeforePlan === 'boolean'
|
|
571
|
+
? own.actBeforePlan
|
|
572
|
+
: value.actBeforePlan === true
|
|
573
|
+
const seenRepeat = own !== undefined && typeof own.repeatNudge === 'boolean'
|
|
574
|
+
? own.repeatNudge
|
|
575
|
+
: value.repeatNudge === true
|
|
549
576
|
store.phase = 'ready'
|
|
550
577
|
store.error = ''
|
|
551
578
|
store.ns = view.ns
|
|
@@ -556,7 +583,9 @@ window.__ModuleLoader__.load({
|
|
|
556
583
|
store.stepBudget = seenBudget
|
|
557
584
|
store.inventory = seenMap
|
|
558
585
|
store.batch = seenBatch
|
|
559
|
-
store.
|
|
586
|
+
store.probe = seenProbe
|
|
587
|
+
store.act = seenAct
|
|
588
|
+
store.repeat = seenRepeat
|
|
560
589
|
// A write we have not seen echoed yet wins: the Loader applies the new
|
|
561
590
|
// section asynchronously, and flipping back to the old paint in that
|
|
562
591
|
// window would read as a failed click.
|
|
@@ -610,7 +639,7 @@ window.__ModuleLoader__.load({
|
|
|
610
639
|
*
|
|
611
640
|
* @param {{settings: {update: (ns: string, patch: object, revision?: number) => Promise<any>}}} remote
|
|
612
641
|
* @param {{enabled?: boolean, gear?: string, outputDiscipline?: boolean|'late', stepBudget?: number, workspaceMap?: boolean}} [patch]
|
|
613
|
-
* @param {{entry?: {enabled?: boolean, gear?: string, discipline?: boolean|'late', stepBudget?: number, map?: boolean, batch?: boolean}}} [options]
|
|
642
|
+
* @param {{entry?: {enabled?: boolean, gear?: string, discipline?: boolean|'late', stepBudget?: number, map?: boolean, batch?: boolean, probeFirst?: boolean, actBeforePlan?: boolean, repeatNudge?: boolean}}} [options]
|
|
614
643
|
* @returns {Promise<boolean>} whether the write was accepted
|
|
615
644
|
*/
|
|
616
645
|
async function write(remote, patch, options = {}) {
|
|
@@ -634,7 +663,9 @@ window.__ModuleLoader__.load({
|
|
|
634
663
|
if (typeof entry.stepBudget === 'number') store.stepBudget = entry.stepBudget
|
|
635
664
|
if (typeof entry.map === 'boolean') store.inventory = entry.map
|
|
636
665
|
if (typeof entry.batch === 'boolean') store.batch = entry.batch
|
|
637
|
-
if (typeof entry.
|
|
666
|
+
if (typeof entry.probeFirst === 'boolean') store.probe = entry.probeFirst
|
|
667
|
+
if (typeof entry.actBeforePlan === 'boolean') store.act = entry.actBeforePlan
|
|
668
|
+
if (typeof entry.repeatNudge === 'boolean') store.repeat = entry.repeatNudge
|
|
638
669
|
}
|
|
639
670
|
if (typeof shared.enabled === 'boolean') {
|
|
640
671
|
store.enabled = shared.enabled
|
|
@@ -646,7 +677,9 @@ window.__ModuleLoader__.load({
|
|
|
646
677
|
if (typeof shared.stepBudget === 'number') store.stepBudget = shared.stepBudget
|
|
647
678
|
if (typeof shared.workspaceMap === 'boolean') store.inventory = shared.workspaceMap
|
|
648
679
|
if (typeof shared.openBatch === 'boolean') store.batch = shared.openBatch
|
|
649
|
-
if (typeof shared.
|
|
680
|
+
if (typeof shared.probeFirst === 'boolean') store.probe = shared.probeFirst
|
|
681
|
+
if (typeof shared.actBeforePlan === 'boolean') store.act = shared.actBeforePlan
|
|
682
|
+
if (typeof shared.repeatNudge === 'boolean') store.repeat = shared.repeatNudge
|
|
650
683
|
emit()
|
|
651
684
|
try {
|
|
652
685
|
unwrap(await withTimeout(remote.settings.update(store.ns, outgoing, store.revision), 15000, 'settings/update'))
|
|
@@ -663,7 +696,9 @@ window.__ModuleLoader__.load({
|
|
|
663
696
|
store.stepBudget = before.stepBudget
|
|
664
697
|
store.inventory = before.inventory
|
|
665
698
|
store.batch = before.batch
|
|
666
|
-
store.
|
|
699
|
+
store.probe = before.probe
|
|
700
|
+
store.act = before.act
|
|
701
|
+
store.repeat = before.repeat
|
|
667
702
|
store.pending = undefined
|
|
668
703
|
store.writeError = describeError(error)
|
|
669
704
|
emit()
|
|
@@ -879,12 +914,23 @@ window.__ModuleLoader__.load({
|
|
|
879
914
|
emit()
|
|
880
915
|
}
|
|
881
916
|
|
|
882
|
-
/**
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
917
|
+
/** Read the fact instead of reasoning about it. */
|
|
918
|
+
const toggleProbe = () => {
|
|
919
|
+
void write(remote, undefined, { entry: { probeFirst: !store.probe } })
|
|
920
|
+
store.panelOpen = false
|
|
921
|
+
emit()
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/** At most one line of plan before the first tool call. */
|
|
925
|
+
const toggleAct = () => {
|
|
926
|
+
void write(remote, undefined, { entry: { actBeforePlan: !store.act } })
|
|
927
|
+
store.panelOpen = false
|
|
928
|
+
emit()
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/** One evidence line when the turn repeats a call or stops learning. */
|
|
932
|
+
const toggleRepeat = () => {
|
|
933
|
+
void write(remote, undefined, { entry: { repeatNudge: !store.repeat } })
|
|
888
934
|
store.panelOpen = false
|
|
889
935
|
emit()
|
|
890
936
|
}
|
|
@@ -923,12 +969,30 @@ window.__ModuleLoader__.load({
|
|
|
923
969
|
),
|
|
924
970
|
row(
|
|
925
971
|
'menuitemcheckbox',
|
|
926
|
-
t('panel.
|
|
927
|
-
t(store.
|
|
972
|
+
t('panel.probe'),
|
|
973
|
+
t(store.probe ? 'panel.on' : 'panel.off'),
|
|
974
|
+
canWrite,
|
|
975
|
+
toggleProbe,
|
|
976
|
+
store.probe,
|
|
977
|
+
t('panel.probeTitle'),
|
|
978
|
+
),
|
|
979
|
+
row(
|
|
980
|
+
'menuitemcheckbox',
|
|
981
|
+
t('panel.act'),
|
|
982
|
+
t(store.act ? 'panel.on' : 'panel.off'),
|
|
983
|
+
canWrite,
|
|
984
|
+
toggleAct,
|
|
985
|
+
store.act,
|
|
986
|
+
t('panel.actTitle'),
|
|
987
|
+
),
|
|
988
|
+
row(
|
|
989
|
+
'menuitemcheckbox',
|
|
990
|
+
t('panel.repeat'),
|
|
991
|
+
t(store.repeat ? 'panel.on' : 'panel.off'),
|
|
928
992
|
canWrite,
|
|
929
|
-
|
|
930
|
-
store.
|
|
931
|
-
t('panel.
|
|
993
|
+
toggleRepeat,
|
|
994
|
+
store.repeat,
|
|
995
|
+
t('panel.repeatTitle'),
|
|
932
996
|
),
|
|
933
997
|
react.createElement('div', { className: 'fm-panel__scope' }, t('panel.scope')),
|
|
934
998
|
)
|