机场实测室JICHANGTUIJIAN.MOM
搜索线路 / 教程/
流媒体与 AI

OpenAI API 连接超时:长连接、流式输出与节点的三角关系

一句话结论

普通聊天是短请求,断一次几乎无感;API 的流式输出和 Codex 的长任务是持续数分钟的单条连接,中途任何一次链路抖动、空闲超时或中转切换都会直接中断。所以问题往往不在「能不能访问」,而在链路的连续性:跳数越多、空闲回收越激进的线路,越容易在长任务上翻车。

同一个订阅,浏览器里聊一下午没出过问题,换到终端上调 API,跑到第三分钟抛出连接重置;agent 类工具跑一个稍长的任务,输出到一半突然截断,重来一次又断在另一个位置。这种「每次断的地方都不一样」的特征,基本可以排除地区判定和账号资格——那两类问题的表现是稳定复现的拒绝,而不是断在半路。

真正的变量是时间。网页版的一次问答是几秒钟的短请求,链路即使抖了一下,前端悄悄重试一次,你根本不知道发生过。而流式输出和长任务是一条持续几分钟甚至更久的连接,链路上任何一个环节在这段时间里做了一次会话回收、节点切换或者重传失败,整条连接就没了,也没有谁替你重试。

所以这类问题的排查方向不是「这个节点能不能访问」,而是「这条链路能让一条连接活多久」。下面按数据包从客户端到落地经过的顺序,把可能掐断它的环节逐个点名。

为什么网页版好好的,API 一跑长任务就断

三种用法对链路施加的压力,完全不在一个量级。

使用方式单条连接持续时间中途断开时的表现是否有自动重试
网页版对话数秒到数十秒页面转圈后自动恢复前端通常会重试
API 流式输出数十秒到数分钟输出截断、抛出连接错误默认没有,要自己写
命令行 agent/长任务数分钟到数十分钟任务半途终止,上下文丢失部分工具会重来一整轮

同一条链路,故障率不变,暴露概率却随连接时长线性上升。一条平均每十分钟抖动一次的线路,对网页版意味着「偶尔卡一下」,对二十分钟的长任务意味着「几乎必然失败」。

判断依据:如果多个不同地区的节点都在同一个位置报同样的错,先怀疑账号或平台侧;如果断点每次都不同、且重试有时能成功,那就是链路连续性问题,属于本文讨论的范围。

流式输出到底对链路提了什么额外要求

流式输出用的是 SSE(服务端推送事件,服务器在一条不关闭的 HTTP 连接上持续往下写数据)。它的流量特征很特别:总量不大,但持续时间长、包很小、间隔不规则。

这带来三个普通网页浏览提不出来的要求。

要求破坏它的链路现象你看到的症状
连接从头到尾不能重建节点自动切换、会话表被清空输出到一半直接断,错误提示是连接被重置
包序完整且能持续送达中间某段丢包严重、重传超时输出突然卡住十几秒,然后报错
大包不能被静默丢弃路径 MTU 黑洞(超过某个尺寸的包被丢且不返回通知)握手成功、短请求正常,一发长内容就卡死

第三条最容易被误判成「节点慢」。MTU(一个数据包在这条路径上允许的最大尺寸)如果被中间某一跳压低,而沿途设备又不回送提示报文,超尺寸的包就会消失得无声无息。表现是能连上、能发短消息,一旦请求体变大或返回内容变长就永久挂起。

空闲超时与连接回收:谁在中途把连接掐了

一条连接从你的设备到落地,途中会被好几个组件登记为「会话」,每个组件都有自己的回收计时器。任何一个先到期,连接就结束了。

环节常见空闲回收区间(参考值)触发条件
本机代理客户端数分钟量级无数据传输且未开 keepalive
家用路由器/运营商 NATTCP 较宽松,UDP 明显更短会话表项长时间无包
机场入口机与中转节点按各家配置差异很大连接闲置、或节点重启维护
平台侧网关有上限,长任务需分段单连接超过服务端允许时长

上表的区间只是行业常见量级,不同设备、不同运营商差别很大,请当成排查思路而不是精确数字。

关键在于「空闲」的定义:这些组件多数只看有没有数据包经过,不理解应用层语义。推理模型在长时间思考、agent 在本地执行工具调用时,连接上确实一个字节都不走,在计时器眼里和已经废弃的连接没有区别。开启 TCP keepalive,让连接周期性发出探测包,正是为了避免这种误判。

中转跳数、负载均衡和长连接为什么天然冲突

每多一跳,就多一张会话表、多一个可能重启的进程、多一个独立的超时计时器。对短请求来说这些几乎不可见;对长连接来说,它们是串联关系——任意一环出事,整条连接就断。

线路结构对长任务的主要风险
直连落地环节最少,但跨境段拥堵时丢包直接命中长连接
单跳中转增加一个会话表与一次转发进程重启的可能
多跳/动态优选中转后端出口可能在任务中途更换,连接必然重建
客户端负载均衡组定时测速触发切换,正在跑的连接被一并丢弃

最容易被忽略的是最后一行。很多人把 AI 相关规则指向一个 url-testfallback 策略组,图的是自动挑最快节点,结果这个组每隔一段时间就重新评估一次,切换发生的瞬间,正在跑的长任务一起陪葬。想理解跳数与出口结构的差别,可以先看中转与直连的路段拆解

顺带说一句,出口在任务中途更换,除了断连还会引出另一个问题:平台看到同一会话里出口 IP 变了,可能触发风控。那属于出口 IP 漂移引发的验证码与登出,和本文的传输层断开是两种失败。

协议选择会影响长连接的存活时间吗

会,但方向不像很多人想的那样单一。

