问题原因:Qwen3-32B模型流式工具调用的后续分片用空 id/name 覆盖了首帧有效值,导致实际执行成为 unknown tool "";随后携带失败工具结果的第二轮模型请求返回 HTTP 406。 |
Replies: 1 comment
|
你的机制判断方向对,这属于 wire identity-loss 家族(同族已有多起:#5268 GLM 同响应重复 callId、#5182 空 id、#5247 前端 dup-start)。对照上游 master(4e84901e64 = 0.1.2-alpha.4),DSH 侧有一个真实的不对称点 + 一个需要你提供判别信息的层级问题: 1. BlockAssembler 的 id/name 处理不对称(llm/src/assembler.ts)
也就是说:只要 delta 流里出现过一次 2. 层级问题:覆盖发生在 pi-ai 内部还是 DSH 之外? 所以你的场景只有两种可能:
判别方法:DSH 为回放保真会记录原始 chunk(assembler 头部注释明说 raw chunks 落盘)——把你那条会话的原始流 chunk 尾部贴出来(工具调用的 toolcall_start / 各 delta 的 id、name、arguments 前 40 字符 / 有没有 block-end),一眼就能定是 (a) 还是 (b)。另外告知 provider 路由(llm-pi-ai 自定义 OpenAI 兼容 base URL,还是 deepseek 系适配)。 3. HTTP 406 不在现有错误分类里 要定位到具体层,把原始 chunk 日志 + provider 路由发出来即可;若确认是 (a),DSH 侧可做的防御是 assembler :72 加空值守卫(与 :73 name 对称)+ |


你的机制判断方向对,这属于 wire identity-loss 家族(同族已有多起:#5268 GLM 同响应重复 callId、#5182 空 id、#5247 前端 dup-start)。对照上游 master(4e84901e64 = 0.1.2-alpha.4),DSH 侧有一个真实的不对称点 + 一个需要你提供判别信息的层级问题:
1. BlockAssembler 的 id/name 处理不对称(llm/src/assembler.ts)
partial.toolCallId = chunk.id—— 无条件覆盖,后续 chunk 带空 id 会直接抹掉首帧有效 id;if (chunk.name) partial.toolCallName = chunk.name—— name 有 truthy 守卫,空 name 覆盖不了首帧;assemble()的兜底partial.toolCallId ?? call-${index}只救 nullish——空字符串不是 nullish,'' ?? 兜底仍得''。也就是说:只要 delta 流里出现过一次
id: ""(空字符串存在而非字段缺失),DSH 最终就拿空 id 去执行。name 有守卫所以通常能活下来——你看到「unknown tool ''」,如果空的是 name 而不是 id,说明空值是从 block-end 的权威 block 带进来的(见下)。2. 层级问题:覆盖发生在 pi-ai 内部还是 DSH 之外?
pi-ai adapter(l…