本地跑得好好的脚本,一上批量任务就开始满屏「并发限制 请稍后再试」,重试几次能过、重试多了又全挂——这种报错最烦人的地方在于它不告诉你到底是账号档位不够、中转站池子太小,还是你自己把并发开太大。这篇不解释并发概念,只给一套排查顺序和改造清单:先确认是谁在限制你,再决定是排队、分批还是降级。
本地跑得好好的脚本,一上批量任务就开始满屏「并发限制 请稍后再试」,重试几次能过、重试多了又全挂。这种报错最烦人的地方在于它不告诉你到底是账号档位不够、中转站池子太小,还是你自己把并发开太大。
这篇不解释并发概念,只给一套排查顺序和改造清单:先确认是谁在限制你,再决定是排队、分批还是降级。照着往下走,基本能把「到底是哪一层卡住」这件事拆清楚。
先分清是谁在限制你
同一个报错文案,可能来自三个完全不同的地方:官方账号的档位限制、中转站自有通道池的容量、或者你自己网关和客户端的连接池。三者的处理方式差别很大,前者要么等要么升级,中者换站或换时段,后者改代码就行。所以第一步不是调参数,而是先定位层级。
- 同一把 Key 用浏览器或 curl 单发一次请求,看能不能过——单发也报错,说明限制不在你的并发上
- 换一个模型名再试,如果换个模型就好了,问题多半在特定通道或特定模型上
- 换一个中转站再试,如果换了就通,说明是原来那家通道池太小或临时拥挤
- 三次对照都通不过,再回头怀疑自己的并发设置和客户端连接数
从报错本身挖出可用的线索
很多人只看状态码就丢掉响应体,其实中转站经常在 body 里塞了渠道名、剩余额度、建议等待秒数这类信息。把这些字段记进日志,后面复盘时才有依据判断是集中在某段时间还是某个模型。
- Retry-After
- 响应头里如果带这个,优先按它给的节奏等待,比自己拍一个固定间隔更稳
- 请求时间与耗时
- 记录发起时刻和结束时刻,用来判断是不是集中在某个高峰时段
- 模型名与是否流式
- 把这两项和报错一起记,方便对比是不是只有某类请求出问题
- 原始响应体
- 完整落盘而不是只留状态码,很多线索只在这里出现
日志字段不用多,这四项加上渠道标识就够了。写太多反而没人看,关键是出事时能一眼看出「什么时候、对谁、发了什么请求」。具体各家接口的字段口径,可以到 /models 的模型资料页核对当时的说明。
把「并发」换成排队和分批
最直接的错误做法是把重试次数调大硬扛,那样只会让同一时间飞出去的请求更多。正确方向是把无节制的并发改成固定线程数的队列,让同时进行的请求数可控,失败项单独收集、统一重投。
| 场景 | 推荐做法 | 判断标准 |
|---|---|---|
| 请求量小、能容忍串行 | 串行发送加短间隔 | 单次任务总耗时可以接受就行 |
| 请求量大、延迟不敏感 | 生产者-消费者队列加固定 worker 数 | 队列不积压太多、失败率稳定 |
| 交互式低延迟场景 | 少量并发加降级通道 | 用户等待时间在可接受范围内 |
- 把并发数固定下来把散落的线程或协程数量改成统一配置项,先降到当前的一半跑一轮
- 加一层任务队列让提交请求和发送请求解耦,队列长度可观测,积压时能及时发现
- 失败项单独收集失败的请求不要立刻原地重试,先攒起来,本轮跑完再统一重投
退避与降级怎么配
指数退避如果不加随机抖动,多个 worker 会在几乎同一时刻一起重试,等于自己制造了第二波冲击。抖动的作用是把重试时间打散,让恢复过程平滑一些。
- 退避时加入随机量,避免所有 worker 同步重试
- 连续失败达到设定阈值后,切换到备用模型或备用通道
- 给整个任务设总时长上限和最大重试次数,超过就整体中止
- 中止时输出一份失败清单,而不是无声退出
改完怎么确认真的生效
改完之后别急着全量放开,先用小批量验证。把并发数减半跑一轮,看报错是否消失,再逐步加回去,找到当前档位下的舒适线。需要注意的是,这条线不是固定的,账号档位和通道容量都会变。
- 关注重试成功率而不是只看有没有报错,成功率高但慢说明排队策略合格
- 成功率低说明限制不在你这一侧,该考虑换通道或换时段
- 定期到 /price-watch 核对当时的限额与价格口径,别让代码里写死的假设过期
- 把每次调整前后的参数记下来,方便下次出事时快速回滚
还有一点常被忽略:不同中转站的限额口径不完全一样,有的按分钟、有的按同时在途请求数。拿不准的时候,可以到 /tools/speed-test 做一轮基础连通和响应测试,先建立自己的基线数据。
下一步想看你常用的那家通道当前是什么水平、别人踩过哪些坑,可以去站点目录挨个翻一遍实测记录,比在群里问「这家行不行」靠谱得多。→常见问题
同一把 Key,为什么网页端好用、脚本一跑就报并发限制?
网页端通常是单发、间隔大,等于天然串行。脚本容易并行发出多个请求,或者循环里没等上一个返回就发下一个。先把脚本改成串行跑一轮,如果串行能过,问题基本在自己这侧的开度,而不是账号被限死。
重试次数调大是不是就能解决?
不能。重试只对偶发失败有用,如果触发的是硬性并发上限,请求越多排队越久,重试还会放大压力。正确顺序是先降并发、加队列和间隔,再考虑有限次数的退避重试,并且要设总时长上限。
怎么快速判断是账号档位问题还是中转站问题?
同一把 Key 换一个模型名试、再换一个中转站的 Key 试,两个维度交叉对照。只有某个模型报错,多半是通道侧;所有模型都报错,看是不是账号档位或本地网络出口的问题。