← Back to home@qlheric

dsh-cvm

Keep DSH agents from stalling, fake-finishing, or overspending: 4 cognitive guards (task contract / loop detection / evidence-before-done / single injection point) + 1 cost guard (budget nudge). No core changes - official seams only.

Stars
1
Language
JavaScript
Created
Oct 2, 2026
Updated
Oct 3, 2026
GitHub repo

Introduction

dsh-cvm —— 给 DSH agent 加一层"防卡住 / 防假完成 / 防超支"的监督

四个认知监督插件(管模型跑偏)+ 一个成本监督插件(管花钱失控),共五个。 全是正交的 Cordis 插件,不改 DSH 内核,只用官方接缝。 不提升模型能力——模型已经够强了;它管的是偶尔会出现的几种"跑偏"。

一、它解决什么问题(先看症状,对号入座)

A 组|认知监督(四个,管"模型跑偏")

强模型在长任务里偶尔会停在一个低于自己水平的状态。下面三种症状,中了任何一条,就有对应的插件:

你会看到的症状它为什么坏对应插件插件做什么
用户第 1 轮说了硬约束,干到第 6 轮忘了——把"不许动"的文件也改了全局目标被最近的局部信号挤掉dsh-contract把首条消息落成任务契约(含约束原话)钉进 system prompt
反复读同一堆文件、就是不推进——一轮烧掉几十步,最后啥也没改轨迹塌进"打转",没有信息增益dsh-convergence数连续只读;到阈值就提示"你在打转,换个方法"

说人话:"打转"有两种——反复看同一个地方(深度),和一直在读、读的东西换了一堆但就是不推进(广度)。 后者更常见也更贵:模型看着很忙,其实一步没往前走。 | 说"已完成",但其实一次都没跑过——改了文件就宣布成功 | 模型被自己的结论锚住 | dsh-evidence | 检测"声称完成 + 改了文件 + 没有一次成功验证" |

上面三个只负责"检测",真正"开口说话"的是第四个:

插件职责
dsh-intervention唯一的注入点:读前三个的状态 → 注入提示,或在轮次收尾时 agent.steer 强制再走一步

为什么 A 组拆成四个:检测(写状态)和行动(读状态)分开 → 每个都能单独开关、单独调参,互不耦合。contract / convergence / evidence 互不 import。

B 组|成本监督(一个,管"花钱失控")

你会看到的症状对应插件插件做什么
token 不知不觉烧掉一大截——没有人在看总消耗dsh-budget到阈值软提醒一次(不中断;不做硬熔断)

B 组与 A 组完全正交:它不管认知,只管消耗。可以只装 A 组不装 B 组(enabled: false 或干脆不挂)。 它读的是官方 tokenUsage 投影,自己的状态放 cvmBudget。

一句话说清它是什么

是:给强模型加的过程保险。风险不是"模型做错",而是"模型偶尔停住或自我说服"。 不是:不是提示词技巧合集,也不是"让模型更聪明"——模型越强,"补能力"的空间越小。

适用:长任务、要它真跑起来、无人看管时防打转、要控成本。 不适用:一句话问答;或你不想让任何规则打断模型。

装上以后你会看到什么

它不刷屏、不弹窗,也不改模型说的话。只在这三种时刻,往上下文里注入一条提示(文案都能在 Config 里改):

打转时

⚠️ 运行时检测:你已经连续多次只读操作却没有推进,可能陷入了原地打转。请换一种方法——例如直接执行/运行看真实输出、换一个假设、或从另一个入口文件切入。注意:目标是让任务真正完成,而不是继续收集信息。

声称完成、但其实没验证过

⚠️ 运行时检测:你已声称完成,但修改了文件后从未成功验证过。请先运行脚本/测试确认改动真的生效,再交付;否则应视为未完成。

快超预算时

[预算提醒] 本次会话已用约 85%(token 850,000/1,000,000)。请收窄范围、少做无效探索;接近完成就直接收尾给出结论。

其余时间完全静默——没有信号时注入的是空串(这也是"守前缀缓存"的要求:提示只在有信号时出现)。

二、装(一条命令)

node install.mjs                                   # dry-run:只打印将要执行的命令
node install.mjs --apply --profile <你的profile>   # 真装(5 个包一条命令 + 自动自检)
node install.mjs --check --profile <你的profile>   # 只自检(没装齐时退出码非 0)

脚本会:探测 DSH_HOME 与现有 profile → 打印命令 → --apply 时执行 → 用 --dump-config 自检 5 个层是否真的加载。 dsh 不在 PATH 时用 --dsh "node /path/to/dsh/lib/bin.js"。默认只做 dry-run(有些 profile 是生产环境)。

