LLM推理能耗真相:Token只是表面成本,GPU功耗由什么决定
2026/9/15 4:05:17 网站建设 项目流程

前阵子帮朋友调一个LLM问答服务的性能,现象很奇怪:日活没涨多少、Token消耗量也基本持平,但GPU的功耗均值比之前高了将近一倍。查了半天,最后定位到问题出在模型输入的上下文长度被某个策略意外拉长,导致Prefill阶段的计算量暴涨。这件事让我意识到一个常见误区——在LLM推理这个场景里,用Token数量来估算GPU能耗,误差会大到离谱。Token只是表面成本,真实的能耗藏在模型规模、序列长度、批量策略和显存带宽这些更底层的因素里。这篇文章想把这个账彻底算清楚。

1. 为什么说Token只是表面成本

1.1 Token到底计量了什么

Token是文本被分词后的基本单位,一个Token可能是一个中文词、一个英文单词片段、一个数字或者一个空格。在做成本核算的时候,绝大多数人习惯把Token当成"模型干了多少活"的计量单位,Token越多,以为开销越大。

这在一整批相同的请求里大体成立,但只要稍微放大尺度,就会发现Token作为计量单位非常不准。Token度量的其实是"模型读入和生成的语言量",而不是"GPU实际执行的计算量"。打个比方,Token相当于快递单上的包裹数量,可同一个包裹,寄到隔壁小区和跨省运输,成本完全不同。Token只是描述了包裹个数,没有描述重量、距离和运输方式。

在LLM推理里,决定"运输成本"的因素包括模型体量、输入长度与输出长度的比例、是否批量推理、并发程度、显存带宽利用率,甚至GPU当前有没有进入节能状态。这些变量叠加在一起,会让单位Token的能耗差异拉出数量级。

1.2 同样的Token,完全不同的能耗

我们直接看两个极端场景。第一个场景是100个用户各发来一句"你好",模型每次只输出一句话,总Token量可能是几万。第二个场景是1个用户输入了一篇5000字的文章,要求模型生成摘要,同样也能凑出几万Token。两个场景的Token总量可能接近,但GPU的功耗曲线绝对天差地别。

差在哪?主要差在三块:第一,长输入会触发大规模Prefill计算,GPU的算力单元被拉满,功耗峰值明显抬高;第二,短对话场景下,如果服务端做了并发批处理,多个请求可以共享一次权重读取,单位Token的能耗会被摊薄;第三,长输出的后半段,KV Cache体积越来越大,每一步解码要搬移的数据越来越多,单Token成本会随序列长度逐步上升。

所以,只看Token总量来估算GPU能耗,就好比只看了油价牌上的"加了多少升",却完全没在意车型、路况和载重。在真实线上服务里,这些被忽略的变量才是决定电费单的大头。

1.3 只按Token做成本评估的坑

不少做LLM应用的朋友习惯拿Token量去反推资源需求:昨天消耗了100万Token,今天预计120万,那GPU资源就加20%。这个线性外推在负载结构稳定时勉强能用,一旦输入输出模式改变,就会出问题。

举个例子,产品经理说"用户反馈回答太短,把最大输出长度从256改到1024"。从Token总量看,可能只是每次输出多了几百Token,似乎无所谓。但实际上,对于生成密集型任务,输出长度翻4倍意味着Decode阶段的时间翻4倍,GPU的功耗曲线从"短促脉冲"变成"长时间高负荷",如果再叠加并发,卡上的显存和带宽压力会同时上涨。数据上看起来只是Token变多了,资源需求却可能从1块卡变成3块卡。

我见过不少团队在做容量规划时只用Token总数做除法,结果线上遇到长上下文任务直接卡顿,只能临时加机器。Token作为表面成本,最大的问题就是它把能耗的很多真实维度压平了,让人误以为成本模型非常简单。

2. LLM推理的能耗到底花在哪

2.1 Prefill:算力密集的真烧电阶段

在生成第一个Token之前,模型需要把用户输入的整个序列一次性处理完,这个阶段叫Prefill。它的计算量大约是"输入Token数 × 模型参数总量"再乘一个倍数,输入越长,矩阵乘法的规模越大。

