dsh-plugin-jina-json-repair:在 llm/stream 层修复 Jina MCP 工具调用的畸形 JSON

前言

在 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 校验,包括:

  1. 必填键存在;
  2. 声明的属性类型匹配;
  3. format: "uri" 的值为 http 或 https;
  4. 数组非空;
  5. 不出现 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 打断整轮对话的开发者。不适合指望插件「理解」错误语义或替模型补全缺失字段的场景。


羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