在本地机器上跑一个模型,和把它接到真实流量里,是两件不同的事。前者关心“能不能出结果”,后者关心结果在什么时间、以什么成本出来。很多团队第一次遇到落差都在压测阶段:单条请求看着还行,并发一上来等待时间被拉长几倍,而显卡利用率显示还有余量。
先弄清楚时间花在哪
一次生成请求大致分两段。前半段处理输入,把整段提示词压成模型内部的状态,通常是一次性的大计算;后半段逐字往外吐,每吐一个词都要把此前的状态重新读一遍。两段的瓶颈不一样:前者更吃算力,后者更吃显存带宽。混在一起谈“慢”,往往找不到下手的地方。所以推理优化的第一步不是换框架,而是把这两段拆开测。
还有一段常被忽略:排队。请求进来先进入调度队列,等一个批次凑齐,或者等显存腾出位置。这部分时间不出现在模型的计算里,却实实在在落在用户的等待上。
吞吐和延迟是两笔账
批处理是最常见的做法:把多个请求拼在一起算,显卡一次干更多活,单位成本随之下降。代价是每个请求都要等同伴,批次越大,单条请求的等待越长。这就是吞吐和延迟之间的取舍。
所以讨论推理优化时,得先说清楚优化的是哪一笔账。离线批量生成任务,比如夜里处理一批文档,几乎只看吞吐,批次开大是合理的;在线对话场景里,用户盯着屏幕,首字延迟和吐字节奏比总成本更敏感,激进批处理反而伤体验。
- 先定指标:是首字时间、单请求完成时间,还是每千次调用的成本。三者常常互相拉扯。
- 再看分布:平均值会掩盖长尾,少数很慢的请求往往决定了用户感受。
- 最后才选手段:换推理引擎、量化、缓存复用,都只在特定瓶颈下才有效。
被低估的重复计算
很多线上请求带着相同的系统提示词或同一段长文档。每次重新算一遍是纯粹的浪费。把这段计算的结果缓存下来复用,往往比换一个更快的计算内核更直接。这类改动不涉及模型本身,属于工程侧的空间,却常被跳过——因为它不像“换模型”那样显眼。
量化是另一条路:用更低精度表示权重和中间结果,减少显存占用和搬运量。它对带宽受限的解码阶段帮助明显,但对精度敏感的任务要小心验证。这里没有通用答案,只能在自己的数据上看差异。
优化有边界
不是所有系统都值得做深度推理优化。请求量很小、模型本身不大的场景,把工程复杂度堆上去,维护成本可能超过省下的那点算力。反过来,一个功能已经稳定运行,改动带来的风险也要计入成本。
我更倾向于这样的顺序:先测量,找出真正占时间的那一段;再做那些不改动模型语义的调整,比如缓存和调度;最后才考虑量化或结构上的改动。每一步都留出回退的余地。
推理优化听起来是个纯技术问题,实际上是个取舍问题——你得先知道自己在意哪段时间,才谈得上把它变短。