我们拿7B模型举例,FP16精度下,模型权重大约14GB。处理1000个输入Token时,要做的是大批量的矩阵乘,这时GPU的Tensor Core能把算力跑到很高。A100级别的卡FP16峰值算力在300 TFLOPS级别,Prefill阶段也能跑到几十TFLOPS的有效算力。算力单元被大量激活,动态功耗自然上去了。

这也是我前面提到的那个线上事故的根源:上下文长度被策略意外拉长,用户每条请求的Prefill计算量涨了好几倍,GPU功耗均值明显升高。从Token总量看,变化不大;但从GPU的实际工作模式看,每一次请求都变成了一次重型计算。

2.2 Decode:显存带宽决定速度与功耗

生成Token的阶段叫Decode,它是逐Token串行出结果的,每次只生成一个Token,然后把新Token加入序列,继续预测下一个。这个阶段的问题在于,每一步都要从显存里把完整的模型权重读一遍,再做一次矩阵乘。

还是7B模型FP16,权重14GB。如果显存带宽是2TB/s,那么光读一遍权重就需要大约7毫秒,这还没算KV Cache的读取和其他开销。也就是说,Decode阶段的Token生成速度,本质上被显存带宽卡住了,而不是被算力卡住。GPU的计算单元大量时间在等待数据搬运,整体运行在一个"带宽饱和、算力闲等"的状态。

这个特点反映到功耗上,就是Decode阶段GPU的功耗虽然不低,但往往达不到Prefill那种"完全烧起来"的峰值。最麻烦的是,因为模型权重每个Token都要读一遍,模型越大,每股Token消耗的显存带宽就越多,能效也更差。所以70B模型跑推理,不只是比7B模型贵几倍,而是贵得更多。

2.3 KV Cache:序列越长单Token越贵

KV Cache是Transformer解码过程中缓存的历史Key和Value向量,用来避免每次生成都重新计算之前所有Token的注意力。它的体积和序列长度成正比。以7B规模的模型为例,FP16下一个Token的KV Cache大约在0.5MB上下,看起来单Token不大,但上下文一旦到4096,KV Cache就能涨到2GB量级;如果支持1万Token的长上下文,单路请求的KV Cache就会吃掉很大一块显存。

KV Cache不只是占显存,它还会拖慢解码速度。生成第1000个Token时,需要把前面999个Token的KV Cache读出来参与注意力计算;生成第2000个Token时,要读的数据翻倍。所以序列越长,单Token解码时间越长,功耗也越高。换句话说,同样一个"Token"的输出,放在长上下文请求的末尾,和一个短对话里单独的Token,实际成本完全不是一个等级。

这也是"Token是表面成本"最具欺骗性的地方:用户看到的每个Token长得一模一样,但对GPU来说,长序列后面的Token每一步都要背着一大包历史数据跑,代价显然要高得多。

2.4 静态功耗:没跑任务也在花钱

GPU不是只在计算时耗电。显卡上电后,显存要持续刷新,核心要保持运行状态,这部分的静态功耗一直都在。空载的A100可能也有三四十瓦的功耗,一些老款显卡待机功耗更高。

更关键的是,整个推理节点不只有GPU。CPU、内存、主板、风扇、电源转换损耗都在耗电。服务器整机的空载功耗往往比GPU的空载要高不少。如果把数据中心里的空调和散热也算进去,每1瓦的IT设备功耗背后,可能还要额外分摊0.3到0.5瓦的制冷能耗。

所以在做推理能耗核算时,如果把GPU满载功耗当成唯一成本,会系统性低估整体能耗。反过来,如果GPU长时间处于低利用率,静态功耗的占比会变得非常难看。经常有人问为什么GPU看起来没跑满但电费还是很高,多半就是静态功耗摊薄后的结果。

3. 六个改变能耗走向的关键变量

3.1 批处理大小

批处理是影响推理能效最直接的因素。GPU最擅长的是大规模并行计算,如果一次只处理一个请求,大批算力资源都在空转。如果把多个请求拼成一个batch,那么模型权重从显存读取一次,就能服务多个请求,等效的单Token显存搬运量大幅下降。

vLLM这类框架用Continuous Batching技术,不要求请求对齐到同一个batch,而是每来一批Token就动态拼一次计算,这样能显著提高吞吐。从能耗角度看,批处理越大,单位Token耗电越低;但batch过大,显存里的KV Cache会被挤爆,矩阵计算的调度开销也会上升,实际效果需要实测。

