前言¶
在 DSH(DeepSeek Harness)里跑带 Jina MCP 的智能体时,模型流式输出的 tool_use 参数会在回合结束时被 DeepSeek 适配器整段解析。一旦累积的 partial_json 不是合法 JSON,适配器会抛出 MALFORMED_RESPONSE: DeepSeek Messages stream: tool input is invalid JSON,整轮对话直接结束,工具也根本来不及执行。损坏通常来自模型输出,而不是 DSH 网关;网关侧保存的响应里往往同样是坏的。把工具 schema 从 anyOf: [string, array] 压成纯 string 能缓解症状,却会丢掉一次调用传入多个 URL 或查询的能力。dsh-plugin-jina-json-repair 在 llm/stream 接缝处拦截并在持久化前尝试修复,同时用请求里的 schema 校验,避免「能解析但语义已乱」的参数悄悄执行。
这是什么¶
dsh-plugin-jina-json-repair 由维护者 frederick-wang 发布,归类为模型推理。它在 DSH 的 provider 适配器与会话日志之间监听 llm/stream 瀑布流,针对 Jina MCP 的 read_url、search_web(及可配置的其他工具)在流关闭前修复畸形 tool-call 参数;修复后全部块均通过 schema 校验时,用合成的 finish: tool-calls 放行,让回合继续。当前 package 版本为 0.1.2,许可证 MIT,运行环境要求 Node >= 20。
问题从哪来¶
DSH 的 DeepSeek 适配器在流结束时解析每个 tool_use 块。无效 JSON 会触发上述 MALFORMED_RESPONSE,整轮中止。README 中给出的典型坏样本是字符串值少写了引号:
{"url": https://example.com/a}
维护者在资料中说明:某一 profile 下 62 个工具里,只有 read_url 和 search_web 把必填参数声明为 anyOf: [string, array],绝大多数坏样本也集中在这两个工具上。本插件保留原有 schema,改在流层修复,而不是把 schema 扁平化成单一 string。
核心机制¶
插件在 llm/stream 上工作:每个 tool-call 的 block-end 会暂留到 finish 到达;文本与推理类的 delta 仍立即透传,正常流式体验不受影响。
当 finish 为带 tool-input 提示的 MALFORMED_RESPONSE 时,对配置目标工具的已暂存参数运行 jsonrepair(依赖 jsonrepair ^3.15.0),再按本次请求里该工具的 schema 校验,包括:
- 必填键存在;
- 声明的属性类型匹配;
format: "uri"的值为 http 或 https;- 数组非空;
- 不出现 schema 未声明的键。
最后一条用来约束 jsonrepair 的「过于宽松」:{"url": https://a.com, https://b.com} 可能被修成带多余键的结构,校验会拒绝,而不是带着错误参数去调工具。若消息里所有 tool-call 块都校验通过,则释放修复后的块并合成 finish: tool-calls;否则原错误原样传出,由 DSH 既有重试策略处理。若请求未携带某工具的 schema,则不做修复。同一消息里若有无法修复的 bash 等块,即使 read_url 可修,整轮仍会中止——未经验证的参数不去执行。
安装与启用¶
插件通过 dsh.bundle.patch 声明,安装后会追加到 profile 的 dsh.profile.bundles,并由包内 cordis.patch.yml 挂载。安装后需重启 DSH,插件在启动时挂载。
从 GitHub 安装(命令来自官方 README,profile 示例为 dsh-tui):
dsh plugin --profile dsh-tui add github:frederick-wang/dsh-plugin-jina-json-repair
本地目录安装:
dsh plugin --profile dsh-tui add ./dsh-plugin-jina-json-repair
dsh plugin add 会把包装进该 profile 的 node_modules。DSH 社区插件目录为独立站点,与 DeepSeek / 幻方无官方从属关系;安装前请自行阅读仓库源码与 MIT 许可证。插件在当前 dsh 进程权限下运行,与其他 DSH 插件相同。
配置¶
默认修复目标为 read_url、search_web,匹配工具名中 server__ 之后的部分。可在 profile 的 cordis.patch.yml 中覆盖:
- id: jina-json-repair
config:
tools:
- read_url
- search_web
- search_arxiv
列表为空或缺失时回退到默认两项。列入的工具只有在参数能通过自身 schema 校验时才会被修复,单纯增删名单不会放宽安全边界。
已知限制与 UI 行为¶
修复成功的回合会丢掉其 replayState,该轮 thinking 块回到 provider 时不再带签名;DeepSeek 接受无签名 thinking,后续回合仍可进行,但较早的推理无法逐字回放。
插件修的是 JSON 语法,不是语义:模型若完全省略必填字段,没有可修内容,错误仍会透出。修好的 search_web 查询仍可能是无意义的合法字符串。
为等待 finish,tool-call 在界面上的展示会略晚于流结束,README 称通常为最多几百毫秒。
开发与测试¶
维护者提供的本地开发命令:
pnpm install
pnpm test
测试套件用 Node 内置 runner,README 写明共 21 个用例,覆盖透传、修复、拒绝、顺序、中止、schema 查找与自定义目标列表,无需真实 provider。
适用谁¶
适合在 DSH 中频繁使用 Jina MCP 的 read_url / search_web(或你在配置里扩展的同类工具)、且常被模型输出畸形 JSON 打断整轮对话的开发者。不适合指望插件「理解」错误语义或替模型补全缺失字段的场景。