DeepSeek Harness 报 unknown tool 空转?DSH plugin 工具调用 id 被覆盖排查

故障排查发布于 2026-09-12作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSH pluginunknown tool工具调用失败流式续帧
DeepSeek Harness 报 unknown tool "" 导致工具调用全失败?根因是流式续帧里的显式 null 覆盖了 DSH plugin 工具调用的 id/name。给出规避做法、源码定位与社区补丁进展。

DeepSeek Harness 报 unknown tool ""、每个工具调用都失败、模型空转几步后退出,根因是流式翻译把工具调用的身份覆盖成了空:provider 在首帧给出 id 与 name 后,又发送带显式 null 的续帧,SSE 翻译用 !== undefined 判定,把已捕获的身份写成了 null 这个问题不丢数据、不坏配置,换一个不发显式 null 续帧的 provider 就能立刻恢复。

DeepSeek Harness 报 unknown tool 空转是什么样

现象非常固定:日志里出现 [tool/call] {"callId":"","name":""},紧接着报 unknown tool "" 有用户实跑遇到(讨论原文),表现如下:

  1. 模型正常发起工具调用,但打印出来的调用请求里 callIdname 都是空字符串;
  2. 运行时找不到名为空的工具,直接以 unknown tool "" 拒绝执行;
  3. 模型收不到有效结果,继续尝试若干步后退出,整轮对话零产出;
  4. 同一 provider 下所有工具调用一起失败,不是某一个插件的问题。

这也是它容易被误判的原因:报错文本指向「工具不存在」,看起来像插件没装上或名字写错,实际插件完全正常——被丢掉的是调用本身携带的身份信息,而不是工具讨论原文)。

DSH plugin 工具调用身份为什么会被 null 覆盖

根因在 SSE 翻译层的判定写法:把「字段存在」与「字段有值」当成了一回事。 流式响应按帧下发,首帧带完整的 idname,后续增量帧只带变化字段。社区核对源码后定位到 packages/llm/llm-deepseek/src/translate.ts,问题链条是:

  1. 翻译层累积工具调用身份时,用 !== undefined 判断这一帧是否要更新字段;
  2. provider 发的续帧里字段是 null 而不是省略,null !== undefined 成立,于是执行覆盖;
  3. 首帧捕获的 id 与 name 被覆盖为空,日志里就出现 {"callId":"","name":""}
  4. 其中 空 name 才是致命项:name 为空直接导致工具无法解析,空 id 只是让调用难以对上号(来源)。

正确写法是只在字段「有实际值」时更新,把 undefinednull 都视为无效值。社区据此给出了修改判定条件的补丁分支 fix/tool-call-null-delta-identity,另有参考实现分支 Jstn-1g/reference/discussion-4671-sse-null-identity(提交 138691e0),两者都尚未合入。这个问题与 DSH插件、DeepSeek插件 各自的实现无关,因为覆盖发生在运行时共用的流式翻译层。

DSH plugin 场景下 unknown tool 空转怎么规避,修复到哪一步

在官方合入前,规避手段是绕开触发条件:换 provider / 模型,或回退版本。 按可达性从高到低排:

  1. 切换到不发显式 null 续帧的 provider 或模型:这是最快见效的做法,同一会话换完即恢复;
  2. 回退到出问题前使用的 DeepSeek Harness 版本,避开引入该翻译路径的改动;
  3. 排查时保留完整日志:[tool/call] 那一行的 callId / name 是否为空,是区分「工具真的不存在」与「身份被覆盖」的唯一判据;
  4. 需要装插件或回退插件版本来对照时,可在「设置 → 插件市场」里管理已装插件,本项目的社区插件市场入口是 DSH Plugin Hub
  5. 修复进度:补丁分支已经给出明确的改点(判定条件),但仍在等待官方合入,升级到含修复的版本前不要指望它自动消失。

DSH plugin 排查注意事项

先分清「工具不存在」与「调用身份被覆盖」再动手:前者要改插件,后者只要换 provider 或回退版本。 三条别踩的坑:

  1. 不要把 unknown tool "" 当成插件安装问题去重装:插件卸载重装不解决任何问题,被覆盖的是运行时捕获的身份,与插件包本身无关。
  2. 该问题与模型能力无关,不要靠换提示词规避:无论提示词怎么写,续帧里的 null 都会照常覆盖。
  3. 模型报错类问题还汇总在《DeepSeek Harness 模型报错合集:连接失败、模型清单缺失与配置排查》,可对照查看。
DSH Plugin Hub 已安装插件列表:集中管理已装插件、查看版本与更新

来源:Discussion #161Discussion #4671

常见问题

DeepSeek Harness 报 unknown tool "" 且所有工具调用都失败是什么原因?

DSH plugin 出现的这种空转,根因是流式翻译把工具调用的身份覆盖成了空。provider 在首帧给出 id 与 name 之后,又发了带显式 null 的续帧,SSE 翻译用 !== undefined 判定,把首帧已捕获的 id/name 覆盖成 null,于是每个工具调用都变成空名字,模型只能空转若干步后退出。

为什么在 DeepSeek Harness 里只有部分 provider 和模型会遇到 unknown tool 空转?

DeepSeek Harness 里,只有会发送显式 null 续帧的 provider 才触发这个覆盖。多数 OpenAI 兼容实现会直接省略空字段,字段缺席时不会被覆盖;一旦实现选择发 "id": null 这样的显式空值,就会命中这个判定缺陷。

在 DSH plugin 日志里,空 name 和空 id 哪个更致命,排查时应该先看哪个?

在 DeepSeek Harness 的日志里,空 name 才是致命项。id 为空只会让调用难以对上号,name 为空则直接变成 unknown tool "",工具没有可执行目标,调用必然失败;排查日志时优先确认 name 这一项是否被覆盖。

DeepSeek Harness 的 unknown tool 空转怎么临时规避,什么时候能修好?

DSH plugin 遇到 unknown tool 空转时,先换用不发显式 null 续帧的 provider 或模型,或回退到出问题前的版本,工具调用即可恢复。社区已给出修改 translate.ts 判定条件的补丁分支,等待官方合入后升级到含修复的版本即可。

相关术语

DeepSeek Harness
DeepSeek Harness(简称 DSH)是 DeepSeek 官方开源的智能体运行时,负责把模型、工具与插件组织成可执行的会话流程。DeepSeek Harness 官方文档
tool call(工具调用)
tool call 是模型在会话中要求运行时执行某个工具的请求,由 id、name、arguments 三部分组成。DeepSeek Harness 官方架构文档
SSE delta(流式增量帧)
SSE delta 是流式响应中在首帧之后追加的分片数据,只携带发生变化的字段,未变化的字段本应省略而不是填 null。DeepSeek Harness 官方架构文档

来源