一个问答功能刚上线时,白天的表现还算正常,到了晚间高峰,响应开始排队。模型没有换,机器没有换,可监控面板上的曲线明显变了。这类问题通常先被归给网络或流量,但排查到后面,瓶颈常常落在推理优化上。它决定的不是模型会不会答,而是每一次回答要搬多少数据、等多久。
训练阶段的关注点是如何收敛,进入线上之后,问题换了一套:怎样在有限显存里同时放下缓存和批次,怎样让计算单元不必空等内存。很多团队把精力集中在权重和效果上,等到服务真正跑起来,才发现工程侧的账要重新算。
一次生成,其实分两段
输入被并行处理的那一段,主要消耗算力;随后逐字吐出的那一段,瓶颈更多落在显存带宽上。两段特性不同,如果只按一套参数去调,很容易按下这头翘起那头。输入很长的场景,前一段的占比会上去;输出很长时,拖尾的则是后一段。
- 输入偏长:先看预填充阶段的算力占用与排队情况。
- 输出偏长:留意逐字生成时带宽是否被占满,尾延迟是否被少数请求拉长。
把这两段分开测,比笼统看一个平均值有用得多。平均值会掩盖掉那些真正让人感知到卡顿的慢请求。
缓存是省下来的,也是占地方的
键值缓存用空间换掉重复计算,这是推理优化里最常被提起的一招。但它同时是消耗品:上下文越长,占用越大,能并行服务的请求就越少。有时所谓变慢,并不是算不过来,而是缓存把显存挤满了,新请求只能排队等位置。
于是取舍出现了:缓存留多长、什么时候回收、长上下文请求是否单独分组。这些问题没有通用答案,取决于业务的输入长度分布。
批处理不是越大越好
把请求攒在一起送进去,吞吐上去了,代价是单个请求的等待变长。在线服务面对的是真人,等待的感受比总吞吐更直接。分档处理、限制并发、给交互式请求留出通道,这些手段通常比盲目调大批次更实际。
还有一点常被忽略:压测要能复现。没有可重复的负载和可对照的指标,调参很容易变成猜,改动越多,越说不清是哪一步起了作用。
它有边界
推理优化的收益并非在所有场景都显著。请求极短时,调度开销本身就占了不小比例;冷启动阶段,缓存还没热起来;强实时的交互里,能压缩的余量有限。承认这些边界,比承诺一个普适的加速方案更负责。
更现实的做法是把它当成一种工程习惯:把指标拆开看,把负载按场景分开测,每次改动留好回滚路径。模型能力决定上限,而推理优化决定这个上限在日常使用中能被摸到多少。