下午三点,监控面板上那条 P99 曲线又开始抬头。机器没换,模型没改,上游流量也只是平稳上涨。值班的人先去查网络,再去看显卡利用率,最后往往在一张延迟分布图前停住——大部分请求很快,少数请求拖得很长,平均值把这件事盖住了。
慢的往往不是计算,而是排队
把一次请求拆开看,时间花在几个地方:在队列里等一个空闲的批次,等前面的长请求算完,把提示词送进模型做预填充,然后一个 token 一个 token 地解码,中间还夹着显存与显存之间的搬运。任何一段变长,用户感受到的都是“卡”。
所以推理优化的第一步不是换框架,而是把这条路径量清楚。哪一段占大头,优化才有落点。不少团队直接上手改算子,结果发现瓶颈其实是调度器把一个短请求排在了几个超长请求后面。
合批的两面
批处理是吞吐的朋友,却常常是延迟的敌人。把请求攒在一起喂给显卡,单位时间能算得更多,但短请求要陪着长请求一起等。连续批处理把这件事缓解了不少,新请求可以在旧请求解码的间隙插进来。可调度策略仍然要按业务来定:对话类场景在意首字延迟,批量生成类场景更在意整体吞吐,两者对同一套参数的容忍度完全不同。
这也是我对推理优化的一个基本判断:它更像资源分配问题,而不是纯粹的算力问题。让该快的先快,往往比让所有请求平均快一点更值钱。
手段都有前提
几类常见做法,效果都成立,但前提常被忽略。
- 量化能压显存带宽占用,让同样的硬件塞下更大的模型;代价是精度损失,在长尾输入上更容易露出来,评测集跑得好不代表线上稳。
- KV 缓存复用对多轮对话很划算,因为前缀重复;对一次性长文输入,能复用的部分有限。
- 投机采样用一个小模型先起草、大模型再校验,起草质量高时才真正省时间,否则校验开销会把收益吃掉。
这些手段单独看都不错,叠在一起却可能互相抵消。显存被缓存占满,批大小就上不去;批大小压得太低,量化的带宽优势又发挥不出来。参数之间是耦合的,调优更像找一个合适的平衡点。
什么时候该停手
还有一种情况值得说:请求量本来就小,延迟也不算难看,这时候花几周做优化,收益可能不如把超时、重试和降级理顺。优化本身有维护成本,一套为特定流量结构调出来的配置,流量一变就要重调。判断标准其实很朴素——先看延迟账本上有没有明显的一段,再看这段是不是稳定可复现。
如果量出来的分布是平的,各段都不突出,那大概率不是推理层的问题。
先量,再改
我见过不少团队在优化上花了力气却没感觉变好,原因多半是没先拆开看。一张清楚的延迟分解图,比任何一套默认参数都有用。推理优化到最后,考的不是谁知道多少技巧,而是谁愿意先把等待的形状画出来。