我自己习惯的做法是,在离线跑批场景里把batch调到显存允许的上界,在线服务场景则通过并发控制让框架自己聚合,尽量让每张卡的batch不低于个位数,否则单Token的能耗会非常难看。

3.2 输入与输出的配比

用户的请求结构不同,GPU的能耗账单完全不同。输入占多数的场景,比如要给文档做分类、摘要、信息抽取,能量主要集中在Prefill阶段,特征是"爆发式算力消耗"。输出占多数的场景,比如聊天机器人生成长回复,能量集中在Decode阶段,特征是"长时间低效率计算"。

同样是100万Token总量,如果全是输入Token,可能几秒钟就烧完了,GPU峰值功耗高但总耗电量不大;如果全是输出Token,可能要持续跑几十分钟,总耗电量显然大得多。做成本估算时必须区分输入和输出,把它们当成两种不同的资源类型来对待。

3.3 并发度与排队

在线服务一定有并发。并发数的提高,一方面通过批处理摊薄了单位Token成本,另一方面也让GPU的功耗更稳定、更饱和。但并发并非无上限,如果请求到达速率不均匀,会出现排队:请求在等待时,GPU可能已经算完了当前批次,进入短暂的空转,功耗先落下来,下一波请求来了又冲上去。

这种"锯齿形"的功耗曲线,不仅让电费核算变难,也意味着GPU资源存在浪费。如果排队时间过长,反而会让静态功耗占比拉高,单位Token的能耗不降反升。所以并发设计的目标不是一味求高,而是让GPU始终处于"有事可做"的连续运转状态。

3.4 量化与精度

模型权重用FP16还是INT8,对能耗影响非常大。Decode阶段受限于显存带宽,把权重从FP16降到INT8,意味着每次读取的数据量减半,带宽压力大幅下降,单Token生成速度和单位Token能耗都会改善。W4A16这种权重4比特、激活16比特的方案,能进一步压缩权重体积。

代价是精度损失和实现复杂度。不是所有模型都适合直接量化,需要做校准和评估。但从能耗角度看,量化是用质量换能耗的一种非常划算的交易。尤其对长上下文和多并发场景,权重体积减小带来的收益是全局性的。

3.5 模型规模与架构

模型规模对Token成本的影响是线性甚至超线性的。7B模型和70B模型,参数差距10倍,Decode阶段每个Token都要读取权重,带宽需求也差约10倍,单Token能耗自然水涨船高。这也是为什么小模型在能耗上拥有天然优势。

架构层面,MoE(混合专家)模型是另一个方向。它保持总参数很大,但每个Token只激活一部分专家,理论上推理时的有效计算量远小于同等参数量的Dense模型。不过MoE的显存占用依然很大,路由和通信开销也需要消耗资源,实际能效需要看具体实现。

3.6 显卡型号与功耗墙

注意,GPU型号的峰值功耗并不直接决定推理能耗。一张TDP 450W的卡,如果在推理时只跑到250W,那它实际的能耗和"省电"没有必然关系。反过来,一张TDP 300W的卡,如果推理时长期贴墙跑,反倒可能更耗电。

更实用的指标是"完成同一批推理任务,谁的总耗电量更低"。这个指标跟算力、带宽、功耗墙、散热策略都有关。有些卡能通过设定功耗上限来降低整体能耗,比如用nvidia-smi把功耗拉到TDP的70%,性能损失可能只有10%,单位任务的能耗却更优,这在供电和散热受限的机房尤其值得试。

4. 实测记录:同一个模型,不同负载下的功耗曲线

4.1 测试环境怎么搭

这里我分享一组实际观测数据,虽然具体数值换到你的显卡上肯定有差异,但趋势有普遍参考价值。测试环境是一个7B参数量的对话模型,FP16精度,跑在一张A100 80G上,推理框架用的是支持Continuous Batching的服务端方案。监控工具很简单,就是nvidia-smi周期性记录功耗和利用率。

nvidia-smi --query-gpu=timestamp,power.draw,utilization.gpu,utilization.memory,memory.used --format=csv -l 1

