前言¶
在 DSH(DeepSeek Harness)里跑带大段代码或 HTML 的工具调用时,有时会出现一种很误导人的现象:界面显示 turn 已正常完成,实际上没有任何工具被执行,而 <invoke>、<parameter> 或带 antml: 前缀的调用标记却混进了 assistant 正文。Harness 不报错,agent 循环直接当作 {kind:'completed'} 结束。坏样本还会留在历史里,模型容易继续模仿同一格式;fork 会把父会话里的损坏输出一并继承。社区里也有人把这类连锁失败叫作 chain reaction。
dsh-tool-call-leak-fix 是维护者 IRwDONE 发布的工作流类宿主插件(GitHub 仓库 IRwDONE/dsh-tool-call-leak-fix,npm 包 @irwdone/dsh-tool-call-leak-fix,当前资料中的版本为 0.5.1,MIT 许可证,零运行时依赖)。它针对「调用标记泄漏为正文、调用未执行却 turn 静默关闭」这一类失败,在分发前拦截、在同一 turn 内纠偏、fork 时简报、并在模型可见面上作废已进入历史的损坏输出。下面介绍它解决的问题、机制、安装方式与配置边界。
这是什么¶
一句话:DSH 宿主插件,把「工具调用没跑、标记却进正文、turn 像成功一样关掉」从静默 no-op 变成可感知、可纠正的行为,并在 fork 与上下文回放侧尽量切断坏样本对后续模型的影响。
维护者 IRwDONE;分类为工作流;插件在 SkillHub 目录页为 dsh-tool-call-leak-fix。实现为纯 ESM JavaScript,仅使用 Node 内置模块,不需要额外构建或前端半边。
故障长什么样¶
README 里保留了一段真实形态的节选:思考内容里模型甚至意识到该用 antml: 前缀,但整段调用仍作为正文输出,随后 turn 结束且没有工具卡。常见形态包括:
- V1 结束序列增殖:调用尾部结束标记重复出现。
- V2 开场标记缺失:只剩参数开场,没有外层 invoke 开场。
- V3 泄漏为正文:调用信封混进 assistant 正文,未被识别为真正工具调用。
- V4(相关):容错 JSON 解析把非法参数降级为
{},工具带着空参数执行。
泄漏方言既有裸标签(<invoke / <parameter),也有 antml: 前缀形式;还有「伪造工具结果」——正文出现结果形标记但该步并未调用工具。三种核心形态都是静默失败:不执行、不报错,turn 正常关闭。
用户在对话里让模型自行修复、仅 fork、或 compact,往往不能从根上去掉历史里的坏样本;README 说明装上本插件后,fork 之后损坏输出可在模型可见面上被作废,后续对话可不再出现同类泄漏型失败(具体还依赖 M9 等开关,见下文配置)。
核心功能¶
插件 README 将能力归纳为多条守卫(平时不主动打扰用户):
拦截(M2)¶
工具调用分发前扫描已解析参数。若某字符串参数边界已损坏(例如尾部结束序列增殖、结构中途截断),且体量达到阈值(默认 ≥2000 字符或 ≥20 行),则拒绝本次调用并给出可操作说明(如建议拆成 ≤100 行分块重发)。同时处理「声明必填却收到空 {}」的情况。已现场验证:真实会话中 22 行以上且结构截断的参数在分发前被拒,目标文件未被创建。
纠偏(M3)¶
写入类工具执行后,若结果中有机器可读的空转证据(如 noop: true、status: "noop"、written: 0 且确实带了内容),在结果后补一句短提示,不做自由文本猜测。由配置项 noopCheck 控制总开关。
自愈(M4)¶
观察已提交的 assistant 消息:若某步输出损坏且该步没有任何工具调用,在 turn 即将关闭时注入纠正,保持 turn 打开、让模型在同一 turn 内重发。纠正次数有上限,由 maxCorrectionsPerTurn 控制;本 bundle 的 patch 将默认改为 2,以便「第一次纠正后又写坏」时还能再给一次更硬的指令。到顶即停,避免循环。已现场验证 turn 不关闭并继续的完整链条。
fork 简报(M7)¶
fork 会话继承父历史且历史本身难以改写(README 称冻结请求 D-8)。插件在 fork 的第一个模型步之前注入一次代码生成的简报:把历史里「没有对应工具卡的孤立调用标记」标为损坏、未执行,请模型勿模仿。每个会话只放一次;非 fork 零开销。由 forkBrief 控制。
上下文修复(M9)¶
已进入历史的坏样本仍会被逐字回放。插件在模型可见 surface 上遮蔽损坏步骤(该步损坏且无工具调用),换成静态说明(「此处原为损坏输出、已作废,请勿模仿」),日志原始事件保留,零模型调用。启用前用自建探针自检 surfaceOp.replace 语义;自检失败则整个会话故障关闭。fork 继承的损坏步骤可在每会话第一次 turn 结束时一并扫描遮蔽。由 repairContext 控制,设为 false 可完全停用。
装上之后的行为对比(摘要)¶
| 以前 | 现在(插件生效时) |
|---|---|
| 坏调用不执行、不报错 | 分发前拦截并说明原因 |
| 泄漏后 turn 静默关闭 | turn 保持打开,同 turn 内纠正重发 |
| 写入工具自报成功却无改动 | 结果后补空转提示(M3) |
| 历史坏样本持续被模仿 | 当场机制缩短故障窗口;不能改写已写入的历史(见边界) |
README 明确:刻意不做 system-prompt 规则块注入,也不做「强制小块写入工具」。
安装与启用¶
用 Harness 自带的插件管理器安装,不要手改 profile 来「假装挂上」。三种方式任选其一。
方式 A:在插件市场 / 插件管理器搜索 dsh-tool-call-leak-fix 或 @irwdone/dsh-tool-call-leak-fix,点击安装。
方式 B:一条命令安装时使用 npm 包名或 GitHub 地址(资料原文如下,勿自行拼接其它 install 语法):
@irwdone/dsh-tool-call-leak-fix
或(仓库需公开):
https://github.com/IRwDONE/dsh-tool-call-leak-fix
方式 C:克隆仓库后,对 install_bundle 的 target 填仓库根目录(含 package.json),不要填到 plugin/ 子目录。
安装之后:
install_bundle返回application: "applied"即表示已生效;若提示重启则重启 Harness。- 判活:插件管理器列表,或 Config 中出现
include:tool-call-leak-fix;更硬判据是是否真的注入了纠正。 - 不要仅通过 grep
~/.dsh/profiles/<profile>/cordis.patch.yml判断——bundle 自带 patch(plugin/cordis.patch.yml,由package.json的dsh.bundle.patch声明),该行本就不一定出现在 profile 的 patch 里。 - 停用:管理器禁用,或将该行
config.enabled设为false。
配置¶
config 会校验并归一化;非法值回退默认。数值阈值须为整数且 ≥1(仅 maxCorrectionsPerTurn 允许 0)。
| 键 | 默认 | 含义 |
|---|---|---|
enabled |
true |
false 时不注册任何监听器 |
maxLines |
100 |
单字符串叶子行数上限(过长预警) |
maxChars |
20000 |
单字符串叶子字符数上限 |
closingTagCount |
8 |
</ 出现次数作「密集」证据,不单独导致拦截 |
endSequenceRepeats |
2 |
尾部连续结束序列达到几个判损坏 |
maxCorrectionsPerTurn |
1 |
每 turn 最多自愈次数;本 bundle patch 设为 2 |
lang |
zh |
注入文案语言:zh / en |
noopCheck |
true |
M3 空转检查总开关 |
debugLog |
false |
诊断日志;false 时不写文件 |
debugLogPath |
'' |
空串由系统临时目录推导 |
contextGuard |
false |
内部保留、未接线 |
contextGuardNote |
'' |
内部保留、未接线 |
forkBrief |
true |
M7 fork 首步前简报 |
forkBriefNote |
'' |
空串用内置中英文简报 |
repairContext |
true |
M9 模型可见面遮蔽损坏步骤 |
典型用法与适用场景¶
本插件没有单独的「业务 API」:安装并启用后,守卫在工具分发、turn 关闭、fork 首步、会话 surface 替换等接缝上自动工作。典型适用场景包括:
- 经常通过 DSH 调用「大段 code / HTML / JSX」类参数的工具,且遇到过 invoke/parameter 标记出现在正文里。
- fork 父会话后继续开发,希望 inherited 历史里的损坏调用标记被简报或 M9 作废,减少模仿。
- 需要把静默 no-op 变成带原因的拦截或同 turn 重试,而不是误以为任务已完成。
注意:
- 插件以当前 DSH 进程权限运行;安装前请自行阅读仓库源码与 MIT 许可证,确认可接受其行为(含 M9 自检失败时关闭整个会话等策略)。
- README「已知边界」:不能改写历史(M5 / D-8);坏样本「不洗白过去」,只能缩短故障窗口。绕法包括新开会话,或明确让模型忽略某段损坏内容。
M2拦截、M4自愈、M7fork 简报、M9上下文修复在 README 中标注为已现场验证;做不到的部分以仓库「已知边界」为准。
结尾¶
dsh-tool-call-leak-fix 把 DSH 里一类常见的工具调用静默失败——标记泄漏、turn 假完成、历史污染——拆成拦截、同 turn 自愈、fork 简报与模型可见面作废四层处理,零依赖、仅依赖 Host 半边接缝。社区目录页:SkillHub · dsh-tool-call-leak-fix。源码与完整说明:GitHub · IRwDONE/dsh-tool-call-leak-fix。