DeepSeek Harness 工具参数非法 JSON:MALFORMED_RESPONSE、bash 超时与快照失真
DeepSeek Harness(DSH)里有一类故障看起来是「工具坏了」,实际是参数在传递链路上变了形**:模型把工具参数拼成非法 JSON,适配器在流结束时一次性解析失败、抛 MALFORMED_RESPONSE 硬终止本轮且不重试;deepseek-flash 会把模型侧的 DSML 调用标记混进参数 JSON,导致字符串永远无法闭合、会话用不下去;bash 工具里 heredoc 的感叹号触发交互式历史展开,命令根本没跑却烧满 300 秒超时;以及无损 JSON 快照把精确整数降级成对象——校验放行了,却在变换阶段悄悄失真。** 这四条的共同点是:报错都指向「结果不对」,但真正出问题的是「输入在中间被改过」,所以排查时要顺着链路往前找,而不是去改命令或结果(#9402、#9848、#9240、#8810)。
DSH插件 tool input is invalid JSON:参数被拼坏,而且不重试
一句话结论:适配器在流结束时对每个工具调用做一次参数 JSON 解析,失败即抛 MALFORMED_RESPONSE;而这个码不在默认可重试集合里,所以整轮立刻结束、既不重试也不带原文。 报错文本是 DeepSeek Messages stream: tool input is invalid JSON(#9402)。
DSH插件 判据:两类来源,一个报错
| 来源 | 特征 | 说明 |
|---|---|---|
| 模型偶发拼坏参数 | 报错偶发、换一轮可能就好了;参数前半段像 JSON | 解析在消息停止分支一次性执行,失败即终止本轮(#9402) |
| DSML 标记混入 | 报错可稳定复现、同一模型反复出现;会话用不下去 | 模型把参数后半段塌缩成 DSML 标记,累积字符串永远无法闭合(#9848) |
DSML 那条要特别说明:这是模型侧的格式泄漏——DSH 的系统提示与工具定义里都没有 DSML 概念(全仓搜索零命中),所以不要往配置或插件里找原因(#9848)。
DSH插件 四步处置
- 确认判据:报错里出现
tool input is invalid JSON且code=MALFORMED_RESPONSE(#9402)。 - 救急:执行一次
/compact。讨论中实测压缩后该会话能恢复正常(需要 agent 处于空闲);如果压缩本身因摘要过长失败,先把摘要调用的输出上限调大或换到更大窗口的模型再压(#9848)。 - 配置层缓解:把该码加进重试白名单。注意
retryableCodes是整体替换语义,写就要把默认五类一起写全(#9402):
- patch:
id: <你的 provider 适配器 id>
config:
retryPolicy:
retryableCodes:
- EMPTY_RESPONSE
- RATE_LIMIT
- SERVER
- TIMEOUT
- TRANSPORT
- MALFORMED_RESPONSE # 本次要补的码
- 更窄的插件门控:讨论中提到社区插件
@argszero/cordis-plugin-empty-response-retry可以把这类失败改判成可重试形态,比整体放开白名单更克制(#9402)。 - 要记住「遮蔽 ≠ 删除」:
/compact只是让后续请求不再携带那段坏参数,同一模型的同类输出仍会复发(#9848)。
DSH插件 bash 工具 300 秒超时:命令其实没跑,是 ! 触发了历史展开
一句话结论:多行命令被编码成 eval 形式交给交互式 bash 执行,而交互式 shell 的历史展开发生在解析之前、且不认 ANSI-C 引号——脚本里第一个 ! 就让整行被丢掉,工具于是等一个永远不会出现的完成标记,最后烧满超时并重置 shell。 症状是「模型只看到超时、看不到真实错误」,于是反复重试(#9240)。
DSH插件 复现判据与一行修复
- 复现:在 macOS 默认的 bash 3.2.57 上,执行一个带 shebang 的 heredoc 脚本,例如
#!/usr/bin/env python3这种开头——!会命中历史展开(#9240)。 - 关键细节:触发需要
!之前的上下文配合(讨论中给了交叉验证矩阵);所以「有时能跑、有时超时」并不矛盾(#9240)。 - 一行级修复(已验证):在初始化时同时关闭回显与历史展开:
stty -echo; set +H
set +H 关掉历史展开,是这条修复的核心(#9240)。
DSH插件 快照把精确整数变成对象:校验放行之后才降级
一句话结论:无损 JSON 校验接受真正的原始 JSON 值,但快照助手把它拷贝成带同名属性的普通对象,丢失了特殊序列化行为——于是校验通过之后,在变换阶段发生降级,一个整数可以变成对象。(#8810)
DSH插件 三步确认与处置
- 确认判据:同一个值在两种位置表现不同——声明为精确整数时报「输出非法」,作为对象的属性时静默变成结构体。这种不一致就是本条的指纹(#8810)。
- 规避:把精确整数字段声明为规范化十进制字符串,并在快照前编码回字符串;讨论中有对应的社区插件(
dsh-exact-integers)采用这种做法(#8810)。 - 验证:重跑同一工具调用,确认输出里的整数字段是数值或规范化字符串,而不是带属性的对象(#8810)。
- 诉求口径(值得写进反馈):要么保真、要么在校验阶段拒绝——唯一不可接受的是「校验放行之后在变换阶段降级」(#8810)。
DSH插件 排查注意事项
这四条的排查心法只有一句:报错指向「结果」,病因在「输入被改过」——顺着链路往前段找。 八条要点:
- 先分「偶发」还是「稳定复现」:偶发偏向模型输出不稳,稳定复现优先怀疑 DSML 这类格式泄漏(#9402、#9848)。
MALFORMED_RESPONSE是「不允许重试」的码,看到它立刻结束本轮属预期行为(#9402)。/compact是这一族的通用救急手段,但要清楚它只是遮蔽(#9848)。- 改重试白名单要写全:整体替换语义下漏写等于关掉默认重试(#9402)。
- 「命令没跑却超时」优先看 shell 语义,而不是去调超时值(#9240)。
set +H是这一条的关键动作,记它比记整段原因更实用(#9240)。- 数值类型失真别只看校验结果:校验通过不等于变换后仍然保真(#8810)。
- 修复状态如实:四条在讨论所指版本(
0.2.0-rc.2~0.2.1-alpha.*)里都未修;set +H是已验证的一行修复但属核心侧改动,其余三条的用户侧手段是配置(重试白名单)、命令(/compact)与插件(重试/历史展开/精确整数守卫)。
这类「参数变形」问题排查时,往往要先把插件层排掉——重试策略、历史展开守卫、精确整数守卫都是插件形态。如果你想先把环境看清,与其在各处手敲命令,不如用 DSH Plugin Hub 这类可视化插件市场:已安装列表、装卸历史与系统日志都在一个面板里。

来源:Discussion #9402、Discussion #9848、Discussion #9240、Discussion #8810。
常见问题
DeepSeek Harness 报 MALFORMED_RESPONSE 后不自动重试,是因为这个错误码不在默认可重试集合里。适配器在流结束的消息停止分支会对每个工具调用做一次参数 JSON 解析,失败就抛出 MALFORMED_RESPONSE,而重试轮只处理另外五类错误,所以整轮立刻结束。缓解方式是把该错误码加进所在 profile 的重试白名单(注意是整体替换语义),或使用把这类失败改判为可重试的社区插件。
在 DeepSeek Harness 里遇到这种报错,可以先执行一次 /compact 救急(需要 agent 处于空闲)。讨论中实测压缩之后该会话能恢复正常,因为压缩会重写上下文并让后续请求不再携带那段坏参数;如果压缩本身因为摘要过长失败,可以先把摘要调用的输出上限调大、或换到一个窗口更大的模型再压。注意这是缓解不是根治,同一模型的同类输出仍会复发。
DSH插件 的 bash 工具超时,是因为脚本里的感叹号触发了交互式 shell 的历史展开。多行命令被编码成 eval 形式执行,历史展开发生在解析之前、并且不认 ANSI-C 引号,于是整行被丢弃,工具等一个永远不会出现的完成标记,最后烧满超时。一行级修复是在初始化时关闭历史展开(同时保留回显关闭),用户侧可先规避:避免在裸 heredoc 里出现感叹号,或改用不触发展开的写法。
在 DeepSeek Harness 里精确整数变成对象,是因为快照助手把原始 JSON 值拷贝成了普通对象,丢失了特殊序列化行为。校验阶段接受这种值,但在其后变换阶段发生降级,于是同一个整数在声明为精确整数时报非法、作为对象属性时静默变成结构体。规避是把这些整数字段声明为规范化十进制字符串,或使用对应的社区插件在快照前编码回字符串。
DSML 是一类模型侧的工具调用标记语法,它不是 DeepSeek Harness 的概念。当模型把参数前半段输出成 JSON、后半段却塌缩成这类标记时,累积起来的字符串永远无法闭合成一个合法 JSON,于是解析在固定位置失败并抛 MALFORMED_RESPONSE。这属于模型侧格式泄漏,宿主的系统提示与工具定义里都没有这类标记,规避手段是压缩上下文或换模型。
相关术语
- MALFORMED_RESPONSE
- MALFORMED_RESPONSE 是 DeepSeek Harness 在响应内容不符合预期结构时使用的错误码,例如工具参数无法解析成 JSON。它不在默认可重试集合里,因此通常会直接终止当前轮次。— https://github.com/deepseek-ai/deepseek-harness/discussions/9402
- DSML
- DSML 是一类模型侧的工具调用标记语法,形如带特殊分隔符的参数标签。它不属于 DeepSeek Harness 的协议,出现在工具参数里会让参数 JSON 永远无法闭合,从而触发解析失败。— https://github.com/deepseek-ai/deepseek-harness/discussions/9848
- heredoc 与历史展开
- heredoc 是 shell 里用于内联多行文本的语法;历史展开是交互式 shell 把感叹号开头的片段替换成历史命令的功能。二者相撞时,脚本里的感叹号会让整行被历史展开吞掉,命令因此永远不执行。— https://github.com/deepseek-ai/deepseek-harness/discussions/9240
- 无损 JSON 快照
- 无损 JSON 快照是 DeepSeek Harness 在把工具结果物化进会话时保留原始数值语义的机制,用于避免大整数精度丢失。当前实现在拷贝原始 JSON 值时会丢失其特殊序列化行为,导致精确整数在变换阶段被降级成普通对象。— https://github.com/deepseek-ai/deepseek-harness/discussions/8810
来源
- #9402 — dsh-llm-deepseek 偶发把工具参数拼成非法 JSON ⇒ MALFORMED_RESPONSE 硬终止(无重试、无原文)· deepseek-ai(GitHub Discussions)
- #9848 — deepseek-flash 将 DSML 工具调用标记混入 tool input JSON,导致 turn 以 MALFORMED_RESPONSE 中止· deepseek-ai(GitHub Discussions)
- #9240 — Heredoc shebangs 里的感叹号触发历史展开 → 300s 超时(含一行修复)· deepseek-ai(GitHub Discussions)
- #8810 — Lossless JSON snapshots change raw values into objects: exact-integer transport· deepseek-ai(GitHub Discussions)