AI API 流式指南:SSE、首输出与超时

学习 Chat Completions 与 Responses 的流式事件、SSE 解析、首个有效输出、分阶段超时及 499 取消诊断。

AI API 流式响应会在模型生成过程中逐步发送输出,而不是等完整响应体生成后再一次返回。它可以改善用户感知速度,但不一定降低模型本身的延迟,同时还要求客户端正确实现一套流式协议。

第一条原则是让解析器与端点匹配。Chat Completions 返回流式 completion chunk,Responses 返回带类型的 response event。即使 HTTP 状态是 200,如果客户端期待了错误的事件结构,也可能完全渲染不出内容。

从不缓冲的请求开始

对于 Chat Completions 模型,curl -N 会关闭 curl 的输出缓冲:

curl -N -sS https://modelflare.dev/v1/chat/completions \
  -H "Authorization: Bearer $MODELFLARE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "YOUR_CHAT_MODEL",
    "messages": [{"role": "user", "content": "用三点解释 SSE。"}],
    "stream": true
  }'

对于兼容 Responses 的模型:

curl -N -sS https://modelflare.dev/v1/responses \
  -H "Authorization: Bearer $MODELFLARE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "YOUR_RESPONSES_MODEL",
    "input": "用三点解释 SSE。",
    "stream": true
  }'

请从模型与价格选择准确的模型 ID。先把同一请求以非流式方式执行一次,可以把请求校验问题与流式解析问题分开。

把事件流当成一套协议

Server-Sent Events 是有边界的事件记录,而不是任意切开的 JSON 片段。生产客户端需要:

  • 确保 HTTP 库、代理和 UI 层都不会缓冲响应体;
  • 累积不完整的网络读取,直到获得一个完整事件;
  • 按所选端点解析正确的事件类型;
  • 处理文本增量、推理或工具事件、完成事件和错误事件;
  • 不要假设所有有效响应都包含可见文本;
  • 保留取消状态与最终用量信息;
  • 收到终止事件后主动关闭,而不是无限等待。

应优先使用原生支持目标协议的 SDK。自建解析器至少要测试事件被拆成多次读取、一次读取包含多个事件、仅工具输出以及正常终止等情况。

不要只测“首个 Token 时间”

对于 Agent 流量,“首个 Token 时间”经常不够精确。应该分别测量:

指标 含义
连接与鉴权 到达网关并完成 Key 校验所需时间
上游响应头 所选路由开始返回响应的时间
首个有效输出 首段有意义的文本、推理或工具事件
首段可见文本 用户真正可以看到的第一段文字
输出吞吐 可见输出开始后的生成速度
总响应时间 到完成、失败或取消为止的总耗时

工具调用可能在任何可见文字前就已经产生有效输出。因此,首个有效输出更适合运维判断,首段可见文本更适合用户体验评估。

Modelflare 用量日志保留请求级时序证据,可以把这些阶段与模型、分组、状态、Token 和费用一起比较。

按阶段设计超时

一个很短的全局超时会让失败原因变得模糊。流式客户端至少要考虑几类时间预算:

  1. **连接超时:**HTTP 连接未能建立。
  2. **响应头或首个输出超时:**请求已经接受,但迟迟没有响应或有效事件。
  3. **空闲超时:**流已经开始,但长时间没有新事件。
  4. **总体期限:**完整操作超过业务允许的最长时间。

重推理或工具驱动的请求,在出现可见文本前可能合理地等待更久。应根据真实工作负载的观测值设置预算;当用户不再需要结果时,再有意取消请求。

正确理解取消与 499 记录

如果客户端、反向代理、浏览器页面或调用方截止时间关闭了下游连接,网关可能把请求记录为客户端取消。请求记录中的 499 表示下游连接在完成前结束;仅凭这个标签不能证明所选模型或渠道发生故障。

排查取消时应比较:

  • 客户端截止时间和 abort signal;
  • 代理缓冲与空闲超时;
  • 首个有效输出之前经过了多久;
  • 客户端是否收到过任何事件;
  • 实际选择的模型和分组;
  • 请求 ID 与取消时间。

排查“流正常但没有可见文本”

按以下顺序检查:

  1. 使用 "stream": false 重复同一请求。
  2. 确认模型支持所选端点。
  3. 在 UI 转换前捕获原始事件。
  4. 检查响应是否只有工具调用或推理事件,而没有文本。
  5. 确认中间层没有缓冲响应体。
  6. 确认解析器能够识别该端点的终止事件。
  7. 在用量日志中核对状态、首个输出、总耗时与取消情况。

如果非流式调用成功,原始流式事件也能到达,问题通常位于客户端解析或渲染,而不是鉴权或模型权限。如果连原始事件都没有到达,请继续阅读AI API 错误指南

生产流式检查清单

  • 明确让解析器匹配 Chat Completions 或 Responses。
  • 关闭 HTTP 客户端和所有可控代理层的缓冲。
  • 测试应用会使用的文本、推理、仅工具和错误事件。
  • 区分首个有效输出与首段可见文本。
  • 使用分阶段超时和明确的取消信号。
  • 除非已经设计好幂等,否则把重试视为一笔新请求。
  • 为排查保留请求 ID、状态、所选模型、分组和时序。
  • 结合Responses API 与 Chat Completions 对比确认端点选择。

常见问题

流式响应会让模型生成得更快吗?

不一定。流式只会更早暴露输出;生成速度和首个事件前的等待时间仍取决于模型、路由、上下文、推理和工具。

为什么 curl 能输出,但应用页面什么都没有?

应用或中间层可能缓冲了响应体,也可能用 Chat Completions 的解析器读取 Responses 事件。更换模型或路由前,先在应用边界捕获原始事件。

流断开后是否应该自动重试?

只有在重复执行安全时才应该重试。流虽然断开,上游可能已经完成部分工作或触发工具操作。对可能产生重复副作用的任务,需要有界重试和应用级幂等设计。