Qwen3.7-Plus 在启用 tools 后输出半截中断,不能只凭页面上“少了一段文字”判断是模型 Bug。应先保存原始流式事件,分别检查 HTTP 是否完整结束、最后一个数据包的 finish_reason、工具参数是否拼接完整,以及应用是否把工具调用阶段误当成最终回答。原帖报告了带 tools 时高概率截断和重复结束原因,但售后尚未给出结论,因此当前最可靠的处理方式是复现、分层定位并保留请求 ID。
工具调用(Function Calling)不是一次普通的文本生成。模型可能先返回工具名和参数,应用执行工具,再把 tool 角色的结果发回模型,最后才生成面向用户的答案。任意一段提前结束,界面上都可能表现为“只输出一半”。
第一类是传输中断:服务端仍在生成,但代理、网关、SDK 超时或客户端主动取消连接。第二类是生成达到限制:输出 Token 达到上限,结束原因为 length。第三类是工具调用被误判:模型已经正常结束当前工具调用轮次,客户端却没有继续执行工具或请求下一轮。第四类才是服务端返回序列异常,例如同一选择出现互相冲突的结束事件或工具参数永久缺失。
普通流式文本只需按顺序拼接 delta.content。工具调用还需要按选择序号和工具调用序号累计名称、调用 ID 与 JSON 参数。参数可能跨多个数据块返回,不能把每个片段单独解析为完整 JSON,也不能收到第一个非空 finish_reason 就立刻丢弃队列中尚未消费的数据。
阿里云百炼的官方 OpenAI 兼容接口说明,设置 tools 后,模型决定调用工具时会通过 tool_calls 返回信息。对于包含数组或对象的复杂工具参数,Qwen 系列还提供 tool_stream 控制是否流式输出参数。关闭时参数集中返回,格式通常更准确,但复杂参数可能面临等待时间;开启时复杂参数分片输出,客户端必须正确累计。
复现请求要尽量小,只保留一个工具、一个必填字符串参数和一条用户消息。固定模型精确名称、地域、接入域名、SDK 版本、stream、tool_stream、思考模式、输出上限和超时设置。每次测试保存以下信息:
如果不能记录原始事件,至少在解析器前增加日志。只看聊天界面无法区分服务端少发、SDK 少读、代理截断和业务代码提前停止。
工具参数应按 choice.index 与 tool_calls[].index 建立独立缓冲区。每个数据块只追加本次增量;直到该轮结束后,才把完整字符串作为 JSON 解析。工具调用 ID 和名称也可能分片或只在早期数据块出现,不能用后续空值覆盖已保存值。
for event in stream:
save_raw_event(event)
for delta_call in event.tool_call_deltas:
key = (event.choice_index, delta_call.index)
buffers[key].id = buffers[key].id or delta_call.id
buffers[key].name += delta_call.name_fragment or ""
buffers[key].arguments += delta_call.arguments_fragment or ""
record_finish_reason(event.choice_index, event.finish_reason)
parse_json_only_after_stream_finishes(buffers)
这段伪代码的重点不是具体 SDK 字段名,而是保留原始顺序、按索引聚合和延迟解析。若应用使用统一 OpenAI 适配层,还要确认适配层没有把厂商扩展字段过滤掉。
finish_reason 表示当前选择停止生成的原因,不等于整条业务链路已经得到最终文本。遇到 length 时先提高合理的输出上限或缩短上下文;遇到工具调用结束时,应执行工具并提交带匹配 tool_call_id 的工具结果;值为 null 的中间流式包通常不能作为终止信号。
百炼官方文档还指出,非流式请求超时后可能返回已生成的部分内容,并通过响应头标识部分响应;无法读取响应头时,可结合结束原因判断内容是否完整。因此,排查时不能只打印最终字符串,响应头和尾包同样重要。
若同一个 choice 确实收到两条非空且语义冲突的结束原因,应保留未经 SDK 二次加工的 SSE 数据。某些封装会把工具调用轮次与最终回答轮次合并展示,看起来像重复;只有原始流中同一请求、同一 choice 的事件异常,才能更有力地指向服务端或兼容层问题。
tools,确认普通文本流是否完整。tool_stream 开关,观察复杂参数是否只在一种模式下失败。若直连也能稳定复现,而且原始尾包或工具参数不完整,就把最小请求、发生时间、地域、模型名和请求 ID 提交给平台售后。若直连正常而生产链路失败,则逐层恢复网关、SDK 封装和业务解析器,最先恢复后出现异常的层就是主要排查对象。
在原因未确认前,可以让复杂工具参数采用非流式返回,或对工具调用轮次关闭流式,仅对最终回答使用流式输出。提高客户端读取超时和网关空闲超时也能排除连接层问题,但不能掩盖参数拼接错误。重试必须使用幂等设计,尤其是支付、发信和写数据库等有副作用的工具,避免截断后重复执行。
应用还应把“收到完整工具参数”“工具执行成功”“收到最终回答尾包”设计成三个独立状态。任何状态缺失都应显示可恢复错误,而不是把半段内容当作成功回答。这样即使问题来自模型服务,也能防止异常结果直接进入生产业务。
修复不能以一次请求成功为准。应使用同一最小样例分别测试有无 tools、流式与非流式、简单与复杂参数,并连续运行足够次数。成功标准是工具参数均可解析、调用 ID 能正确关联、每轮结束状态一致、最终回答完整,且生产网关日志中没有超时或主动取消。
因此,Qwen3.7-Plus 带 tools 截断的首要动作是抓取原始事件并建立对照,而不是直接更换模型或只调大 Token 上限。原帖现象值得提交平台排查,但在售后结论出现前,只有把传输层、流式解析、工具状态机和服务端响应逐层分开,才能判断它究竟是模型接口异常还是客户端兼容问题。
高质量编程 Prompt 要具备哪些关键要素?
追踪 Claude Code 用量及文件修改过程
Claude Opus 4、GPT-5 等 AI 编程助手在 RubberDuckBench 上表现如何?
Claude 与 GPT 模型家族的代码生成能力如何与人类程序员比较?
从线性 Agent 到流程图:用 LangGraph 编排分岔、循环与暂停
最新版Ubuntu 17.10与Windows 双系统安装、配置与美化详细图文教程