
MrWeiCodes/dsh-loop-guard
dsh-loop-guard
dsh-loop-guard is a community DeepSeek Harness plugin. Read the repository README before installing.
Install
npx @deepseek-ai/dsh plugin --profile web add @mrweicodes/dsh-loop-guardRestart `dsh web` after install. Bundle APIs can change during the developer preview.
README badge
[](https://dshhub.dev/plugins/dsh-loop-guard)Paste this into your README. The star count updates with every catalog sync.
From the README
Excerpt from MrWeiCodes/dsh-loop-guard, cleaned of badges and images.
dsh-loop-guard — DSH 思考循环守护
为 DeepSeek Harness(DSH)提供的思考循环守护插件:模型陷入「只想不做」的退化循环时自动打断并注入纠正提示,任务继续往下走,不必再手动中止
🌏 中文 | English
dsh · dsh-plugin · plugin · guard · thinking-loop · reasoning · repetition · AI agent · 思考循环 · 死循环 · 推理退化
简介
长上下文 + 高 reasoning effort 下,模型会退化:推理里开始出现低熵重复(好。执行。好。、Write. / Output. / Let me write. / Go. 这种短句轮转),然后停不下来。
麻烦的是 DSH 自带的 guard/ 家族抓不到这种情况——它们都围绕工具调用:
| 内置 guard | 挂载点 | 能抓什么 |
|---|---|---|
guard/timeout-policy | tools/execute | 工具调用超时 |
guard/repeat-tool-reminder | tools/post-execute | 重复的同一个工具调用链 |
而退化循环的特征恰恰是完全不调工具:只有 reasoning-delta,零 text-delta、零 tool-call-delta。于是:
- 两个 guard 都不触发;
- agent-loop 的
turn()从已完成的消息推导StepEndReason,流不结束 → step 不 settle →turnEnds永远为 null →while (true)永不 break; - 回合停不下来,只能由你手动中止——而界面上只显示「思考中」,看起来和认真推理没区别。不点开 thinking 块根本察觉不到它在空转。
本插件接管 llm/stream 瀑布流,按每次模型调用的 chunk 组成做判定,在退化发生时从流内部切断,让回合正常结束。
上图是实际运行效果:推理块里反复出现 OK. / Writing. / Let me write. / Go. / Executing. / Now. 的轮转,插件在重复累积到阈值时截断该次调用,并在下方注入一条提示,让模型回到原本的任务。
0.1.7 起聊天区不再显示那条提示
DSH 0.1.7 把「上下文」类消息从聊天区可见行里排除了(isVisibleChatNode,硬编码 kind !== "context"),所以注入的纠正提示在聊天区完全没有——不是被折叠,是压根不渲染。
0.1.6 及更早没有这个过滤,那时它正常显示为「上下文注入」行。
提示没有丢,两处能看到:
| 位置 | 看到什么 |
|---|---|
| 会话历史 / 轨迹视图 | 该消息原样列出,带「上下文」标签和完整正文 |
| 宿主日志 | dsh-loop-guard: breaking a repetitive stream (N repeated chars, ...) |
轨迹视图里的样子(上下文 那一行):
功能特性
- 五层检测,各管一种形态:纯推理无输出、复述上一步材料、可见输出内部的周期循环、可见输出内部的短语池重排、以及推理内部的短语池重排。后三条互补,见下。
- 能终止「永不结束的回合」:这是本插件存在的核心理由。退化循环里流永远不结束,任何「调用结束后再判定」的检测都够不到;只有从流内部切一刀才行。
- 切断后任务继续,不必手动重启:切断只是结束当前这次调用,回合以正常完成收尾,会话照常可用——你原本的任务可以直接往下走。这是它和「卡死到只能手动中止」的根本区别。
- 在 1% 处就切断:实测一个 330,188 字符的循环在 3,264 字符(1.0%)时被切断;一个 124,070 字符的在 17,888 字符(14.4%)时被切断。原来这两个都要跑满全程、最后靠人手动中止。
- 误报极低:在真实会话 119 个「有产出」的调用上,零误报;扫描本机全部 735 个会话、40 个触发点,误判 12 个(全是「贴代码改前/改后」),已由集中度护栏挡住——见下。
- 精确判据:判定用的是逐字周期和跨调用复述,不是时长、也不是比率。
- 纠正信息指向原任务:切断时注入的提示只说「不要重复,继续完成任务」,不会让模型去"给个结论然后收尾"——后者会让它偏离原本在做的事。
- 反应不闩锁:一次 steer 常常打不破强循环,所以阈值到了会重新计数、再次开火(上限
maxFires)。 - 跟随界面语言:注入的提示读宿主
locale设置,中文环境说中文(默认即中文)。 - 绝不静默重试:没有模型回退、没有自动重发同一请求——把退化模型再喂一遍比循环本身更糟。
- 离线分析器:
tools/analyze-session.mjs用插件运行时同一个检测器复跑 session jsonl,回答「这次到底该不该响」。 - 可观测:切断时写 warn 日志,并注明是哪条规则命中的。
使用
开箱即用
装好就能用,不需要任何配置。 默认值已按真实数据标定:
- 纯推理空转、复述上一步、推理内部周期循环 → 自动打断回合;
- 单次调用刷屏式重复可见输出 → 自动从流内部切断;
- 正常的长推理、正常的重复性输出(表格、日志、CSS、JSON)→ 不误伤。
想调? 见下面的配置一节,里面有可直接复制的 YAML。
官方「插件」页为什么不提供配置表单
- 绝大多数用户用不到。 默认值就是为「不用调」设计的——装好即用,该拦的拦、该放过的放过。
- 改了多半会更差。 20 个字段里 13 个是检测阈值,默认值按真实数据标定。凭直觉调(把
maxThinkingSteps调小、把minReasoningChars调低)方向通常是变灵敏, 代价是误伤正常的长推理——从「几乎不误报」变成「频繁误报」。- 容易漏。 阈值是配套的,只改一个常常不生效甚至起反作用:想关掉某条规则要把它的
max*置0,只调min*没用。表单不会提示这些耦合关系,README 会。真正值得动、且属于行为选择(而非阈值标定)的只有 4 个:
escalate、resumeAfterBreak、breakCorrection、maxThinkingSteps。改 profile 的cordis.patch.yml,重启dsh web生效。
熔断后会发生什么
会话继续,任务可以往下走——不需要你手动重启或重新发指令。
…
