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
结论:如果只能记住一件事,记出口 IP 的稳定性。它决定了鉴权、风控和排错能不能收敛,而速度可以在稳定之后再优化。

并发连接与线路类型的匹配

并发上限由四段共同决定:本地连接池、代理客户端的多路复用设置、线路带宽与出口 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 会变,域名不会。

检查顺序

  1. 在代理开启的状态下解析目标域名,记录结果。
  2. 关闭代理再解析一次,对比两次结果是否落在同一区域。
  3. 用回显地址确认最终出口 IP,而不是只看解析结果。
  4. 如果解析结果和出口地区不一致,检查客户端的 DNS 设置与分流规则优先级。

选线路时的自查清单

把上面几节压缩成一份清单,选线路时逐条对照,比看参数表有用。下面四个数字是订阅侧能直接确认的条件,不是测速结果。

  • 120+ 国家与地区可选出口
  • 150+ 线路,可按域名分流
  • 不限 设备台数,瓶颈在出口侧
  • 7 天 无理由退款,够跑一轮观察
  • ✅ 出口 IP 是否固定,断开重连后是否保持不变。
  • ✅ 能否指定出口地区,是否有多条线路可切换。
  • ✅ 是否支持长连接与流式响应,客户端会不会做缓冲。
  • ✅ 单账号并发是否受限,限制在本地还是出口侧。
  • ✅ 是否支持按域名分流,规则能不能单独调整。
  • ✅ 计费方式是否匹配调用量:月付按开通日重置,流量包用完为止、不过期。
  • ❌ 只看标称带宽,不看出口稳定性。
  • ❌ 把调试、生产、批量任务放在同一个出口上。
  • ❌ 用单次请求的结果判断一条线路的好坏。

排错步骤:从出口 IP 到并发

出问题时不要从改参数开始,按下面的顺序走,每一步都有明确的判断依据。

  1. 确认代理是否生效。请求回显地址,看出口 IP 是否为目标地区。IP 没变,后面都不用查。
  2. 确认 DNS。对比代理内外的解析结果,判断是否发生泄漏。
  3. 确认系统时间。VMess 等协议依赖时间校验,偏差过大会握手失败。
  4. 确认 TLS。证书错误、SNI 不匹配、中间设备拦截,表现都是连接被重置。
  5. 确认流式输出。看首字节时间与逐行到达情况,判断是否被缓冲。
  6. 确认并发。从低并发逐步加压,记录错误类型分布,而不是只看平均值。
  7. 确认线路切换。换一条线路复现:能复现说明是客户端或代码问题,不能复现说明是线路问题。
顺序很重要:出口 IP 决定请求能不能被正确识别,DNS 决定请求打到哪个区域,超时与重试决定失败之后会不会放大。按这个顺序排查,比反复换线路省时间。

一周观察记录与结论

单次请求的结果说明不了什么。跨境线路的表现按时段波动,工作日白天、晚高峰、凌晨是三种状态。建议用一周时间记录同一组请求,每次记录五个字段:

  • 时间与线路名称
  • 出口 IP
  • 首字节时间
  • HTTP 状态码或错误类型
  • 是否触发重试

一周之后看的是分布,不是平均值:错误集中在哪个时段、哪条线路、哪类错误。如果 429 集中在晚高峰,说明出口被共用;如果连接超时集中在某条线路,说明那条线路的入口拥塞;如果 TLS 错误零散出现,优先查客户端与中间设备。

结论:AI API 调用的线路选择,顺序是固定出口优先、线路类型其次、超时与重试最后。出口稳定之后,并发和超时才有调优的意义;出口不稳定,调什么参数都只是把失败推迟。