AI API 调用线路推荐的核心不是「哪条线路最快」,而是「哪条线路能让请求稳定地落在同一个出口上」。网页端断一次刷新即可,脚本里一次超时可能让整批任务重跑,还会带来重复计费。下面把固定出口、并发连接、超时重试三件事拆开讲,最后给一份可以直接照着做的排错步骤。
AI API 调用与网页端的差别
同一个订阅,浏览器里能打开的服务,脚本里未必跑得通。差别不在带宽,而在请求形态和失败代价。
- 连接时长不同。网页端一次页面加载由几十个短请求组成,单个请求很快就结束;API 的流式响应会让一条连接持续几十秒甚至几分钟,中途任何一次抖动都直接体现在输出上。
- 失败代价不同。网页端失败重试一次;批量任务失败要重跑,消耗的是配额和费用,还可能因为重复提交产生重复结果。
- 出口敏感度不同。不少 API 服务按「账号 + 出口 IP」做风控。出口在同一天里反复变化,容易触发二次验证、临时限流,严重的会直接拒绝。
- 并发模型不同。浏览器最多几个标签页;脚本可以同时开几十个连接,压力落在客户端连接池和出口的 NAT 会话表上。
把这四点放在一起看,选线路的顺序就清楚了:先保证出口稳定,再谈线路类型,最后才是调超时参数。
固定出口:为什么比最快更重要
固定出口指的是同一个账号的请求,长期从同一个或同一小组出口 IP 出去。它解决的是「服务端认不认得你」的问题,而不是「跑得快不快」的问题。
出口漂移会带来什么
- 会话与令牌绑定 IP 时,重连换 IP 会让已有会话失效,需要重新鉴权。
- 配置了 IP 白名单的接口,出口一变就直接返回 403。
- 风控系统看到同一账号短时间内从多个地区登录,会提高验证等级。
- 排查问题时,日志里的出口 IP 每次都不一样,很难判断是线路问题还是代码问题。
共享出口不等于线路差
很多人把「晚高峰变慢」归因于线路质量,实际原因常常是出口被共用:同一个出口 IP 上有很多用户,目标服务看到的是这个 IP 的高频请求,于是触发限流。判断方法是看错误类型——如果是 429 或连接被重置,而带宽测试正常,基本就是出口侧的问题。
怎么验证出口是否固定
准备一个能返回请求来源 IP 的回显地址,在代理开启的状态下连续请求,记录每次结果;断开重连后再测一轮;隔几个小时再测一次。三轮结果一致,才算固定。
export ECHO_URL="你的回显地址"
# 连续请求,观察出口 IP 是否漂移
for i in 1 2 3 4 5; do
curl -s --max-time 10 "$ECHO_URL"
printf '\n'
sleep 2
done
并发连接与线路类型的匹配
并发上限由四段共同决定:本地连接池、代理客户端的多路复用设置、线路带宽与出口 NAT 会话表、目标服务的账号级限流。任何一段打满,表现都是超时或连接被拒,只看其中一段会误判。
三种线路类型的差别
| 线路类型 | 路径特征 | 出口表现 | 适合的调用形态 | 需要注意 |
|---|---|---|---|---|
| IEPL 专线 | 走运营商专线出境,不经过公共互联网国际出口 | 出口相对固定,抖动小 | 长连接、流式响应、批量任务 | 成本较高,可选地区比直连少 |
| 中转 | 先连就近中转节点,再由中转节点出境 | 出口由落地节点决定 | 日常调用、对成本敏感的场景 | 多一跳,中转节点拥塞时整体变慢 |
| 直连 | 本地直接连境外节点 | 出口随节点变化 | 轻量请求、临时调试 | 国际出口拥塞时波动明显 |
选哪种取决于调用形态,不是取决于价格。流式响应和批量任务优先专线,临时调试用直连就够,中转适合把两者分开:调试走一条,生产走另一条。
协议层要看的两点
Shadowsocks、VMess、Trojan、VLESS 走 TCP,Hysteria2、TUIC 基于 QUIC 走 UDP。对 API 调用来说,协议选择影响的是两件事:
- 时间校验。VMess 依赖客户端与服务端的时间一致性,系统时间偏差过大会直接握手失败。这类失败看起来像线路不通,实际同步一次时间就好。
- UDP 可用性。Hysteria2 和 TUIC 在丢包链路上表现更稳,但依赖网络不限制 UDP。部分办公网与公共网络会限制 UDP,这时只能回退到 TCP 类协议。
超时与重试:客户端侧的最小配置
超时不是设一个总数就完事。一次请求要分成四段看:连接建立、TLS 握手、首字节返回,以及流式输出过程中的空闲间隔。四段混在一起设,排错时无法定位是哪一段出的问题。
- 连接超时设短一些,连不上就换线路,不要挂着等。
- 首字节超时覆盖 TLS 与请求发出到第一个字节返回,可以比连接超时宽松。
- 空闲读取超时针对流式响应,只计算两段输出之间的间隔,不计算总时长。
- 总时长对流式请求不要设,否则长回答会被自己的客户端掐断。
重试要满足三个条件:请求可重试、错误可重试、次数有上限。连接失败、读取超时、429 和 5xx 可以重试;400、401、403 这类参数或鉴权错误重试多少次都一样,只会放大问题。
import random
import time
import httpx
API_URL = "https://api.example.com/v1/chat"
# 四段超时分开设:连接 5s,空闲读取 60s
timeout = httpx.Timeout(connect=5.0, read=60.0, write=10.0, pool=5.0)
# 连接池上限决定本地并发上限
limits = httpx.Limits(max_connections=16, max_keepalive_connections=8)
with httpx.Client(timeout=timeout, limits=limits) as client:
for attempt in range(4):
try:
with client.stream("POST", API_URL, json={"stream": True}) as resp:
if resp.status_code in (429, 500, 502, 503, 504):
raise httpx.HTTPStatusError(
"retryable", request=resp.request, response=resp
)
resp.raise_for_status()
for line in resp.iter_lines():
handle(line) # 逐行处理,不要先攒进列表
break
except (httpx.ConnectError, httpx.ReadTimeout, httpx.HTTPStatusError):
if attempt == 3:
raise
# 指数退避加抖动,避免多个任务同时重试
time.sleep(min(2 ** attempt, 8) + random.uniform(0, 0.5))
DNS 与分流规则怎么配合
DNS 泄漏指的是域名交给本地 DNS 解析,拿到的是「离你最近」的节点,而不是「离出口最近」的节点。对多数 API 来说,服务端用统一入口,影响有限;但对按区域返回不同结果的服务,解析结果会直接决定请求打到哪个区域,鉴权也可能跟着失败。
分流比全局更省事
把 API 域名固定走一条线路组,其余流量走默认组,好处有三点:出口稳定、调试时能单独切换、一条线路出问题不影响其他任务。规则按域名后缀写比按 IP 写更稳,因为 API 的入口 IP 会变,域名不会。
检查顺序
- 在代理开启的状态下解析目标域名,记录结果。
- 关闭代理再解析一次,对比两次结果是否落在同一区域。
- 用回显地址确认最终出口 IP,而不是只看解析结果。
- 如果解析结果和出口地区不一致,检查客户端的 DNS 设置与分流规则优先级。
选线路时的自查清单
把上面几节压缩成一份清单,选线路时逐条对照,比看参数表有用。下面四个数字是订阅侧能直接确认的条件,不是测速结果。
- 120+ 国家与地区可选出口
- 150+ 线路,可按域名分流
- 不限 设备台数,瓶颈在出口侧
- 7 天 无理由退款,够跑一轮观察
- ✅ 出口 IP 是否固定,断开重连后是否保持不变。
- ✅ 能否指定出口地区,是否有多条线路可切换。
- ✅ 是否支持长连接与流式响应,客户端会不会做缓冲。
- ✅ 单账号并发是否受限,限制在本地还是出口侧。
- ✅ 是否支持按域名分流,规则能不能单独调整。
- ✅ 计费方式是否匹配调用量:月付按开通日重置,流量包用完为止、不过期。
- ❌ 只看标称带宽,不看出口稳定性。
- ❌ 把调试、生产、批量任务放在同一个出口上。
- ❌ 用单次请求的结果判断一条线路的好坏。
排错步骤:从出口 IP 到并发
出问题时不要从改参数开始,按下面的顺序走,每一步都有明确的判断依据。
- 确认代理是否生效。请求回显地址,看出口 IP 是否为目标地区。IP 没变,后面都不用查。
- 确认 DNS。对比代理内外的解析结果,判断是否发生泄漏。
- 确认系统时间。VMess 等协议依赖时间校验,偏差过大会握手失败。
- 确认 TLS。证书错误、SNI 不匹配、中间设备拦截,表现都是连接被重置。
- 确认流式输出。看首字节时间与逐行到达情况,判断是否被缓冲。
- 确认并发。从低并发逐步加压,记录错误类型分布,而不是只看平均值。
- 确认线路切换。换一条线路复现:能复现说明是客户端或代码问题,不能复现说明是线路问题。
一周观察记录与结论
单次请求的结果说明不了什么。跨境线路的表现按时段波动,工作日白天、晚高峰、凌晨是三种状态。建议用一周时间记录同一组请求,每次记录五个字段:
- 时间与线路名称
- 出口 IP
- 首字节时间
- HTTP 状态码或错误类型
- 是否触发重试
一周之后看的是分布,不是平均值:错误集中在哪个时段、哪条线路、哪类错误。如果 429 集中在晚高峰,说明出口被共用;如果连接超时集中在某条线路,说明那条线路的入口拥塞;如果 TLS 错误零散出现,优先查客户端与中间设备。