晚高峰的在线客服窗口里,用户发出问题后,光标闪了两秒才开始吐字。工程师常先想到加机器,可把监控拆开看,排队时间、首字延迟、吐字速度、上下文长度和并发数并不在同一张图上。推理优化要处理的,正是这张被拉开的图:不是让模型显得聪明,而是让它在既定资源下守时。
先分清慢在哪一段
一次生成请求可以粗略分成进入队列、预填充、逐 token 解码和返回四段。预填充像一次性读完长材料,解码像逐字写答案。长上下文请求会把预填充拉长,高并发则让解码阶段互相争抢。只盯平均响应时间,容易把排队问题误判成模型问题。实用的做法,是把首字延迟和每 token 延迟分开记录,再按请求类型切片:短问答、长文档摘要、多轮对话,瓶颈并不相同。
这也是常被误解的地方。它不等于换一个更小的模型,也不等于把批大小一味调高。批处理能摊薄单位成本,却可能让个别请求多等一会儿;缓存能省掉重复计算,却要面对上下文变化后的失效问题。工程上的取舍,往往取决于业务能不能接受平均变快、尾部变慢,或者反过来。
把手段放回约束里
常见手段可以列成一串,但每一项都有条件。
- 批处理与连续批处理:适合吞吐压力大、请求长度差异可控的场景,需要关注排队策略和超时设置。
- KV 缓存复用:对多轮对话、固定前缀的请求有帮助,前提是缓存命中率足够,且内存开销算得过来。
- 量化与蒸馏:能降低显存和计算压力,但要重新评估输出稳定性和长尾任务表现,不能只看短样本。
- 投机解码:用轻量草稿先猜、再由主模型校验,适合对延迟敏感且分布相对稳定的任务,收益会随任务变化。
- 路由与降级:把简单请求交给轻量路径,把复杂请求留给完整路径,难点在于判定规则要可解释、可回滚。
这些手段不必同时上。稳妥的顺序是先建立可观测性,再找一个能被验证的瓶颈,做小范围改动,观察首字延迟、尾部延迟、错误率和资源占用是否一起变化。推理优化如果只追求单点指标,容易在另一个角落付出代价。
延迟预算也是产品设计
用户感知的快,并不完全等于服务器时间。输入框里的即时反馈、流式输出的首段内容、可取消的生成过程,都会改变等待的感受。与其把所有请求压进同一条低延迟通道,不如先问:哪些步骤必须实时,哪些可以异步,哪些可以给用户一个明确进度。把延迟预算分配清楚,往往比盲目堆叠算子有效。
边界也要提前说清。长上下文、复杂工具调用、严格格式输出,都会让推理优化的空间收窄;某些任务对数值精度或输出一致性要求高,量化和近似计算就要谨慎。优化不是消灭所有等待,而是让等待发生在合适的位置,并且可被解释。
所以,当首字迟迟不来时,先别急着把问题归因于模型太慢。把请求拆开、把指标分开、把约束摆上桌面,推理优化才会从口号变成一组可验证的小决定。