请求超时网络 / 代理 / 长上下文
timeout:API 请求超时、504 或连接中断怎么解决
timeout 可能来自网络、代理、DNS、服务端处理太慢、上下文过长或你的运行环境超时限制。先定位是连接超时还是读取超时。
排查结论
先用最小请求隔离问题:只保留 API Key、Base URL、模型名和一条 ping 消息。最小请求失败,先修配置;最小请求成功,再回到业务代码排查并发、上下文和部署环境。
1. 问题现象
- SDK 报 timeout、ETIMEDOUT、ECONNRESET、AbortError、Read timed out 或 504 Gateway Timeout。
- 短 prompt 正常,长文档、图片、多轮上下文或推理模型请求容易超时。
- 本地运行成功,部署到 Vercel、Cloudflare Workers、Serverless 后超时。
- 非流式等待很久无响应,开启 stream 后能看到持续输出。
2. 最可能原因
请求体过大,模型推理时间超过客户端、代理或 Serverless 超时时间。
海外 API 网络链路不稳定,代理节点、DNS 或 TLS 握手失败。
没有开启流式输出,长回答必须等完整生成后才返回。
max_tokens 设置过大,模型尝试生成很长内容。
服务端没有设置合理 timeout 和重试,连接池复用异常。
3. 快速排查清单
1
区分连接超时和读取超时
连接超时多看网络、DNS、代理;读取超时多看 prompt 长度、模型速度和输出长度。
2
用最小请求测试链路
只发 ping 级别 prompt,如果也超时,先修网络或 Base URL。
3
开启 stream
长输出、推理模型和聊天产品建议用流式输出,避免网关长时间无数据返回。
4
缩短上下文
把长文档分块、摘要历史消息、降低 max_tokens。
5
检查部署平台限制
Serverless 常有 10 到 60 秒限制,长任务应改为后台队列或长连接流式接口。
4. 对应 API 的特殊情况
OpenAI / Claude / Gemini
海外链路受网络环境影响明显。国内服务器直连失败时,要使用合规稳定的网络出口或国内可用平台。
Claude
长上下文能力强,但长上下文也意味着更长处理时间;大文档任务优先 stream。
DeepSeek / Kimi
长文本、推理模型或高峰时段可能更慢。先用短 prompt 验证 Key 和 Base URL,再调大上下文。
本地部署模型
timeout 也可能是本机显存不足或模型加载太慢,不要只排查网络。
5. 可复制的修复示例
Python OpenAI SDK 设置 timeout 和有限重试
python
from openai import OpenAI
import os
client = OpenAI(
api_key=os.environ["API_KEY"],
base_url=os.environ["BASE_URL"],
timeout=60.0,
max_retries=2,
)
response = client.chat.completions.create(
model=os.environ["MODEL_ID"],
messages=[{"role": "user", "content": "用三句话总结这段内容"}],
max_tokens=300,
)
print(response.choices[0].message.content)同时控制 timeout、重试次数和输出长度,避免无限等待。
fetch 使用 AbortController 控制超时
typescript
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 60000);
try {
const response = await fetch(process.env.BASE_URL + "/chat/completions", {
method: "POST",
signal: controller.signal,
headers: {
"Authorization": "Bearer " + process.env.API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: process.env.MODEL_ID,
messages: [{ role: "user", content: "ping" }],
max_tokens: 50,
}),
});
console.log(await response.text());
} finally {
clearTimeout(timer);
}超时要显式失败并记录日志,不要让请求永久挂住。