把输出重定向到文件,跑完测试后再拿Python做聚合分析。有一点必须提醒:单次采样只能看到瞬间情况,一定要跑足够长的时间,等GPU温度稳定之后再做对比,否则冷机状态下的功耗和热机状态下的功耗会干扰结论。

4.2 场景A:单条长输出

第一个场景是模拟用户要求模型写一篇长文,生成上千Token,输入很短,输出很长。这种场景GPU大部分时间处于Decode阶段,平均功耗在280W左右,峰值能到350W,但算力利用率并不高,因为显存带宽先到了极限。

此时的有效吞吐大概在每秒60个Token,算下来每百万Token大约消耗1.3度电。注意这只是单张卡GPU本身的耗电,不含CPU和散热系统。这个场景的特点是"跑得久、功耗居中、每Token成本偏高"。

4.3 场景B:并发短对话

第二个场景是模拟线上一堆用户同时聊天,平均输入512 Token,输出256 Token,并发控制在4到8路之间。因为有Continuous Batching,多个请求的计算被拼在一起,GPU的算力得到了更充分的利用,平均功耗上到350W左右,但有效吞吐拉到了每秒180个Token。

换算一下,每百万Token耗电降到约0.54度。相比场景A,单卡功耗更高,但单位Token的电费反而降了六成。原因就是批处理把权重读取成本摊薄了。线上服务的Token分布越接近这个场景,GPU能效就越好看。

4.4 场景C:离线批量推理

第三个场景是给一批离线数据做推理,batch直接调到32,输入和输出都比较规整。这时候GPU几乎全程贴墙跑,平均功耗390W,有效吞吐稳定在每秒400 Token以上,每百万Token耗电只有0.27度左右。

这个数字很有说服力:同样是百万Token,批量推理的能耗只有单条长输出的五分之一左右。所以如果服务里存在大量可以异步处理的请求,把它们从在线链路里挪到离线batch队列,既能改善在线延迟,又能大幅降低单位Token的能耗。

4.5 这些数据到底说明了什么

汇总一下这组示意数据:

负载场景平均功耗(W)有效吞吐(tokens/s)每百万Token耗电(kWh)
空载约35W0无意义
单条长输出280W60约1.3
并发短对话350W180约0.54
离线批量推理390W400约0.27

同样是一个Token,在不同负载模式下,背后的能耗可以相差接近5倍。如果只看Token总量做成本核算,相当于把这5倍的差距全部抹平了。这就是"Token只是表面成本"最直接的证据。

5. 推理能耗怎么估、怎么省

5.1 一套不算太严谨但很实用的估算方法

要估GPU推理能耗,与其从Token数量反推,不如按"请求分布"来算。核心公式很简单:请求总量里有多少是输入Token、有多少是输出Token、平均并发和batch是多少,然后分阶段估算。

更实用的做法是先给当前部署打一个基线:在标准测试负载下量出"每百万Token耗电"这个数。比如你的服务跑聊天场景,可以用并发短对话模式测出大致0.5到0.7度/百万Token的基线。有了这个基线,后续根据输入输出分布的变化做加权调整,比直接拿Token总数乘一个固定系数要准确得多。

如果要做容量规划,从能耗反过来推更靠谱:单卡能稳定提供多少Token吞吐,一天能跑多少Token,再结合功耗上限确定需要几张卡。这个逻辑比"按Token总量除以单卡吞吐"可靠,因为它把并发、批处理、输入输出结构都考虑了进来。

5.2 立竿见影的省电手段

在不动模型结构的前提下,有几种实用省电手段可以立刻见效。

第一,升级推理框架。vLLM、SGLang这类带Continuous Batching的框架能显著提高吞吐,同样一批请求跑下来,总耗电更少。第二,做量化。INT8或W4A16对带宽瓶颈的Decode阶段非常友好,只要精度损失在可接受范围,能效提升立竿见影。第三,控制最大输出长度,减少长尾输出对KV Cache和Decode时间的浪费。

第四,设置功耗上限。很多卡支持通过nvidia-smi -pl限制最大功耗,比如把450W的卡限制到350W,性能损失可能只有十几个百分点,但整机供电和散热压力小很多。第五,空闲时把不用的模型实例缩容,避免GPU空转吞电。

5.3 如何把能耗成本看清楚