⚠️ 不要用 add github:qlheric/dsh-cvm(不带 #path:)——本仓库根是 private 的 workspace 包, 那样装到的只是根包,dsh 会警告 declares no dsh.bundle,一个插件都不会生效(我们实测踩过)。

手工挂载则是往 dsh.profile.bundles 里加这五项:

{ "dsh": { "profile": { "bundles": [
  "@deepseek-ai/dsh-base",
  "@qlheric/dsh-contract", "@qlheric/dsh-convergence", "@qlheric/dsh-evidence",
  "@qlheric/dsh-intervention", "@qlheric/dsh-budget"
] } } }

三、配置(都能单独关)

所有阈值/关键词/提示文本都在各插件 Config(schemastery),可在 cordis.patch.yml 覆盖(patch 层跨升级存活):

- id: convergence
  config:
    threshold: 8            # 连续只读 8 次才算打转
    readTools: [read, glob, grep]
- id: intervention
  config:
    steerAtTurnStop: false  # 关掉"收尾强制再走一步"
- id: evidence
  config:
    enabled: false          # 整个终局门禁关掉
- id: budget
  config:
    maxTokens: 1000000      # token 上限(默认 100 万)
    maxSteps: 200           # 步数上限
    softRatio: 0.8          # 到 80% 先软提醒

四、实测(诚实版:有正结果,也有撤回的假阳性)

一句话结论:结果指标(任务成败)几乎测不出差异——强模型本来就很少掉;过程指标能测出,而且取决于"场景有没有给它发挥空间"。

下文里的 C1 / C5 / C8 是我们自己造的几个评测场景编号(C 系),完整台账在 C1-AB数据汇总.md。 读的时候只要记住一句话:场景越"容易打转",插件越有用。

4.1 有效的地方:打转(C5 跨文件排查)

场景:app.py → lib.py → data.csv,bug 藏在 lib.py,必须跨文件追——天然容易广度打转。各 20 次:

统计量(maxReadStreak=连续只读最长串)基线装插件后变化
mean19.959.75−51%
median189.5−47%
sd9.152.75−70%
max4216−62%
步数 / 只读44.3 / 38.326.5 / 20.9−40% / −45%
结果20/2020/20不变

两组结果都满分,但被打转耗掉的步数差一倍。 这是目前最硬的证据。

4.2 反例:C1(明确可修的任务)基线满通过、过程只削长尾

统计量基线装插件后
结果(各 20 次)20/2020/20
maxReadStreak mean6.35.55
maxReadStreak median55(不变)
maxReadStreak sd2.871.60(−44%)
maxReadStreak max1511

中位数完全一样——只看均值/中位数会得出"没效果"的错误结论;要看 sd 与极值。

4.3 干预参数:有一个最优窗口,不是越敏感越好

改 convergence.threshold(各 20 次,maxReadStreak 越小越好):

阈值C1(基线 6.30)C5(基线 19.95)
T=3(早干预)8.4511.4
T=5(默认)5.559.75
T=8(晚干预)12.6514.6

只有 T=5 优于"不装插件";T=3 和 T=8 都比不装还差(早干预打断正常探索,晚干预时模型已陷深打转)。

4.4 一个被撤回的假阳性(留着当标本)

我们曾用 20 次样本得出"新 contract 把 C8 场景退化率从 35% 打到 15%"——补跑到 40 次后塌了(基线 25% vs 新 contract 28%)。该结论已作废。 教训:差异 10pp 时 p≈0.34,要达 p<0.05 需约 250 次/组——当置信区间宽度大于效应本身时,不要下结论。

4.5 边界(别把上面的数字当承诺)

  • 样本 20 次/组(部分对照 8–12 次),方向性证据;同一配置 8 次与 20 次能差 50%。
  • 有一个场景(用户施压要求改口)在 deepseek 上基线就不退化,测不出改善空间 —— 不是插件没用,是基线没这个毛病。
  • 实验室级证据(隔离 DSH_HOME + headless),未到生产级。

五、已知代价(这类插件的风险是"误伤",不是"没效果")

  • dsh-evidence 早期把 tool/result.error 当"工具失败",在调试场景里把正常的"看报错再改"误判成失败,退化率反而涨到 37.5%(比不装还差)。修正为"验证工具成功执行才算验证过"后消除。
  • dsh-convergence 的 threshold 过低(T=3)会因过早干预恶化过程(见 4.3)。
  • dsh-budget 的团队聚合是"下界":只把当前活跃子 agent 计入(已结束的无法归属,child 上没有 parent 字段);实测子 agent 往往在父会话收尾前就结束了,所以父会话常看到 childTokens = 0。修过的一个真 bug:turn-stopping 在子 agent 自己的会话里也会触发,不排除自己就会重复计算(实测团队量翻倍)。

⇒ 所以每个插件都可配置、可单独关闭;调参要按场景标定,不能照搬默认值。

六、评测方法学(我们踩过的坑,写给要复现的人)

  1. 场景文件必须每轮复位,且复位源不能是 git HEAD——评测会改场景文件,而 git add -A 会把模型产物一起提交,git checkout 就再也复位不到"原始 bug 版"了(我们踩过两次)。现在用独立模板目录 eval/scenarios/。
  2. A/B 数据要并存:batch-eval.mjs --label A|B,否则互相覆盖。
  3. 别只看均值:强模型的过程指标均值可能不动,差异藏在 sd / 极值 / p90。
  4. 单测 mock 必须对齐真实事件结构:user/message 的 payload 就是 UserMessage,assistant/message 才是嵌套 {turn,step,message}。我们曾因 mock 假设错误,让 41 项单测全绿而线上功能恒为 null。

七、目录

packages/dsh-{contract,convergence,evidence,intervention,budget}/  # 五个插件
install.mjs                                                        # 一键安装器(dry-run / apply / check)
eval/                                                              # 评测集 + 驱动 + 模板(scenarios/)
src/domain/                                                        # 单测(70 项)
*.md                                                               # 知识底座、调研、数据汇总

License

MIT