dsh-repeat-guard
解决大模型用你的token唱歌的糟糕问题
我们发现部分模型(尤其是deepseek v4.1 flash)很容易在长上下文时进入复读状态。
dsh社区中称呼这种情况为“唱歌”,典型的表现如下所示:
Let me do it.
Let me run.
Let me go.
Let me do it.
...
如果在预设或者AGENTS.md中约束使用中文思考,则会变成如下的场景:
好。
做。
开始。
做。
嗯。
做。
我必须开始工作了。
好。
做。
...
配合deepseek v4.1 flash高达 300tok/s 的恐怖输出速率,模型可能会以极为可观的速度消耗token,而不产生任何有效输出。
这通常是比较隐蔽的,尤其是在用户没有注意模型的思考过程的时候。用户实际上只会看到思考过程快速闪过很短的句子,回答好像很正常。
在上下文长度达到 300k 以上的时候,该现象会变得十分频繁。
不仅如此,我们也观察到deepseek v4.1 flash有着在已经思考到需要工具调用的时候输出一个短句,接下来又进入另一个方向的复杂思考过程的倾向。如下所示:
我已经收集到了足够的信息,接下来开始操作。先修改xxx文件。
做。
但是我还发现仓库里有其它的内容。注意到用户提到xxxxx
...
显然这不是我们想要的行为。既然模型已经清楚下一步的工作是什么,就应该直接开始工具调用。
我们还注意到上述问题只出现于思考过程而不出现于回答内容。
此插件的功能
此插件致力于解决上述模型复读和无端长思考的问题。它会持续检测模型的输出,如果思考过程出现了一个白名单中的短句且单独成段,且模型在输出这个短句后既然有继续思考的意图,我们就会强行中断对话,并发送一句提醒,让模型直接开始下一轮的输出。
例如
[深度思考]
直接检查服务器状态和崩溃日志。
关键:先看最新日志和 crash-reports。
执行。 <--打断
[复读拦截]
你上一段思考退化成了碎片复读(反复输出"好。"一类的空话),已被系统截断。
请直接继续执行下一步,不要再输出任何确认语、寒暄或空话。
[深度思考]
直接调用工具,检查服务器状态和崩溃日志。
[tool calls]
ssh -o ConnectTimeout=10 -o BatchMode=yes ...
...
工作原理
逐 chunk 观察 reasoning-delta,检查思考文本。
独立段命中白名单时,向模型传递中断请求,掐断模型输出的片段,并补充结束标志,伪装成正常结束的思考过程。
向模型发送一条注入提示词,以恢复agent-loop。
用户会通过注入提示词这个步骤看到大模型被中断的过程,因此步骤可能会变得很多。这是不得不付出的代价。
虽然我们可以将下一步思考的过程接到上一轮打断的位置以伪装成什么都没发生过的样子,但是一方面这种做法有风险,另一方面不是很有利于缓存命中。更何况,这也能帮助用户判断插件是否在正常工作。
可配置选项
在 设置 → 复读打断 里查看,保存后生效,无需重启。
| 项 | 含义 |
|---|---|
| 累计拦截 | 掐断次数(有清零按钮) |
| 拦截短句 | 触发打断的白名单,需要加上标点 |
| 连续命中次数* | 连续命中的阈值,如果为2就需要连续出现两个短句才触发 |
| 行内重复检测* | 打开后"好。好。好。"这种挤在一行里的重复也算命中。 |
| 续跑指令 | 截断后推给模型的提示词 |
| 折叠行摘要 | 注入段用户可见的简要信息 |
* 连续的意思是中间没有长段。如果配置成2就只会拦截循环,默认配置连一个短句后的分支思考过程也会拦下。
*deepseek不存在行内重复问题,这个选项是为 qwen 35B 这样的模型准备的。
安装到 dsh
dsh plugin --profile web add dsh-repeat-guard
许可
MIT,见 LICENSE。
No comments yet. Be the first to write one.