Replies: 2 comments
|
Confirmed with DeepSeek-V4-Pro; the same tool schema and prompt work with DeepSeek-V4-Flash. I implemented option A as a minimal two-file change and added a regression test for a valid opening identity followed by empty-string continuation placeholders: Gelly52/deepseek-harness@master...develop/fix-empty-stream-tool-identity The translator now updates |
0 replies
|
感谢 @Gelly52 的跨模型复核(DeepSeek-V4-Pro 复现、V4-Flash 通过)并实现方案 A + 回归测试。这个对照尤其有价值——它把"判空写法差异"从单模型偶发锁定为跨模型的确定性缺陷,也印证了根因定位。感谢落地最小改动。 |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
摘要
dsh-llm-deepseek的 SSE 流装配器在合并tool_calls[]delta 时,用call.id !== void 0/call.function?.name !== void 0作为写入守卫(lib/index.jsL321-322)。对"后续块用空字符串""占位 id/name"的 OpenAI 兼容网关(OpenAI 规范本应只在首块携带 id/name、后续省略),空串通过守卫并覆盖首块已写入的值——最终工具调用块变成id=""、name="",agent 循环发出空名工具调用,本地注册表返回unknown tool "",整轮工具调用不可用。这是 #879 的现象,源码断点即上述两行。复现步骤
id=""、name="";agent 以空名调用工具 →ToolNotFoundError: unknown tool ""。根因(源码定位,rc.6)
@deepseek-ai/dsh-llm-deepseek/lib/index.jstranslate的 delta 合并循环(L310-332):undefined,不排除空字符串;OpenAI 规范约定 id/name仅在首块出现,因此符合规范的网关后续块省略这两个字段(
undefined)——但存在以空串占位的兼容网关,空串通过守卫后覆盖首块已写入的
call_xxx/ls。?? ""++=(L323-324),空串不影响累加——唯独id/name 的"最后写入者胜"语义对空串是错误行为。
建议修复
方案 A(推荐)· 空串视为缺失:L321/L322 增加空串排除:
一行一处,向后兼容(规范网关不受影响),空串占位网关立即恢复。
方案 B · keep-first 语义:id/name 只在块尚未赋值时写入(
block.callId === void 0才写)。更贴合"首块携带、后续省略"的规范意图;但对"后续块才第一次出现 id/name"的异常网关
(虽然不该存在)会丢值,需要与 A 权衡。
方案 C(诊断增强)· 装配后校验:块结束时若
callId/name为空,抛出带网关上下文(如块索引)的明确错误而非静默产出空名工具调用——至少让用户知道是网关
不符合规范,而不是"unknown tool"这种误导性错误。
影响
[bug]llm-deepseek: SSE tool_calls id/name overwritten by empty-string deltas #879 的示例即其一)工具调用整体不可用,且最终错误
unknown tool ""完全误导定位方向
缺失值"的防御不足(Bug: tool calls are dropped against servers that send null in continuation deltas (id/name overwritten, every call becomes UNKNOWN_TOOL) #161 已报 null,本报告补上空串分支)
环境
dsh-llm-deepseek/lib/index.jsL310-332,Node v24.16.0,Windows 11)
验证材料
!== void 0守卫 + L323-324 的+=对照""通过守卫覆盖首块值)id="call_xxx"、name="ls"First source-located analysis of discussion #879. Happy to open a PR with fix option A.
All reactions