前言¶
在使用 DSH(DeepSeek-Harness)进行智能体开发时,一种隐蔽的失败模式值得注意:模型返回的内容只剩下协议标记(如 </||DSML|| calls>、<thinking> </thinking> 等),既没有正文也没有工具调用,而 Harness 把它当作一次正常的回合结束。这会导致对话静默中断,很难排查。
dsh-empty-turn-guard 插件针对这种场景,把只有协议标记的回合改判为可重试的 EMPTY_RESPONSE 错误,让 Harness 重新调用模型,而不是默默结束。
是什么¶
这是一个 DSH bundle(自带 cordis.patch.yml 的插件包),由维护者 FYTXY 开发,分类为「工作流」。它通过拦截 llm/stream 链路,在接收到模型返回的 finish 事件时检查三个条件:reason 为 stop、未观察到工具调用、去除标记后文本为空。满足时将结果重写为 EMPTY_RESPONSE,触发重试机制。
插件没有依赖,不修改 DSH 原有文件,通过 DSH 的 bundle 机制安装。
核心功能¶
- 拦截只有协议标记的回合。当模型返回以
</||DSML|| calls>、<thinking> </thinking>或剩余标点结尾的内容,且没有工具调用时,将其转为 EMPTY_RESPONSE。 - 提供两处开关。在「Settings → Built-in plugins → Empty-turn guard」和「Plugins」侧边栏各有一处开关,控制同一个配置。
- 避免误判。插件要求同时满足 finish 为
stop、无工具调用、去标记后文本为空三个条件才触发。一个词的回答、单独的?或提及标记的正文都会正常通过。 - 不影响截断。
max-tokens限制导致的截断已经是可见结果,插件不介入。 - 日志安全。诊断日志只记录字符长度(如
text=24ch),不记录模型输出文本。
安装与启用¶
从 GitHub 安装:
dsh plugin --profile <your-profile> add github:FYTXY/dsh-empty-turn-guard
安装后重启 DSH,在「Settings → Built-in plugins → Empty-turn guard」打开开关即可生效。
若从本地 checkout 开发,可使用:
dsh plugin --profile <your-profile> add link:/absolute/path/to/dsh-empty-turn-guard
典型用法¶
启用后,当模型只返回协议标记时,日志会出现类似信息:
[dsh-empty-turn-guard] empty-turn-guard: mounted (markup-only stops become EMPTY_RESPONSE retries)
实际拦截时:
[dsh-empty-turn-guard] rewriting an empty stop (text=24ch) into EMPTY_RESPONSE
随后会触发 llm/retry 或 llm/retry-started 事件,由 DSH 的重试机制处理,默认重试 5 次,初始间隔 500ms,最大间隔 10s,带有 10% 随机抖动。
若需保持安装但暂时禁用,可在 profile 的 cordis.patch.yml 中为该行添加配置:
- id: dsh-empty-turn-guard
name: 'dsh-empty-turn-guard'
config:
enabled: false
enabled 是易失字段,无需重启即可生效。
适用场景与注意¶
适合需要稳定对话流程的场景,特别是对工具调用和回合完整性要求较高的工作流。
插件以当前 DSH 进程权限运行,安装前建议检查源码与许可证(MIT)。
小结¶
dsh-empty-turn-guard 通过在 llm/stream 链路前置拦截,把只有协议标记的空回合转为可重试的错误,减少静默失败。其实现不依赖额外运行时库,仅使用 DSH 现有的 llm/stream 和 EMPTY_RESPONSE 接口。
- 插件目录:https://www.skillhub.cn/plugins/FYTXY/dsh-empty-turn-guard
- GitHub:https://github.com/FYTXY/dsh-empty-turn-guard