批量脚本跑着跑着,突然满屏 429。把并发改小立刻恢复正常,改大又崩,于是很多人就守在一个拍脑袋定下的数字上,既没吃满带宽,也没用足配额。其实 429 不是「你被封了」的意思,它更像路口的红绿灯——搞懂它在约束什么,才能把速度稳稳推到上限。
先搞清楚 429 到底在拦什么
429 的含义是「请求过多」,但同一个状态码背后至少有三种不同的限法:按时间窗口限制请求数(RPM)、限制每分钟处理的 token 数(TPM),以及限制同时进行中的连接数(并发)。三者里最容易被忽略的是 token 维度——你可能只发了 20 个请求,却因为每个都拖着超长上下文,先把 token 配额撑爆了。
所以第一件事不是降并发,而是看响应头。多数网关会把还剩多少额度、多久之后窗口重置这类信息一并返回。看不懂配额口径就调参数,等于闭着眼睛拧螺丝。
429 是限流,不是封禁。它给你的是节奏信息,不是账号死刑——读响应头比猜并发数有用得多。
并发不是越高越快,先找到那条「甜点线」
很多人把并发当成油门,觉得越大越快。实际曲线是:并发上升,吞吐先涨;过了某个点之后,排队和重试开始互相消耗,吞吐反而掉头向下,而错误率一路上扬。那个拐点就是你这条链路的甜点线。
找它的办法很土但有效:从 1 开始,每次翻倍跑一小批量(比如 50 个请求),记录成功率和总耗时,直到成功率明显下滑,就退回上一档。这个数字会随模型、上下文长度和时段变化,所以它是「你当前配置的」甜点线,不是一条放之四海皆准的真理。
三条实战做法:排队、退避、分流
第一是排队。把任务丢进队列,用固定数量的工作协程匀速取,而不是一次性全部发出。匀速远比突发安全——限流器最怕的就是瞬时洪峰。
第二是退避。收到 429 之后千万不要立刻重试,那只会让窗口更挤。正确做法是等一段时间再发,并且等待时长随连续失败次数递增,同时加一点随机抖动,避免所有任务在同一秒集体苏醒。
第三是分流。如果手里有多把 Key 或多个可用渠道,按权重把请求摊开,单条通道的压力自然下降。反过来,如果只有一把 Key,那就老实做好前两条,别指望靠「多开几个线程」绕过去。
常见问题
一直被 429,是不是 Key 被封了?
基本不是。被封通常表现为 401 或 403,而 429 只说明这个窗口的额度用完了。先看响应头里的重置时间,等窗口过去再发;如果一个完整窗口过去仍然立刻 429,才需要去查配额是不是被别的程序占满了。
退避等待设多长才合适?
起步 1 秒左右,每次翻倍,封顶半分钟到一分钟,再乘一个 0.5~1.5 的随机系数。关键是总时长要有上限,否则一个卡死的任务会带着整批一直睡下去。超过上限就记为失败,让调度器决定什么时候再试。
并发调小了还是很慢,怎么办?
先量再调。统计单个请求的平均耗时,算出「并发数 × 平均耗时」的理论吞吐,再和实测值比。如果差得多,瓶颈通常不在限流,而在上下文太长、模型太重或网络往返太多,换更轻的模型或裁剪提示词比继续调并发划算得多。