一个客服对话窗口,用户点下发送,光标转了两秒才蹦出第一个字。后端监控里 GPU 利用率并不高,日志也没有报错。这类问题在接入大模型之后变得常见:模型能答对,却很难及时给出反馈。
很多人的第一反应是换更小的模型,或者直接加机器。但在动手之前,先拆开看“慢”是由哪几段组成的,会更有帮助。用户感知到的体验至少由三段时间构成:从请求发出到第一个字出现,字与字之间的间隔,以及整段回答结束的总时长。这三段时间的瓶颈未必在同一处,优化手段也未必通用。
延迟与吞吐,本来就互相拉扯
推理服务通常同时背着两个指标。延迟看单个请求有多快,吞吐看单位时间能服务多少请求。把多个请求攒成一批送进显卡,吞吐会上去,但排在后面的请求得等前面的凑齐,单请求的等待就变长。反过来,来一个算一个,响应干脆,硬件却常常闲着。
于是推理优化首先要回答的不是“用什么技巧”,而是“这一路业务更怕哪一种慢”。面向人的实时对话产品,首字延迟是硬指标;离线批量生成摘要、打标,吞吐和单位成本才是重点。两者的调参方向几乎相反。
几个常被混为一谈的手段
- KV cache:把已经算过的中间结果留在显存里,避免重复计算。用空间换时间,代价是上下文变长时显存占用增长很快,并发一多就容易撞到容量上限。
- 连续批处理:请求不必等齐,谁先完成谁先走,新请求随时可以插进来。它缓解的是排队浪费,但对调度实现的要求更高。
- 量化:用更低的数值精度表示权重或激活值,减少显存占用和带宽压力。省下来的资源可以换来更高并发,但精度损失是否可接受,得看具体任务。
- 投机解码:用一个小模型先猜几个词,再由目标模型一次性校验。猜得准时明显加快,猜不准时反而多做功。
这些手段常被并列提起,其实作用的位置不同:有的省算力,有的省带宽,有的省等待。混着上,很可能一项的收益被另一项的代价抵消。
先度量,再谈优化
推理优化最容易犯的错,是在不清楚瓶颈的情况下照搬方案。显卡算力打满、显存带宽吃紧、请求调度不合理、上下文过长,表现都可能是“慢”,但解法完全不同。把首字延迟、每字间隔、批大小、显存占用这几项拆开分别埋点观测,往往比换一套框架更有用。
另一个容易忽略的点是,优化不是一次性项目。模型在换、流量在变、业务对延迟的容忍度也在变,上个月合适的批处理策略,这个月可能就成了尾延迟的来源。把它当作持续的工程习惯,而不是上线前的一次冲刺,判断会稳一些。
回到那个一直转圈、迟迟不出结果的窗口。真正需要回答的问题不是“能不能再快一点”,而是“在哪一段慢、值不值得为它付出精度或成本的代价”。想清楚这一点,推理优化才算真正开始。