#878·minimind

[Bug] 流式工具调用同时出现在 delta.content 和 delta.tool_calls

Author: shuyan-codeCreated Sep 26, 2026Updated Sep 26, 2026

问题

在 POST /v1/chat/completions 的 stream=true 路径中,生成文本会被立即作为 delta.content 发出;流结束后才调用 parse_response(full_text),把解析出的工具调用再次作为 delta.tool_calls 发出。因此模型输出工具调用时,客户端会同时收到原始 <tool_call>...</tool_call> 正文和结构化工具调用。聊天界面可能显示内部标记,兼容 OpenAI 的客户端也会收到不一致的数据。非流式路径会先解析,再构造 message。

相关代码:generate_stream_response 的正文发送与结束解析。

最小复现

请求提供 get_weather 工具并设置 stream=true。若模型生成:

<tool_call>{"name":"get_weather","arguments":{"city":"Beijing"}}</tool_call>

当前循环会先将该片段(可能拆成多个 chunk)放入 choices[0].delta.content;结束时又发出同一次调用的 choices[0].delta.tool_calls。可使用模拟的 streamer/模型输出验证,无需真实模型调用。

预期行为

工具调用的标记和 JSON 不进入 delta.content;流式客户端仅通过 delta.tool_calls 收到调用。普通文本仍正常逐块输出,跨 chunk 的标记与多个工具调用也应正确处理。

建议修复

在流式发送前加入增量解析:暂存尚未闭合的 <tool_call> 标记及 JSON,仅将确认属于普通回答的文本发往 delta.content;工具调用闭合且解析成功后,以包含 index、id、type 和 function 的事件发往 delta.tool_calls,并避免流结束时重复发送。增加跨 chunk、正文与工具调用混合、多个工具调用的回归测试。

这是基于当前 master 源码的静态核查;尚未运行真实模型的端到端请求。