# 超时与流式中断

来源: https://platform.lyrouter.com/ai_gateway/docs/stream-errors
更新日期: 2026-10-22

网关等待上游时有 6 分钟的空闲超时。连接上游失败或等待超时，网关会先换下一个通道，全部失败后返回 500 或 504，响应体是 HTML 页面而不是 JSON。流式请求一旦开始输出就不再换通道，中途出错时网关在流末尾补发一个错误事件后结束连接。客户端应把没有收到结束标记的流当作失败处理，并自行决定重试和去重。

## 504 / 500：响应体是 HTML 页面

| 状态码 | 原因 | 日志「状态说明」 |
| --- | --- | --- |
| 504 | 等待上游响应超时，或连接上游超时 | 「网关」+「上游请求超时」 |
| 500 | 连接上游失败（例如连接被拒绝），或读取上游响应时出错 | 「网关」+「连接上游失败，未收到响应」或「上游请求或响应读取失败」 |

- 这两种响应没有 JSON 错误体，返回的是一个 HTML 错误页，部分 SDK 会报「无法解析响应」一类的错误。请按 HTTP 状态码处理，不要依赖 `error.message`。
- 返回之前，网关已经按[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)的规则尝试过其他通道，所有候选都失败后才返回最后一次的结果。
- 「状态说明」的来源显示「网关」，因为是网关终止了这次请求，但原因在网关与上游之间的连接。持续出现时，查看[服务状态](https://platform.lyrouter.com/ai_gateway/docs/status)或换用其他模型。

## 上游超时怎么计算

网关调用上游时的读超时为 360 秒（6 分钟）：

- **非流式请求**：上游 6 分钟内没有返回响应即超时。生成很长的内容时，请改用 `stream: true`。
- **流式请求**：按相邻两段数据之间的间隔计算，只要上游持续有输出就不会超时；开始输出之前同样最多等待 6 分钟。
- **换通道后重新计时**：一个通道超时后，网关改用下一个通道并重新等待，所以一次请求的总耗时可能超过 6 分钟。

## 流式输出开始后出错

流式请求的响应头和第一段内容一旦发出，网关就不能再换通道。此时上游中断或超时，网关在流的末尾补发一个错误事件，然后结束连接：

**Chat Completions**：

```text
data: {"error": {"message": "upstream timed out after the response had started", "type": "api_error", "code": "stream_interrupted"}}
```

**Anthropic Messages**（`/v1/messages`）：

```text
event: error
data: {"type": "error", "error": {"type": "api_error", "message": "upstream timed out after the response had started"}}
```

**Responses**（`/v1/responses`）：补一个 `response.failed` 事件，`response.error.code` 为 `server_error`。

```text
event: response.failed
data: {"type": "response.failed", "sequence_number": 42, "response": {"id": "resp_...", "object": "response", "status": "failed", "error": {"code": "server_error", "message": "upstream timed out after the response had started"}}}
```

- 超时时 `message` 为 `upstream timed out after the response had started`；连接或读取失败时为 `upstream failed after the response had started`。
- 上游服务商自己在流中发出的错误事件（例如 Anthropic 的 `overloaded_error`）会按你调用的协议转给你。
- OpenAI 和 Anthropic 的官方 SDK 收到对应格式的错误事件会抛出 API 错误。
- 在日志中，这类请求的「状态」是 200（响应头已经发出），「状态说明」显示「网关」+「上游请求超时」或「上游请求或响应读取失败」。

## 没有结束标记就当作失败

出现错误事件后，流中不会再有结束标记。请以协议规定的结束标记判断输出是否完整，没有收到就把这次调用视为失败：

| 接口 | 正常结束的标记 |
| --- | --- |
| Chat Completions | `data: [DONE]` |
| Anthropic Messages | `message_stop` 事件 |
| Responses | `response.completed` 事件 |

上游直接断开连接、没有发出任何错误事件时，流也会在没有结束标记的情况下结束，同样按失败处理。各协议的事件结构见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming)。

## 客户端与代理设置

- **客户端超时**：设得比 6 分钟长，避免客户端先断开；流式请求优先设置读取间隔超时，而不是整次请求的总超时。
- **按完整事件解析**：SSE 事件以空行分隔，一个网络数据块可能只包含半个事件，也可能包含多个事件，不要把每个数据块当作一段完整 JSON。
- **自建代理**：如果应用和 LYRouter 之间还有 Nginx 等反向代理，请关闭响应缓冲（Nginx 中设置 `proxy_buffering off`），并把代理的读超时设得比 6 分钟长，否则流式内容会被攒成一大块才到达，或被代理提前断开。

## 重试与去重

- **流式中断**：收到 `stream_interrupted`、`response.failed`，或没有收到结束标记时，不要把已经收到的部分输出当作完整结果。重新调用会重新生成，内容可能不同，也可能再次触发工具调用；已经执行过的工具操作需要由应用去重，例如为每个操作携带业务上的幂等标识。
- **504 / 500**：网关已经在内部换过通道，客户端使用有上限的指数退避重试即可，不要无间隔地连续重试。
- **持续失败**：同一个 API Key 在 60 秒内大量请求失败会被临时熔断，返回 429 `api_key_circuit_open`，见[429：限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。

## 用日志定位

在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中找到这次请求，打开详情：

- **各阶段耗时**：「④ 上游调用」占「总耗时」的大部分，说明时间花在上游；旁边显示「· N 次尝试，最长 X」时，说明换过通道，每次尝试都可能等待了接近 6 分钟。
- **首 Token**：日志列表的「首 Token」列（在 **自定义列** 中打开）显示上游开始输出前等待了多久。
- **路由追踪**：「上游调用尝试」中每次尝试的状态显示「超时」「连接失败」等，见[查看实际路由](https://platform.lyrouter.com/ai_gateway/docs/route-log)。

（截图：在日志详情的各阶段耗时中比较总耗时、上游耗时和首 Token 时间。）

## 常见问题

### 客户端报超时，日志里这次请求却是 200？

**答：** 通常是客户端或中间的代理先断开了连接，网关仍然完成了这次调用。用日志的「总延迟」和客户端的超时设置比较；日志的「时间」是请求结束的时间，减去「总延迟」就是请求到达网关的时间。把客户端超时调到 6 分钟以上，或改用流式请求。

### 流式响应很久没有第一段内容？

**答：** 先看日志的「首 Token」。首 Token 很长说明上游迟迟没有开始输出，可以稍后重试或换用其他模型；首 Token 正常但客户端迟迟收不到内容，检查中间代理是否缓冲了响应。

### 流式响应解析 JSON 失败，应该检查什么？

**答：** 确认解析器按完整 SSE 事件读取，并能处理 `data: [DONE]` 这类不是 JSON 的行。如果请求在输出开始前就失败，返回的是普通的错误响应而不是事件流：网关拒绝的请求通常是 JSON 错误体，500、504 是 HTML 页面，请先检查状态码和 `Content-Type`。

### 提交超时问题时需要提供哪些信息？

**答：** 网关的响应中不包含请求 ID。请在日志中找到这次请求，附上日志详情顶部的 Request ID、调用时间、模型、是否流式、客户端的超时设置，以及客户端收到的报错原文或最后收到的几个事件。
