AI API 返回 HTTP 200,为什么流式任务还是失败?从连接到完成事件的排查方法

请求日志是 200,界面也出现过几个字,但客户端最后提示失败。这种情况不能仅凭 HTTP 状态码判断任务已经完成。

流式请求需要分开看三件事:HTTP 响应是否正常开始、事件是否被正确解析、模型响应是否到达协议定义的完成状态。即便模型响应完成,文件修改、工具执行等业务任务也仍需单独验收。

本文由 NexoToken 团队整理,讨论通用接入方法。下面的时序是用于解释问题的示意,不是某次生产故障实录,也不是对本站可用率的统计。

1. 先把三个“成功”拆开

层次 观察到什么 还不能证明什么
HTTP 收到 200 和响应头 后续响应一定完整
事件流 收到并解析了文本增量 模型响应已经正常结束
业务任务 得到最终内容或工具调用结果 修改已通过测试、外部操作已经成功

服务先发出响应头,再持续发送内容时,后续失败未必还能通过另一个 HTTP 状态码表达。它可能表现为错误事件、未完成状态、连接中断或客户端超时。

因此,监控里只有一个 http_status=200,信息还不够。

2. 网络分块不是 SSE 事件

一次读取可能只有半条事件,也可能包含多条事件。不能拿到一块网络数据就直接对整块执行 JSON 解析。

SSE 使用 UTF-8,事件按行组织,空行用于触发事件分发;连续的 data: 行会组合成事件数据。标准还允许不同换行形式,连接结束也不能直接替代缺少的事件边界。WHATWG SSE 规范

如果使用成熟 SDK 或解析库,这部分通常由库处理。自己实现时,至少要分别保存字符解码状态、尚未读完的行和当前事件。否则,正常的分块边界就可能被误报成“服务返回了错误 JSON”。

排查时可以记录解析失败的阶段和事件类型,不要为了调试把原始事件正文全部写进日志。正文可能包含用户输入、模型输出或工具参数。

3. 输出了文字,不等于已经完成

以 OpenAI Responses 为例,文本增量和整个响应完成是不同事件。接入时需要分别处理完成、失败、未完成和错误,而不是只监听输出文本。Responses 流式事件参考

一种可能的时序是:

收到 HTTP 200
收到响应创建事件
收到若干文本增量
连接结束
没有确认到正常完成状态

最后一步应该标为“结果未确认完整”,而不是因为前面出现了文字就记录成功。至于它是网络异常、用户取消还是服务端问题,需要结合后续证据判断。

不同协议的终止条件不同。不要把某个接口里的结束标记,直接当作所有模型 API 的统一规则。

4. 用一个字段记录失败,往往查不清

建议为排错保留一个精简记录:

任务关联标识
请求标识
请求开始时间
收到响应头时间
首段有效内容时间
终止时间
HTTP 状态
协议终止状态
是否由用户取消
用量统计是否可用

这些是应用内部的观测字段示意,不是某个 API 规定的响应格式。

这样就能区分:一直没拿到响应头、拿到头但没有内容、输出到一半中断、协议已经完成但客户端展示失败。几类问题混在一个“调用失败”计数里,后续很容易修错地方。

用量统计缺失也应单独标记。不能把“没有拿到 usage”自动记成零 Token,也不能据此推断一定没有发生费用。

5. 重试前先确认请求做到哪一步

如果任务只是生成一段文本,重试可能带来重复生成与额外开销;如果 Agent 已经创建工单、写文件或触发外部动作,整段重跑还可能重复执行这些操作。

因此,建议先检查:是否已有完整结果、哪些工具动作已经执行、调用方有没有幂等约束,以及重复运行是否可接受。确认后,再决定重试整个任务还是只恢复尚未完成的一步。

把“遇到异常就重试三次”当成默认恢复方案,会让表面成功率变好,却未必让结果和账单更可靠。

6. 可以从这四种情况开始验收

  1. 普通文本流正常结束,客户端识别到正确终止状态。
  2. 在受控测试环境模拟中途断开,客户端不把部分内容当成完整结果。
  3. 用户主动取消,界面与日志能区分取消和异常。
  4. 一次工具调用完成回传,后续模型响应与业务结果都能核验。

模拟异常应在本地或隔离环境进行,不需要为了写测试报告干扰生产服务。

NexoToken 维护的流式、工具与长上下文测试资料可以作为扩展检查项。本文不声称列出的所有边界已在每个客户端上测试通过。

HTTP 200 是一条有价值的信息。把事件解析、响应终止和业务验收也记录下来,它才能成为完整排错证据的一部分。

进入 NexoToken 查看接入文档,按客户端所需协议逐项验证

posted on 2026-09-08 13:51  wangjjj1122  阅读(32)  评论(0)    收藏  举报