推荐在监控面板里同时盯五个指标:GPU功耗均值、GPU利用率、显存占用、显存带宽利用率、请求排队长度。功耗均值负责告诉你钱花在哪,利用率和带宽负责解释为什么这么花,排队长度负责判断负载是否平稳。

成本核算时,建议把Token拆分统计,输入Token和输出Token分开记账,再给输出Token一个更高的权重。如果平台是给别人提供API,这种记账方式也更接近真实成本结构。最终你会发现,真正影响账单的不是用户说了多少话,而是模型为此执行了多少次高能耗计算。

6. 排查实录与避坑清单

6.1 利用率高但功耗低

这个现象在Decode密集型负载里非常常见。GPU利用率高,说明计算单元在忙;但功耗低,可能是因为大量时间花在等待显存数据回传上,计算单元并没有在满负荷执行浮点运算。显存带宽把功耗"压住"了。

排查时不要只看utilization.gpu,要配合看utilization.memory。如果memory利用率经常拉满而gpu利用率只有一半,说明你的负载是访存密集型,优先优化路径是降低精度、压缩权重、减少KV Cache读取量,而不是堆算力。这种情况加更多的CUDA Core没有用。

6.2 功耗忽高忽低

在线服务最容易出现这个问题。功耗曲线的锯齿通常来自请求到达不均匀:一批请求同时来了,GPU瞬间拉高功耗跑完,然后陷入短暂空闲,下一波请求又拉起来。这种波动说明没有足够的并行请求让GPU保持持续饱和。

排查方案是把请求日志和功耗曲线对齐,看波峰是否对应请求到达率的高峰。如果确认是流量毛刺导致,可以做小规模缓冲队列,把请求稍微攒一攒再统一批处理。在线延迟允许的话,这个缓冲能显著拉平功耗曲线,同时提升吞吐。

6.3 KV Cache把显存吃光

显存被占满、GPU利用率不高、功耗也不高,但服务经常超时。这种情况大概率是KV Cache膨胀导致的。长连接里如果大量用户同时保持长上下文,每个请求都占着一大块KV Cache,显存被迅速吃光,后续请求只能排队。

建议给每条请求设置合理的最大上下文长度,启用PagedAttention这类显存管理策略,并监控KV Cache的命中率和占用率。如果发下大多数请求用不到长上文,那就把max_model_len调小,把省出来的显存让给并发和batch,综合能效反而更高。

6.4 长期功耗监控脚本

我经常会留一个后台脚本采集功耗数据,尤其是做性能调优对比的时候。一个简单的Python采集思路如下:

import subprocess import time with open("power_trace.csv", "w") as f: f.write("timestamp,power_w,gpu_util\n") for _ in range(3600): out = subprocess.check_output([ "nvidia-smi", "--query-gpu=timestamp,power.draw,utilization.gpu", "--format=csv,noheader,nounits" ]) f.write(out.decode().strip() + "\n") time.sleep(1)

跑完负载测试后,把这个文件丢进Excel或Python里画个趋势线,能直观看到不同阶段功耗变化。注意,nvidia-smi的采样频率是秒级,对于非常短促的负载变化可能捕捉不到峰值,但它足够用来给出能耗基线和判断整体趋势。

6.5 一个容易被忽略的温度问题

GPU温度对功耗的影响比很多人想象中大。温度升高会让晶体管漏电流增加,导致同频下的功耗上升;同时显存在高热下也会更耗电。如果机房风道不合理,或用了很久没清灰的卡,很可能出现"温度高、频率掉、功耗还不低"的情况。

做一个简单测试:同一个负载跑20分钟,对比前5分钟和后5分钟的功耗与跑分。如果功耗明显上升且性能下降,先把散热问题解决,再来谈优化。省电不仅是软件层面的事,硬件维护同样重要。

最后分享一个小习惯:我在做LLM服务性能优化时,一定会同步记录功耗,而不是只看耗时和吞吐。功耗曲线能告诉你很多延迟指标看不到的东西,比如显存带宽是不是瓶颈、批量策略是不是合理。建议你也拿nvidia-smi在标准负载下蹲几分钟,算出一个"每百万Token耗电"的基线。有了这个数,后面做优化和容量规划,都会省很多事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询