大模型推理一次只算一条请求太浪费,把多条请求凑成一批一起算才划算,但批越大、单个请求等得越久,批大小和延迟的取舍由此而来。这道平衡题没有标准答案,只有按场景调的松紧。理解这道题,就理解了大模型服务高峰期的一半现象。
批是怎么攒起来的
服务端通常设一个攒批窗口:第一批请求到达后稍等几毫秒,看还有没有同伴,窗口一到或数量够就把整批送进计算。进来的是零散请求,发生的是凑批与齐队,出去的是一批同行的输入。
窗口开多大是第一道取舍:开大一点能凑更多人,算力利用更充分,头部请求却多等了几毫秒。这段时间用户感觉不到,账却实打实记在延迟上。
攒批还要防头堵:窗口内第一条请求注定等满整个窗口,窗口越靠后的请求等得越短,同一批内等待并不均等。有的实现把窗口拆成两小段,第一段够数就提前开算,不够再等第二段,头部的等待能省下不少。窗口的两端都要记账:开大了平台省算力,开小了用户省时间,窗口大小就是这道题的答案,随流量水位动态调。
等待时间从哪来
批内请求互相拖:同一批里一个要生成两千字、一个只要五十个字,短的那条要陪跑到批尾或等调度把它分出来。批越大,这种陪跑越常见。
还有一道排队账:批正在算的时候,新来的请求只能等这一轮结束。批越大单轮越久,队尾等待越长。进来的是新请求,发生的是排队候场,出去的是被拉长的首字延迟。
两道账叠加,就是高峰期回答变慢的主要来源,网络通常不背这个锅。批内排序也有讲究:长度相近的请求放一批,陪跑自然减少,这叫按长度分桶。分桶牺牲一点填充率,换来批内耗时整齐,实测往往两头都更优。
三种等待来源与各自的缓解办法。
| 等待来源 | 怎么产生 | 缓解办法 |
|---|---|---|
| 批内陪跑 | 同批一条要生成两千字、一条只要五十字,短的陪跑到批尾 | 按长度分桶,长度相近的请求放一批 |
| 排队候场 | 批正在算时新请求只能等这一轮结束,批越大单轮越久 | 动态批每步重新组队,算完一条放走一条 |
| 头部等满窗口 | 攒批窗口内第一条请求注定等满整个窗口 | 窗口拆成两小段,够数就提前开算 |
动态批的折中法
折中方案是动态批:每生成一步都重新组队,算完一条就放走一条,新请求随时插进空位。连续组队让批的成员边走边换,兼顾填充率和等待,两头都不吃亏太多。
再配一条上限:批成员数封顶,防止算力被摊薄到每个请求都变慢。你在豆包、智谱清言里高峰提问仍有跟手的输出速度,服务端多半在跑这类动态组队。它调节的是排队方式,每条请求自己的计算不受影响。封顶值也不是拍脑袋:按单步计算耗时反推,超过这个数,每加一条都在拖慢全批。动态批的调度还有优先级接口:紧急请求可以插队进下一轮组队,普通请求按序排队,和优先级队列是同一套思想在批层面的延伸。动态批和静态批还能混用:长任务走静态大批,短对话走动态小批,框架按请求类型自动分派。观察批行为的窗口指标也有:平均批大小、批内等待分布、填充率,三个数一起看,就知道当前配置偏算力还是偏体感。
- 速查:攒批窗口开大省算力但添等待;批越大陪跑越多;动态批边走边换成员;成员数要封顶;高峰变慢多源于排队。
批之外还有别的旋钮,优先级队列是怎么排 VIP 的?分等级出队决定谁先进批,限流算法是怎么计数的?令牌桶的思路控制进多少,思考模型的思考段是怎么生成的?标记切换影响批内耗时差异,重试的退避是怎么算的?越等越久处理失败的那部分。
聊聊批大小和延迟的常见疑问
- 批越大成本一定越低吗?:算力利用更充分是真,但延迟变差,还要防摊薄,通常封顶后再算总账,总账要把延迟损失也算进去。
- 为什么有的回答第一个字特别慢?:很可能撞上攒批窗口加长队列,等的是开场而不是网速。
- 动态批会改变结果吗?:不会,组队方式不影响每条请求自己的计算内容,结果逐字一致,变的只是快慢。


