Bundle
dsh-cot-anchor
思考锚点:从模型上一段思考中提取已确立结论,在工具结果后注入,减少重复推导;并可识别打转与伪工具调用
- Source
- JiewiW
- License
- MIT
- Updated
- Updated 7 days ago
Readme
# dsh-cot-anchor
DeepSeek Harness(DSH)插件:治一类特定的模型毛病——**思考着思考,但没在推进**。表现为反复重新推导已经得出的结论、把工具调用写成纯文本、原地重复同一段话、输出无意义的递增数字流。
插件做两件事:
1. **结论回流**:每次工具结果返回后,从最新思考中摘出已成立的结论(最多 3 条、每条 ≤ 220 字)插回上下文,下一步起手就能看到,不必重推一遍。**装上默认生效。**
2. **生成中途打断(软切)**:生成过程中每 32 个字符检查一次,发现打转 / 原地重复 / 伪工具调用 / 数字流就立即切断本次请求,把已生成部分作为正常消息落盘、排好结论锚点,让回合从断点续跑——不会因为一次误判丢掉整轮工作。
它不解决一切长任务问题,只解决「单流内思考链极度冗余、结论反复重新发现」。跨步骤的折返跑(同一结论在十几步里重推)不在能力范围内,那是姊妹插件 [dsh-step-governor](https://github.com/JiewiW/dsh-step-governor) 的职责。
## 快速开始
```sh
dsh plugin --profile <你的profile> add github:JiewiW/dsh-cot-anchor#v0.2.1
```
重启实例后设置页出现「COT 锚点」标签即生效。结论注入无需任何配置;软切需要内核支持(见[兼容性](#兼容性与软切内核))。
## 工作方式
```
模型思考 → 工具执行 → [插件] 摘出已成立的结论插回上下文 → 下一步思考
↑
只在工具边界注入
```
注入消息以 `user` 角色追加在工具结果之后、下一次请求之前,尾部追加写入会话日志,不改写已有内容,因此不会打穿前缀缓存。
## 成本
| 场景 | 额外成本 |
| --- | --- |
| 默认(结论注入开启,其余关闭) | 每个工具结果后一条短消息,上界 660 字符(3 条 × 220 字);无额外模型调用 |
| 命令执行纪律提醒 | 每轮一次、随运行时上下文快照("Current runtime context…")注入,位于记忆规则之后;单条全文固定约 380 token(字符估算),作为稳定前缀段参与上下文,不再随工具调用堆叠 |
| 开启 LLM 提炼结论(默认关) | 每个助手回合**多一次**小模型调用 |
| 开启打转 / 重复等判定 | 纯本地字符串计算,零 token 成本;可能增加少量回合数 |
| 开启 CoT 静默采集 | 每个助手回合留一条本地样本;默认关闭 |
注入消息会随之后续请求的上下文一同发送,因此持续占用少量上下文窗口。按中英混排估算,660 字符约合 200–500 token 量级——相对于一次工具往返的上下文可以忽略,但它在**每一步**都会累积。注入以尾部追加方式写入会话日志,不改写已有内容,因此不会打穿前缀缓存:除新追加的一块外,此前内容始终是稳定前缀。新追加块在其首次出现的那次请求上按未命中计费一次,此后转为缓存命中——这一点与文本是否固定无关。推理锚点每次不同,其排列顺序仅为内容组织上的一致性,不影响缓存行为(自 411cb74/v0.2.2 起命令执行纪律已改走运行时上下文快照的固定段,不再参与本次工具注入)。
在一个约 924 万 token 的真实长会话上实测:插件注入总量约占全会话 0.23%(每个注入块只在首现那一次请求按未命中计费,此后转为缓存命中)。具体分项口径见下文「实测成本占比」。
## 能力边界(请先读)
- 两类机制都是**单步边界内**的:软切只看当前一次生成流,进入下一步计数归零。治得了单流内退化,治不了跨步骤折返跑。
- 软切不减少回合步数。长任务账单的大头是「步数 × 每步膨胀的上下文重读」,步数治理请用 step-governor。
- 模型可能**知道自己在空转却停不下来**——实测出现过思考中自述「I'm burning turns, let me stop」之后继续生成下一条探索路线。注入的前提是模型会读且照做,自知不构成刹车。
- 软切每回合按判定类别分桶计预算 **6/20/3**(启发式判定 6 次、字节级确证重复 20 次、伪工具调用 3 次),总闸 **29**(6+20+3)。打满后启发式判定升级为终止本回合,高置信重复仍照常拦截;预算事件(`agent/soft-cut-suppressed` / `phase.abortTurn`)在会话日志可观测。这些常量由内核定义、不由插件持有。
> 以下统计数据自 **v0.2.1 之前的机制**采集:当时命令执行纪律是随每次工具执行后剥出的独立 `user` 消息(`source.summary = cot-anchor: exec-discipline`)与推理锚点同车注入。**自 v0.2.1 起(并入 411cb74 迁移后)**,纪律不再随工具注入,而是注册为运行时上下文快照的一个固定段(每轮出现一次、位于记忆规则之后、用户唠叨之前),不再按工具条数线性堆叠;下述注入量只是旧机制的上限参照。
在一个 95 次助手请求、累计约 924 万 token 的真实长会话上按消息级口径统计(字符→token 为启发式估算,非 tokenizer 实测;任何人可在自己的 DSH 会话日志上按同口径复算:逐条统计 `user/message` 中 `source.summary` 为 `cot-anchor: exec-discipline`(固定纪律)与其他 `cot-anchor:*`(动态锚点)的文本,并对照各次助手请求 `usage` 的 `inputTokens` / `cacheReadTokens`):
> 结论:插件带来的新增输入在全会话 token 总量的 0.3% 以内。每个注入块在首现时按未命中计费一次,此后随上下文增长参与后续每一次请求。纪律块体积约占注入量五分之四,但"文本固定"不带来额外缓存收益——该占比只反映体积,不反映命中。(该占比为 v0.2.1 之前旧机制的历史数据;新版纪律块已移入运行时上下文快照固定段,不再按工具条数累计。)
## 兼容性与软切内核
| 能力 | 支持的 DSH 版本 |
| --- | --- |
| --- | --- |
| 结论注入、设置页 | 0.1.5 起全部版本 |
| 生成中途打断(软切) | 仅 0.1.5-rc.1 / rc.2 开箱可用 |
0.1.5-rc.3 起内核移除了软切所需的 `agent/soft-cut` 钩子,该能力会静默失效;插件在启动日志和设置页顶部明确提示当前内核是否支持——**以设置页显示为准**,不要凭开关是开的就认为在生效。
新版内核可用随包工具把软切机构移植回去(带版本与哈希自检,幂等、可回滚,不符自动还原):
```sh
node node_modules/dsh-cot-anchor/tools/apply-softcut-port.mjs --check # 查看状态
node node_modules/dsh-cot-anchor/tools/apply-softcut-port.mjs # 应用
```
移植后重启实例。完整步骤与风险见 [docs/softcut-kernel-port.md](docs/softcut-kernel-port.md)。
## 设置
设置页「COT 锚点」共 61 项、分组展示,多数场景用默认值即可。下面只列常用项与容易误判的项;其余阈值在设置页内均有内联说明。
### 总开关
| 键 | 默认 | 说明 |
| --- | --- | --- |
| `enableToolInject` | 开 | 工具结果后注入结论锚点,本插件的主要价值,建议保持开启 |
| `enableSoftCut` | 开 | 允许生成中途打断;内核不支持时自动无效 |
| `enableExecDisciplineBlock` | 开 | 随锚点同车注入命令执行纪律提醒;与锚点注入共用去重节奏,关闭后锚点注入行为不变 |
### 五项软切判定
全部关闭时插件只做结论注入。
| 键 | 识别什么 | 注意 |
| --- | --- | --- |
| `enablePseudoTool` | 把工具调用写成普通文本(如 `<seed:tool_call>...`) | 只能识别已知文本形态 |
| `enableRepeat` | 逐字节相同的内容反复吐出 | 换措辞的重复抓不到 |
| `enableChurn` | 措辞不同但反复「重新分析」 | 启发式判定,遇到未闭合代码块自动让路 |
| `enableTransition` | 「接下来我要……」类转折句 | **最容易误判**:正常分阶段思考也有转折句;若频繁在正常思考中切断,先关它 |
| `enableNumberRunaway` | 无意义递增数字流 | 要求数字流足够长(≥ 500 字符跨度等阈值) |
打断太频繁时:先关 `enableTransition`,其次调高判定阈值(`churnMinHits` 默认 18 等)。
### 锚点内容
| 键 | 默认 | 说明 |
| --- | --- | --- |
| `minReasoningChars` | 250 | 思考短于此长度不提取结论 |
| `maxPoints` | 3 | 最多保留几条结论 |
| `maxPointChars` | 220 | 单条结论字数上限 |
结论由规则从思考文本中摘句得到,不理解句子的语义角色,因此入池前会剔除两类无命题内容:纯话语标记句(剥掉 Actually / wait / Hmm / 其实 / 等等 等标记后实词不足 6 字符,如「Actually, wait.」「其实,等等。」)与路线意图宣告句(「the decisive route: ask the user…」)。标记词**领起但带事实命题**的句子(「Wait, the kernel never marks in verbose mode.」)照常保留。
注意:Wait / Actually / Hmm 等转折词在推理链中承担结构控制作用,插件**不从模型输出里删除它们**,只阻止它们被当成结论回灌。
### LLM 提炼与 CoT 采集(默认全关)
- `enableLlmRefine`:用一次小模型调用把整段思考压成摘要式结论,通常比规则摘句更准;provider/model 留空则跟随当前会话。
- `enableHarvest` / `enableAutoAnalyze` / `enableLearnedPatterns`:静默采集思考样本、自动归纳检测器看不见的打转形态、把学习成果用于判定。开启会在本地留存思考文本,启用前请自行评估隐私;学习模式默认有 20 轮影子期(`learnedShadowRounds`)防止一次误学永久改变判定。
## 隐私
- 结论注入与全部软切判定都在本地完成,不向任何外部服务发送数据。
- LLM 提炼开启时,思考文本会发给你指定的 provider(留空则跟随当前会话)。
- CoT 采集开启时,思考文本与工具轨迹只留存本地。
## 常见问题
**设置页显示「当前内核没有掐断能力」**
内核不提供软切钩子,结论注入不受影响。需要软切可停留在 0.1.5-rc.1/rc.2,或按上文移植。
**模型好像没收到提醒**
确认 `enableToolInject` 已开、且思考长度超过 `minReasoningChars`——思考过短本来就不提取。
## 开发
仓库根目录所有 `test-*.mjs` 都是独立可执行脚本(无测试框架、无 `npm test`),逐个 `node test-*.mjs` 运行,退出码 0 即通过。
## 许可
MIT
Install
dsh plugin --profile web add github:JiewiW/dsh-cot-anchor
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-cot-anchor from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.