协议族对长连接的优势需要留意的风险
TCP 系(Trojan、VLESS 等)行为可预期,NAT 对 TCP 会话通常更宽容高丢包链路上重传堆积,卡顿明显
QUIC/UDP 系(Hysteria2、TUIC)丢包环境恢复更快,部分实现支持连接迁移本地对 UDP 限速或阻断时,长时间传输更容易被压制

结论是:在丢包率高但 UDP 通畅的网络里,UDP 系协议对长任务更友好;在校园网、公司网这类对 UDP 做 QoS 的环境里,反而是老实的 TCP 系更能撑。两者的设计差异见Hysteria2 与 TUIC 的拥塞控制对比,而怀疑本地 UDP 被限速时,按UDP 被限速的判断与回退流程先做验证再换协议。

客户端侧可以先调的四个参数

在换机场之前,这四项调整成本最低,且经常能直接解决问题。

  1. 把 AI 相关规则从自动优选组改为固定节点。 目的是消除任务中途的节点切换,这是长任务最常见的单点故障。稳定优先于最快。
  2. 开启 TCP keepalive 并把间隔设得比链路上最短的回收计时器更小。 目的是让空闲期间也有包在走,避免被 NAT 或中转当成废弃会话清掉。
  3. 适当下调 MTU。 目的是绕开路径上的 MTU 黑洞。判断方法是:短请求正常、长响应必挂,调低后症状消失,基本可以确认。
  4. 在调用侧加上超时与断点续传逻辑。 目的是承认链路总会抖,把「断一次就全废」变成「断一次重连一段」。这是唯一不依赖机场质量的那一项。

下面是一段结构示例,展示前两项在配置里的位置,主机名一律用占位域名,不能直接使用:

# 结构示例,非可用配置;example.invalid 为占位域名
proxies:
  - name: 'ai-fixed'
    type: trojan
    server: node.example.invalid
    port: 443
    tcp-keep-alive-interval: 30 # 空闲期也保持有包在走
    mtu: 1380 # 怀疑 MTU 黑洞时下调试试

rules:
  - DOMAIN-SUFFIX,api.example.invalid,ai-fixed # 固定出口,不进优选组

参数名与可用字段随客户端版本变化很大,上面只演示「该在哪一层动手」。实际写法请以你所用客户端的当前文档为准,改完务必备份原配置。

怎么用一次可复现的长任务测试对比两条线路

要比较两条线路谁更适合长任务,测速跑分没有意义——它测的是短时间峰值带宽,恰好回避了连续性这个唯一重要的变量。用下面这个流程,半小时就能得出可比结论。

  1. 固定除线路以外的所有条件。 同一台设备、同一个时间段(建议放在晚间高峰)、同一个请求内容、同一个客户端版本。变量只留线路一个。
  2. 发起一次持续足够久的流式请求,并给每一行输出打上时间戳。 目的是把「断在第几秒」记录下来,而不是只知道「失败了」。
  3. 同一条线路连测三轮。 单次结果没有意义,长连接问题的典型特征就是概率性发生。
  4. 换到第二条线路,重复第二、三步。
  5. 对照三项指标下结论: 完成率(三轮中跑完几轮)、平均断点位置、断开时的错误类型。
# 结构示例:给流式输出的每一行打时间戳,端点用占位域名
curl -N -sS https://api.example.invalid/v1/stream \
  -H "Authorization: Bearer <你的密钥>" \
  -d '{"stream": true, "prompt": "输出一段足够长的内容"}' \
  | while IFS= read -r line; do
      printf '%s %s\n' "$(date +%H:%M:%S)" "$line"
    done

记录成这样一张表,两条线路的差别通常一眼就能看出来:

线路三轮完成情况平均断点报错类型
A3/3
B1/3约第 2 分钟连接被重置

单次成功不代表线路可用,单次失败也不代表线路不行。平台侧同样会限流和抖动,所以任何结论都要基于多轮记录,并注明测试时间与网络环境——不写条件的测试结果没法复核,第二天复现不出来也说不清是哪里变了。

小结

网页版正常而 API 频繁断开,症结在连接的持续时间,不在地区判定。链路上的会话回收计时器、中转跳数、优选组的自动切换和路径 MTU,共同决定了一条连接的存活上限。先在客户端侧固定节点、打开 keepalive、下调 MTU、给调用加上重连,再谈换线路。判断线路优劣时,用带时间戳的多轮长任务记录,不要用测速软件的峰值数字。把这一项和其他节点要求放在一起权衡,可以接着看AI 场景的节点选型清单

常见问题

网页版 ChatGPT 一直很稳,为什么同一个节点跑 API 就断?

网页版的一次问答是几秒钟的短请求,而且前端会自动重试,链路抖动你感知不到。API 的流式输出是一条持续数分钟的单条连接,中途任何一次回收、切换或重传失败都会直接终止,并且没有默认重试。

报错里出现 connection reset 和 incomplete chunked read,说明是哪一侧的问题?

这两类报错的共同点是连接在传输中途被断开,而不是握手被拒绝。握手层面的失败通常表现为 403、地区不支持或证书错误。中途断开更多指向链路上的会话回收、节点切换或 MTU 问题。

推理模型思考很久没输出,会不会被当成空闲连接回收掉?

有可能。部分链路环节按「一段时间没有数据包」来判断会话是否失效,而长时间思考期间确实没有应用层数据。开启 TCP keepalive 让连接周期性发出探测包,可以降低被中途回收的概率。

换成 Hysteria2 这类协议能让长任务更稳吗?

不一定。它在高丢包链路上的恢复能力更强,但如果本地网络对 UDP 做限速或阻断,持续数分钟的大流量传输反而更容易被压制。协议要按你所在网络的实际表现选,不能只看理论。