dsh-fast-mode 1.5.25 → 1.5.27
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 +48 -0
- package/CHANGELOG.md +15 -0
- package/bench/ablate.py +172 -0
- package/docs/REFERENCE.md +1 -1
- package/index.js +1 -1
- package/package.json +2 -1
package/BENCHMARK.md
CHANGED
|
@@ -1944,6 +1944,23 @@ python3 bench/suite-run.py --tasks debugfix,ledger,codeimpl --arms off,def15,bud
|
|
|
1944
1944
|
|
|
1945
1945
|
任何一条不过 ⇒ 这条线判为「时点不可救」,默认永久停在 4,不再追。
|
|
1946
1946
|
|
|
1947
|
+
### 补测(2026-10-29,`D2G2`):闸门没覆盖过的两族补上,方向相反
|
|
1948
|
+
|
|
1949
|
+
上面的 21 对只覆盖 `codeimpl`/`debugfix`/`migrate`。闸门的常数 2 在 `ledger`/`shellpipeline` 上一次都没验过,而这两族恰好是 `d2`(无闸门提前)最两极的地方(`ledger` 0.506×、`shellpipeline` 1.111×)。`D2G2` 用这两族各 3 对补齐(`def15` 为基线,12 行全部可用、丢弃 0、质量零倒退):
|
|
1950
|
+
|
|
1951
|
+
```
|
|
1952
|
+
python3 bench/suite-run.py --tasks ledger,shellpipeline --arms def15,d2g --pairs 3 --tag D2G2
|
|
1953
|
+
python3 bench/block_score.py D2G2 def15 d2g
|
|
1954
|
+
```
|
|
1955
|
+
|
|
1956
|
+
| 族 | 对 | 几何 | 逐对比值 | 备注 |
|
|
1957
|
+
|---|---|---|---|---|
|
|
1958
|
+
| `ledger` | 3 | **1.898×** | 2.68 / 0.95 / **2.70** | 输的两对步数 8→10、7→13,输出 12.1k→34.0k、15.9k→29.1k token |
|
|
1959
|
+
| `shellpipeline` | 3 | **0.597×** | 0.47 / 0.69 / 0.66 | 赢的三对步数 23→19、27→10、24→17 |
|
|
1960
|
+
| 合并(= 上节 21 对 + 6 对) | 27 | **0.816×** CI95 [0.650, 1.023] | 18/27 更快 | 中位 0.719×、步数 0.892×、输出 0.777×、符号 p=0.122 |
|
|
1961
|
+
|
|
1962
|
+
**判定:HOLD 不变,默认继续停在第 4 步。** 补测不是把 CI 收窄,而是把结论说得更准:同一个时点在两族上方向相反——`shellpipeline` 这种「一条命令跑完再读结果」的任务提前提醒很值(0.597×),`ledger` 这种要逐笔对账的任务提前提醒会让它重做并超写(输出 token 涨到 1.9×,单对 2.7×)。所以「第一步调了几次」不是这个时点该用的信号,**时点类旋钮到此收档**:默认 4 不再动,也不再为新时点补块。
|
|
1963
|
+
|
|
1947
1964
|
## 预注册:`disciplineRepeatAtSteps`(第二次压缩提醒)的通过判据(2026-10-28,先写判据再跑)
|
|
1948
1965
|
|
|
1949
1966
|
**为什么是它。** 合并块里唯一被证明有效的机制,是 `outputDiscipline: late` 在第 4 步注入的那一句「剩下的话只写下一步要用的」。它**每回合只发一次**。可是合池的逐格数据显示,回合越长,赢面越小:`debugfix` 1.032×、`perfrefactor` 1.009×、`csvpipe` 0.982×,而 `shellpipeline` 0.699×、`codeimpl` 0.710× —— 长的回合里,第一次提醒之后的那些步又把输出写长了。这不是新机制,同一个机制的第二枪:同一句话,在更晚的一步再说一次,每回合仍然最多一次。
|
|
@@ -2299,6 +2316,37 @@ python3 bench/block_score.py LEN3 def15 nodisc
|
|
|
2299
2316
|
- 所以**纪律提醒的独立份额目前不可判定**,不能对外报 1.54× / 1.79× 这类数字。能报的只有池化主效应(138 对 0.823×),其中「明细律」与其它提醒是同一个机制包里一起生效的,无法在单块里分离。
|
|
2300
2317
|
- 这条给「不要再加提醒时机、不要再加重复提醒」提供了同样甚至更强的支持:连唯一那条提醒的份额都测不出来,继续加同类触发点没有可验证的收益。
|
|
2301
2318
|
|
|
2319
|
+
## 多个开关一起开:默认之上再叠任何一个都是 0(59 个块、183 对池化的消融表)
|
|
2320
|
+
|
|
2321
|
+
单块的 ±20 % 噪声(见上一节 LEN3)意味着「一次只测一个开关、7 对下结论」必然出假信号。已经跑过的所有块加起来其实足够回答另一个问题:**在已发布的默认配置之上,再打开某个开关,还能不能更快?** 新增 `bench/ablate.py` 把所有块的全部臂按「同块、同任务、同 pair」对上锚点臂池化,锚点优先 `off`、缺了回落到 `def15`:
|
|
2322
|
+
|
|
2323
|
+
```
|
|
2324
|
+
python3 bench/ablate.py --ci 2000 # 相对 off
|
|
2325
|
+
python3 bench/ablate.py --ci 2000 --anchor def15 # 相对默认配置(叠开关的边际值)
|
|
2326
|
+
```
|
|
2327
|
+
|
|
2328
|
+
以 `def15` 为锚(59 个块;几何比 / 95 % bootstrap CI / 快过锚点的对数 / 符号检验 p):
|
|
2329
|
+
|
|
2330
|
+
| 臂 = 默认 + 打开 | n | wall 几何比 | CI95 | 中位 | 步数 | 输出 | 更快 | p |
|
|
2331
|
+
|---|---|---|---|---|---|---|---|---|
|
|
2332
|
+
| `d2`:明细律提前到第 2 步 | 41 | **0.695** | [0.565, 0.863] | 0.700 | 0.960 | 0.723 | 27/41 | 0.060 |
|
|
2333
|
+
| `d2g`:同上 + 第 1 步 ≥2 次调用才提前 | 27 | **0.816** | [0.650, 1.023] | 0.719 | 0.892 | 0.777 | 18/27 | 0.122 |
|
|
2334
|
+
| `map15` +`workspaceMap` | 23 | 0.802 | [0.648, 0.999] | 0.790 | 1.048 | 0.824 | 13/23 | 0.678 |
|
|
2335
|
+
| `open15` +`openBatch` | 53 | 0.882 | [0.740, 1.049] | 0.911 | 0.831 | 0.915 | 30/53 | 0.410 |
|
|
2336
|
+
| `bv15` +`batchVerify` | 39 | 0.963 | [0.813, 1.144] | 0.968 | 0.935 | 0.961 | 20/39 | 1.000 |
|
|
2337
|
+
| `bud8` +`stepBudget:8` | 26 | 0.971 | [0.783, 1.200] | 1.110 | 0.990 | 0.973 | 11/26 | 0.557 |
|
|
2338
|
+
| `pp16` +`preferPatch` | 34 | 0.988 | [0.803, 1.216] | 1.012 | 0.911 | 0.995 | 17/34 | 1.000 |
|
|
2339
|
+
| `wide15` 并行宽度拉大 | 20 | 1.075 | [0.796, 1.491] | 0.991 | 1.262 | 1.076 | 10/20 | 1.000 |
|
|
2340
|
+
| `nodisc` 关掉明细律 | 19 | 1.101 | [0.808, 1.492] | 1.110 | 0.998 | 1.049 | 8/19 | 0.648 |
|
|
2341
|
+
|
|
2342
|
+
- **结论 1:默认配置已经在平台上。** 除时点类两臂外,每个可选开关的 CI 都跨 1,几何比落在 0.80–1.08;把 `openBatch`、`workspaceMap`、`batchVerify`、`preferPatch`、更宽并行、步数预算一起打开,一个百分点都拿不到。所以「多开几个开关会更快」是错的——它们的收益在默认里已经兑现,或者从来就不存在。
|
|
2343
|
+
- **结论 2:唯一在池化下站得住的杠杆是「同一句提醒的时点」。** `d2` 41 对 0.695×(CI 上限 0.863 仍 < 1),但它是任务相关的:分族 `debugfix` 0.619、`ledger` 0.506、`migrate` 0.569,`codeimpl` **1.073**、`shellpipeline` **1.111**。加条件闸门后 `d2g` 把 `codeimpl` 收到 0.889,同时把 `debugfix` 的 0.619 抬到 0.903 ⇒ 池化一度是 0.756×(21 对)。把闸门从没测过的 `ledger`/`shellpipeline` 补上后(`D2G2`,6 对)这条也塌了:27 对 **0.816×**、CI95 **[0.650, 1.023]**、18/27 更快。
|
|
2344
|
+
- **结论 3:这两臂仍是 HOLD,不改默认。** `d2` 在 `codeimpl` 上是负收益,`d2g` 的闸门常量为 2、只在 3 个家族验过;按预注册判据(`D2_IMPL` 1.073×、3/8 更快)默认保持 `disciplineAfterSteps: 4`。这张表的作用是说明**没有别的开关可以在默认之上继续叠加**;`ledger`/`shellpipeline` 的补测(`D2G2`)已经做完,见下一节,闸门在这两族上方向相反,时点类两臂到此可以收档。
|
|
2345
|
+
|
|
2346
|
+
**顺带把「只挑了 12 个干净块」这个质疑也答了。** `ablate.py` 不挑块(59 个全进),默认臂对 `off` 的池化读数是 **183 对、几何 0.816×、CI95 [0.755, 0.881]、122/183 更快、符号 p < 0.0001**——与 `pool.py` 那 12 个干净块的 138 对 0.8234×(CI [0.744, 0.918])落在同一点上,置信区间还更窄。所以主结论不是选块选出来的。
|
|
2347
|
+
|
|
2348
|
+
**这张表的两个诚实边界**:不同臂覆盖的任务组合不同(跑一遍命令就能看到 `tasks` 列,`d2` 含 `codeimpl:8`、`map15` 只有 `codebase/debugfix/perfrefactor`),所以行与行之间不能直接排大小;以及每个块只采样一次,`n < 20` 的行只算方向提示。
|
|
2349
|
+
|
|
2302
2350
|
## 同一配置再跑一遍会差多少:块级差 4 %,任务级差 15–31 %(REP2,10 对)
|
|
2303
2351
|
|
|
2304
2352
|
外部评审提的第一条是稳定性。这一块不新增任何开关,只把 `migrate`+`debugfix` 的同一批格子**用同一套配置再跑一遍**(`REP2`,20 次运行,顺序 ABBA 与之前的块一致),看同配置的两次独立测量互相差多少:
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.5.27(把闸门最后两个没测过的任务族补上:方向相反,时点类旋钮收档)
|
|
4
|
+
|
|
5
|
+
- **补测:`bench/suite-run.py --tasks ledger,shellpipeline --arms def15,d2g --pairs 3 --tag D2G2`**(12 次运行、全部可用、丢弃 0、质量零倒退)。`d2g` 的闸门常量(第 1 步 ≥2 次调用才提前)此前只在 `codeimpl`/`debugfix`/`migrate` 三族验过,`ledger`/`shellpipeline` 一个数都没有。
|
|
6
|
+
- **结果方向相反,池化仍不支持提前**:`shellpipeline` 3 对几何 **0.597×**(0.47 / 0.69 / 0.66,步数 23→19、27→10、24→17),`ledger` 3 对几何 **1.898×**(2.68 / 0.95 / 2.70,输的两对输出 token 12.1k→34.0k、15.9k→29.1k)。并进前 21 对后:27 对 **0.816×**、CI95 **[0.650, 1.023]**、18/27 更快、中位 0.719×、符号 p = 0.122。
|
|
7
|
+
- **判定不变:HOLD,默认继续停在第 4 步。** 结论也更准了:提前提醒的价值取决于任务「一条命令跑完再读」还是「逐笔对账」,而不取决于第一步调了几次;时点类旋钮到此收档,不再为新时点补块。
|
|
8
|
+
- **`BENCHMARK.md` 同步**:`d2g` 的消融行 21 → 27 对、0.756 → 0.816、CI 改为 [0.650, 1.023];新增「补测(`D2G2`)」一节记账两条反向的逐对比值。
|
|
9
|
+
- **没有行为变更**:只跑块、改文档;默认值、提醒时机、提示词与 1.5.26 完全一致。
|
|
10
|
+
|
|
11
|
+
## 1.5.26(把「多开几个开关会不会更快」变成一张可复算的表)
|
|
12
|
+
|
|
13
|
+
- **新增 `bench/ablate.py`**:把 59 个块的全部臂按「同块、同任务、同 pair」对锚点臂池化,输出每个开关相对默认配置(`--anchor def15`)或相对 `off` 的几何比、95 % bootstrap CI、中位、步数/输出比、更快对数与符号检验。这是第一次用一张表回答「多个开关一起开的效果」。
|
|
14
|
+
- **结论:默认之上再叠任何开关都拿不到收益。** `openBatch` 0.882 [0.740, 1.049]、`batchVerify` 0.963、`stepBudget:8` 0.971、`preferPatch` 0.988、更宽并行 1.075、`workspaceMap` 0.802 [0.648, 0.999]、关掉明细律 1.101 —— 每个 CI 都跨 1。收益已经在默认配置里兑现,或者从来就不存在。
|
|
15
|
+
- **唯一站得住的杠杆仍是「同一句提醒的时点」**:`d2`(`disciplineAfterSteps: 2`)41 对 **0.695×** [0.565, 0.863],但分族方向相反(`ledger` 0.506 / `debugfix` 0.619 / `migrate` 0.569,而 `codeimpl` 1.073、`shellpipeline` 1.111);带闸门的 `d2g` 把 `codeimpl` 收到 0.889、同时削掉 `debugfix` 的收益 ⇒ 池化 0.756× [0.605, 0.939]。两臂按预注册判据仍是 HOLD,默认不放宽。
|
|
16
|
+
- **没有行为变更**:只加一个只读分析脚本与文档;默认值、提醒时机、提示词与 1.5.25 完全一致。
|
|
17
|
+
|
|
3
18
|
## 1.5.25(收回一个测不出来的结论;两个分析脚本补上推理字符)
|
|
4
19
|
|
|
5
20
|
- **撤回「纪律提醒 1.54×」这个数字**:`LEN3` 把 `LEN_DBG` 那一块(debugfix、7 对、`def15` vs `nodisc`,两臂只差 `discipline:'full' → 'off'`)同题同配再跑一遍,几何比从 **1.790** 变成 **0.648**——方向相反,符号检验两遍都不显著(p = 0.125 / 0.453),块级比值由一两个离群单元格决定(一遍在 `nodisc`,一遍在 `def15`,单格 165 s / 196 s)。所以纪律提醒的**独立份额目前不可判定**,对外只能报池化主效应 0.823×(138 对)。
|
package/bench/ablate.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Pool every block and report each arm's marginal cost against its own block's anchor.
|
|
3
|
+
|
|
4
|
+
`pool.py` answers one question ("how does arm X compare with off, on the clean
|
|
5
|
+
blocks"). This script answers the question a user actually asks when they look at
|
|
6
|
+
the switch list: *what does each switch do on its own, and what happens when
|
|
7
|
+
several are on at once?*
|
|
8
|
+
|
|
9
|
+
Every suite block is an independent experiment with its own anchor arm, and the
|
|
10
|
+
arm names are the switch sets. So for each block, pick an anchor (`off` when the
|
|
11
|
+
block has it, otherwise `def15`), then pair each other arm with that anchor on
|
|
12
|
+
`(tag, task, pair)`. Ratios from different blocks are pooled because they are all
|
|
13
|
+
"arm ÷ anchor of the same block, same task, same pair" — the block, the clock and
|
|
14
|
+
the task family cancel out inside each pair.
|
|
15
|
+
|
|
16
|
+
Two honest caveats, printed with the table:
|
|
17
|
+
|
|
18
|
+
* arms are not tested on the same task mix; the `tasks` column is the whole
|
|
19
|
+
reason a row can look good (an arm measured only on `ledger` is not a
|
|
20
|
+
statement about `migrate`);
|
|
21
|
+
* a block is one sampling. `REP2` and `LEN3` showed block-level ratios swing
|
|
22
|
+
0.65x-1.79x in *both* directions, so anything with n below ~20 pairs is a
|
|
23
|
+
direction hint, not a number. The sign test p-value is printed for that
|
|
24
|
+
reason and nothing here is significant without it.
|
|
25
|
+
|
|
26
|
+
python3 bench/ablate.py [--anchor off] [--min-pairs 1] [--json]
|
|
27
|
+
"""
|
|
28
|
+
import argparse
|
|
29
|
+
import glob
|
|
30
|
+
import json
|
|
31
|
+
import math
|
|
32
|
+
import pathlib
|
|
33
|
+
import statistics
|
|
34
|
+
from collections import defaultdict
|
|
35
|
+
|
|
36
|
+
HERE = pathlib.Path(__file__).resolve().parent
|
|
37
|
+
RESULTS = HERE / 'results'
|
|
38
|
+
|
|
39
|
+
# Blocks whose fixtures leaked; their `llm` column is an artefact (see pool.py).
|
|
40
|
+
RETRACTED = ('V15', 'TA3', 'TA4')
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def valid(row):
|
|
44
|
+
return (row.get('exit') == 0 and row.get('steps', 0) >= 1
|
|
45
|
+
and row.get('out', 0) > 0
|
|
46
|
+
and row.get('hasSessionIds', row.get('exact'))
|
|
47
|
+
and not row.get('leak'))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def load_all():
|
|
51
|
+
"""tag -> (task, pair) -> {arm: row}, last write wins like the report."""
|
|
52
|
+
blocks = defaultdict(lambda: defaultdict(dict))
|
|
53
|
+
for path in sorted(glob.glob(str(RESULTS / 'suite-*.jsonl'))):
|
|
54
|
+
tag = path.split('suite-')[1][:-len('.jsonl')]
|
|
55
|
+
if tag in RETRACTED:
|
|
56
|
+
continue
|
|
57
|
+
for line in open(path, encoding='utf-8'):
|
|
58
|
+
line = line.strip()
|
|
59
|
+
if not line:
|
|
60
|
+
continue
|
|
61
|
+
row = json.loads(line)
|
|
62
|
+
blocks[tag][(row['task'], row['pair'])][row['arm']] = row
|
|
63
|
+
return blocks
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def anchor_for(arms, wanted):
|
|
67
|
+
if wanted in arms:
|
|
68
|
+
return wanted
|
|
69
|
+
if 'off' in arms:
|
|
70
|
+
return 'off'
|
|
71
|
+
if 'def15' in arms:
|
|
72
|
+
return 'def15'
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def sign_p(k, n):
|
|
77
|
+
from math import comb
|
|
78
|
+
if n == 0:
|
|
79
|
+
return None
|
|
80
|
+
tail = sum(comb(n, i) for i in range(0, min(k, n - k) + 1)) / 2 ** n
|
|
81
|
+
return round(min(1.0, 2 * tail), 4)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def main():
|
|
85
|
+
ap = argparse.ArgumentParser()
|
|
86
|
+
ap.add_argument('--anchor', default='off', help="preferred anchor arm name")
|
|
87
|
+
ap.add_argument('--min-pairs', type=int, default=1)
|
|
88
|
+
ap.add_argument('--ci', type=int, default=0,
|
|
89
|
+
help='bootstrap resamples for a 95%% CI on the geometric mean')
|
|
90
|
+
ap.add_argument('--json', action='store_true')
|
|
91
|
+
args = ap.parse_args()
|
|
92
|
+
|
|
93
|
+
blocks = load_all()
|
|
94
|
+
per_arm = defaultdict(lambda: {'ratios': [], 'steps': [], 'outs': [],
|
|
95
|
+
'tasks': defaultdict(int), 'tags': defaultdict(int),
|
|
96
|
+
'anchors': defaultdict(int), 'walls': 0.0, 'anchor_walls': 0.0})
|
|
97
|
+
for tag, cells in blocks.items():
|
|
98
|
+
for (task, pair), arms in cells.items():
|
|
99
|
+
anchor = anchor_for(arms, args.anchor)
|
|
100
|
+
if not anchor:
|
|
101
|
+
continue
|
|
102
|
+
base = arms[anchor]
|
|
103
|
+
if not valid(base):
|
|
104
|
+
continue
|
|
105
|
+
for name, row in arms.items():
|
|
106
|
+
if name == anchor or not valid(row):
|
|
107
|
+
continue
|
|
108
|
+
a = per_arm[name]
|
|
109
|
+
a['ratios'].append(row['wall'] / base['wall'])
|
|
110
|
+
a['steps'].append(row['steps'] / base['steps'] if base['steps'] else 1.0)
|
|
111
|
+
a['outs'].append(row['out'] / base['out'] if base['out'] else 1.0)
|
|
112
|
+
a['tasks'][task] += 1
|
|
113
|
+
a['tags'][tag] += 1
|
|
114
|
+
a['anchors'][anchor] += 1
|
|
115
|
+
a['walls'] += row['wall']
|
|
116
|
+
a['anchor_walls'] += base['wall']
|
|
117
|
+
|
|
118
|
+
rows = []
|
|
119
|
+
for name, a in per_arm.items():
|
|
120
|
+
n = len(a['ratios'])
|
|
121
|
+
if n < args.min_pairs:
|
|
122
|
+
continue
|
|
123
|
+
geo = math.exp(sum(math.log(r) for r in a['ratios']) / n)
|
|
124
|
+
ratio = a['walls'] / a['anchor_walls']
|
|
125
|
+
wins = sum(1 for r in a['ratios'] if r < 1)
|
|
126
|
+
ci = None
|
|
127
|
+
if args.ci > 0 and n >= 3:
|
|
128
|
+
import random
|
|
129
|
+
rnd = random.Random(20261029)
|
|
130
|
+
draws = []
|
|
131
|
+
for _ in range(args.ci):
|
|
132
|
+
sample = [a['ratios'][rnd.randrange(n)] for _ in range(n)]
|
|
133
|
+
draws.append(math.exp(sum(math.log(r) for r in sample) / n))
|
|
134
|
+
draws.sort()
|
|
135
|
+
lo, hi = int(0.025 * len(draws)), int(0.975 * len(draws)) - 1
|
|
136
|
+
ci = [round(draws[lo], 4), round(draws[hi], 4)]
|
|
137
|
+
rows.append({
|
|
138
|
+
'arm': name,
|
|
139
|
+
'pairs': n,
|
|
140
|
+
'wall_geo': round(geo, 4),
|
|
141
|
+
'wall_total': round(ratio, 4),
|
|
142
|
+
'wall_median': round(statistics.median(a['ratios']), 4),
|
|
143
|
+
'steps_geo': round(math.exp(sum(math.log(s) for s in a['steps']) / n), 4),
|
|
144
|
+
'out_geo': round(math.exp(sum(math.log(o) for o in a['outs']) / n), 4),
|
|
145
|
+
'faster': wins,
|
|
146
|
+
'sign_p': sign_p(wins, n),
|
|
147
|
+
'geo_ci95': ci,
|
|
148
|
+
'tasks': dict(sorted(a['tasks'].items(), key=lambda kv: -kv[1])),
|
|
149
|
+
'blocks': len(a['tags']),
|
|
150
|
+
'anchors': dict(a['anchors']),
|
|
151
|
+
})
|
|
152
|
+
rows.sort(key=lambda r: r['wall_geo'])
|
|
153
|
+
|
|
154
|
+
if args.json:
|
|
155
|
+
print(json.dumps(rows, indent=2, ensure_ascii=False))
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
print(f"anchor={args.anchor} (falls back to off/def15 per block), blocks={len(blocks)}")
|
|
159
|
+
print(f"{'arm':10s} {'n':>4s} {'geo (ci95)':>22s} {'median':>7s} {'total':>7s} "
|
|
160
|
+
f"{'steps':>6s} {'out':>6s} {'faster':>9s} {'p':>6s} {'blk':>4s} tasks")
|
|
161
|
+
for r in rows:
|
|
162
|
+
tasks = ', '.join(f'{k}:{v}' for k, v in list(r['tasks'].items())[:3])
|
|
163
|
+
ci = f" [{r['geo_ci95'][0]:.3f},{r['geo_ci95'][1]:.3f}]" if r['geo_ci95'] else ''
|
|
164
|
+
print(f"{r['arm']:10s} {r['pairs']:4d} {r['wall_geo']:7.3f}{ci:<15s} {r['wall_median']:7.3f} "
|
|
165
|
+
f"{r['wall_total']:7.3f} {r['steps_geo']:6.3f} {r['out_geo']:6.3f} "
|
|
166
|
+
f"{r['faster']:4d}/{r['pairs']:<4d} {str(r['sign_p']):>6s} {r['blocks']:4d} {tasks}")
|
|
167
|
+
print('\nRead this as a direction table, not as per-switch numbers: rows are '
|
|
168
|
+
'measured on different task mixes and each block is one sampling.')
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
if __name__ == '__main__':
|
|
172
|
+
main()
|
package/docs/REFERENCE.md
CHANGED
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
- **扇出目标里的数字就是调度器算出的宽度。** `auto` 下提示段和看门狗共用同一个 `autoSchedule` 结果,所以模型读到的数字和被执行的数字不会漂移。
|
|
95
95
|
- **预取只在宽度 ≥ 4 时出现。** 宽度不够时多取一个调用只会挤占别的工作。
|
|
96
96
|
- **有界调用那一段只在 `stallGuard !== false` 时出现**,因为它描述的规则和看门狗是一套东西。
|
|
97
|
-
- **输出纪律有两档**:`light` 给旧档位 `fast` 用,`full` 给 `auto`/`turbo`/`max`/`ludicrous` 用。两档要求模型不预告调用、不复述结果、不写进度报告;最后一步的答案仍然要完整写出。`full` 只多一句"不需要文字时只发调用"。**它不会让答案变短,更不会让模型跳过检查。** 口径要说清:可见正文只占「正文+工具参数」字符的 1.19 %(def15 全量 385 会话;不含 reasoning 与工具返回;`python3 bench/textshare.py --limit 0` 可复算),所以它的价值不在"删掉的字"本身,而在它连带把每步的推理压短(池化 168 对里 `reasoning` 字符 0.75×、`emitted` 0.82×)。把这一项单独关掉(`bench/arms/nodisc.yml`)的份额目前**测不出来**:同一块(debugfix 7 对)跑两遍,`nodisc/def15` 一次 1.79×、一次 0.648×,方向相反、符号检验都不显著,块级几何比由一两个离群单元格决定(见 `BENCHMARK.md` 的 LEN3 一节)。能报的只有池化主效应 0.823×,其中明细律与其它提醒在一个机制包里一起生效,无法在单块里分离;同样不能由此宣称"工作内容不受影响"
|
|
97
|
+
- **输出纪律有两档**:`light` 给旧档位 `fast` 用,`full` 给 `auto`/`turbo`/`max`/`ludicrous` 用。两档要求模型不预告调用、不复述结果、不写进度报告;最后一步的答案仍然要完整写出。`full` 只多一句"不需要文字时只发调用"。**它不会让答案变短,更不会让模型跳过检查。** 口径要说清:可见正文只占「正文+工具参数」字符的 1.19 %(def15 全量 385 会话;不含 reasoning 与工具返回;`python3 bench/textshare.py --limit 0` 可复算),所以它的价值不在"删掉的字"本身,而在它连带把每步的推理压短(池化 168 对里 `reasoning` 字符 0.75×、`emitted` 0.82×)。把这一项单独关掉(`bench/arms/nodisc.yml`)的份额目前**测不出来**:同一块(debugfix 7 对)跑两遍,`nodisc/def15` 一次 1.79×、一次 0.648×,方向相反、符号检验都不显著,块级几何比由一两个离群单元格决定(见 `BENCHMARK.md` 的 LEN3 一节)。能报的只有池化主效应 0.823×,其中明细律与其它提醒在一个机制包里一起生效,无法在单块里分离;同样不能由此宣称"工作内容不受影响"。要判断「在默认之上再打开某个开关还有没有用」,用 `python3 bench/ablate.py --ci 2000 --anchor def15`:它把全部块按同块、同任务、同 pair 池化成每个开关相对默认的几何比与 95 % CI(当前读数:所有可选开关的 CI 都跨 1,叠上去拿不到收益)。
|
|
98
98
|
- **`parallel: 1` 是"开着但不要求扇出"的正式写法**:开关仍然生效于看门狗,提示段整体消失。
|
|
99
99
|
|
|
100
100
|
成本是明码标价的:`auto` 下这一段约 2.7 千字符,每个请求都要付这部分输入 token。这是有意的交换——用输入 token 换更少的往返。
|
package/index.js
CHANGED
|
@@ -97,7 +97,7 @@ const TAG = '[fast-mode]'
|
|
|
97
97
|
* Shipped identity of this build. Traced into the debug log so a stale install is
|
|
98
98
|
* visible at a glance, and pinned by a test against `package.json`.
|
|
99
99
|
*/
|
|
100
|
-
export const VERSION = '1.5.
|
|
100
|
+
export const VERSION = '1.5.27'
|
|
101
101
|
const GLOBAL_AGENT = '__global__'
|
|
102
102
|
|
|
103
103
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-fast-mode",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.27",
|
|
4
4
|
"description": "DeepSeek Harness fast mode: same thinking effort, fewer round trips. An adaptive parallel tool fan-out, output discipline that never trims the answer, and a cancellable stall guard. Never changes reasoning effort, the model, or the request body. Provider-agnostic, one dependency (@deepseek-ai/schemastery).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"bench/textshare.py",
|
|
44
44
|
"bench/reminders.py",
|
|
45
45
|
"bench/patchshare.py",
|
|
46
|
+
"bench/ablate.py",
|
|
46
47
|
"docs/",
|
|
47
48
|
"LICENSE"
|
|
48
49
|
],
|