第一部分:先建立物理直觉
1.1 GPU 为什么"慢"
听起来奇怪 —— GPU 不是很快吗?为什么说它慢?
GPU 的算力(计算速度)很快,但显存到计算单元的数据搬运速度,慢得多。
打个比方:
- GPU 计算单元 = 一个超人,1 秒能做 1000 万亿次乘法
- GPU 显存 = 超人旁边的仓库,里面装着模型权重(要计算的"原料")
- 传送带 = HBM 带宽,把原料从仓库送到超人手上
关键事实:超人干活的速度,是传送带送货速度的几百倍到一千倍。
意思是:如果超人手边的原料没了,他就得停下来等传送带。等的时间里,超人闲着。
H800 的具体数字:
| 指标 | 数值 | 物理含义 |
|---|---|---|
| FP16 算力 | ~1000 TFLOPS | 每秒 1000 万亿次乘法 |
| FP8 算力 | ~2000 TFLOPS | FP8 翻倍 |
| HBM 显存大小 | 80 GB | 显存仓库 |
| HBM 带宽 | ~3 TB/s | 仓库到计算单元的传送带 |
| NVLink(H800) | 400 GB/s | 同机内卡和卡之间 |
| PCIe 5.0 | 64 GB/s | GPU ↔ CPU |
关键比例:算力 ≈ HBM 带宽 × 300 倍。
所有推理加速技术,本质上都在解决同一个问题:要么减少传送带要送的货,要么让超人在等货的时候顺便干点别的,要么让传送带送货更聪明。
1.2 模型在 GPU 里长什么样
模型权重 = 一堆数字(参数)。
脱敏说明:本稿件逐类检查九类敏感项,未发现需要替换的内容。文中出现的 H800 为公开销售的硬件型号,其 HBM 带宽、FP8 算力等参数均为公开产品规格,非内部部署信息,故保留。原稿第 8 页之后(1.2 节起至附录)未包含在本稿件输入中,如需完整内容请获取原稿。
一个 70B(700 亿参数)模型,每个参数用 2 字节存(FP16 精度),共 140 GB。 某型号卡单卡只有 80GB 显存,装不下 140 GB。所以你只有三个选择: 压缩模型(量化):每个参数用 1 字节存,模型变成 70 GB,能装进单卡 切到多卡:把模型分到 2 张卡上,每张卡装一半 换更小的模型 这就是为什么后面会反复看到"FP8 量化"和"多卡部署"。
1.3 LLM 是怎么"说话"的(自回归生成)
你必须先扔掉一个错误直觉
❌ 错误直觉:你问一句话,模型读懂,然后输出一整段回答。 ✅ 实际真相:模型只能预测"下一个字"。一整段回答是一个字一个字蹦出来的。
用例子讲清楚
你问:"请帮我写一首关于杭州的诗" 模型的回答:"江南忆,最忆是杭州"
这 9 个字是怎么生成的?模型不知道自己接下来要说"江南忆"。它每一步只做一件事:看看目前已有的文字,预测下一个字应该是什么。
第1步: 已知 = "请帮我写一首关于杭州的诗" 模型预测下一个字 = "江"
第2步: 已知 = "请帮我写一首关于杭州的诗江" ← 把"江"加进来 模型预测下一个字 = "南"
第3步: 已知 = "请帮我写一首关于杭州的诗江南" 模型预测下一个字 = "忆"
...一直循环,直到模型预测出"<结束>"标记
每一步,整个 140 GB 模型权重都要从显存搬到计算单元走一遍。
这种"一个字一个字往外蹦"的方式,叫自回归生成(Auto-regressive Generation)。ChatGPT 网页上你看到的"流式输出",就是模型真实的工作方式。
1.4 推理的两个阶段:Prefill 和 Decode
理解了自回归,现在能讲清楚推理的两个阶段了。
Prefill = 处理你的输入,吐出第一个字
输入:"请帮我写一首关于杭州的诗"(10 个字) Prefill 做的事:把这 10 个字一起喂给模型,让模型预测出第一个回答字"江"。
关键点:因为这 10 个字都是已知的,可以同时塞进 GPU 让所有计算单元一起算。
矩阵规模大 → 超人忙得过来 → GPU 算力利用率 60-80% 这叫 compute-bound(算力是瓶颈) 时间:100-200 毫秒
Decode = 一个字一个字往外蹦
第一个字"江"已经有了。现在要生成"南"、"忆"...
Decode 做的事:每次只把 1 个新字喂给模型,预测下一个字。
关键点:因为下一个字必须等当前字生成完才知道,没法并行,只能一次一个。但是 —— 整个 140 GB 模型权重还是要搬运一遍。
矩阵规模小 → 超人只算 1 个字 → 但搬运量没变 → GPU 算力利用率 1-5% 这叫 memory-bound(搬运是瓶颈) 时间:每个字 10-30 毫秒。500 个字 = 5-15 秒
两个阶段的对比
| Prefill | Decode | |
|---|---|---|
| 做什么 | 处理用户输入,吐第一个字 | 循环生成后续每个字 |
| 一次处理多少字 | 10-1000 个(用户全部输入) | 1 个 |
| 能不能并行 | 可以(输入已知) | 不能(必须串行) |
| GPU 利用率 | 60-80% | 1-5% |
| 瓶颈 | 算力 (compute-bound) | 搬运 (memory-bound) |
| 用时(典型请求) | 100-200ms | 5-15 秒 |
整个推理领域的"原罪"
一个典型请求:Prefill 100-200 ms,Decode 5-15 秒。
95% 以上的时间花在 Decode 阶段,而 Decode 阶段 GPU 算力闲着 95%。
整个推理加速领域所有技术,都在解决一个问题:怎么把 Decode 阶段那 95% 闲置的算力用起来。
三个最常见的误解,必须校正
误解 1: "Prefill 已经喂给模型了,为什么还要 Decode" 校正:Prefill 只处理了用户的输入 prompt,只产出了第一个回答 token。后面所有的回答 token 都要靠 Decode 循环生成。 类比:你问朋友一个问题。 Prefill = 朋友"听明白你的问题",并说出第一个字"我" Decode = 朋友继续说"觉得...这件事...应该...这样..."一个字一个字往外蹦
误解 2: 模型一次性输出整段回答 校正:LLM 根本不知道自己接下来要说什么。它每次只能预测"下一个 token 的概率分布"。
误解 3: 觉得 Decode 是"在解码 Prefill 的结果" 校正:"Decode" 这个词翻译得不好。Decode 和 Prefill 做的是同一件事 —— 都是"过一遍模型,预测下一个 token"。区别只在于: Prefill: 一次同时处理多个 input token(并行处理已知的 prompt) Decode: 一次只处理 1 个新生成的 token(自回归约束)
1.5 KV Cache:让自回归能跑起来的关键
到这里你可能会问:生成第 500 个字的时候,模型怎么"记得"前面 499 个字是什么?
答案是 Attention 机制 —— 每生成一个新字,模型会"回头看"前面所有字,决定新字应该是什么。
问题:朴素做法太贵
如果每生成一个字都重新"回头看"前面所有字: 生成第 1 个字:算 1 个字 生成第 500 个字:重算前面 499 个字
总成本是 N² 量级的,N=500 时比"只算一次"贵 250 倍
这种成本下,ChatGPT 根本不可能存在。
解决:KV Cache
道理很简单:算过的东西,存下来,下次直接用。
具体来说,每个字会被模型算出两个东西: K (Key) = 这个字的"特征标签" V (Value) = 这个字的"内容信息"
每生成一个新字时,模型只需要算新字的 K 和 V,然后从 cache 里读出所有历史字的 K 和 V,做一次 attention。
复杂度从 O(N²) 降到 O(N)。这才让自回归生成在工程上可行。
代价:KV Cache 很占显存
每个字的 K/V 大约 320 KB。一个长对话的 KV Cache 可以占几十 GB。
| 场景 | KV Cache 占用 |
|---|---|
| 70B 模型,2K 上下文 | ~0.6 GB |
| 70B 模型,32K 上下文 | ~10 GB |
| 70B 模型,128K 上下文 | ~40 GB |
KV Cache 是后面所有显存优化技术的核心战场。PagedAttention、Prefix Caching、KV 量化、KV Offloading —— 全都在围绕 KV Cache 做文章。
1.6 Token 是什么
到现在为止我一直说"字"。实际上模型处理的最小单位不是字,是 token。
Token 不等于字或词
| 输入 | Token 数 | 怎么切的 |
|---|---|---|
| Hello | 1 | ["Hello"] |
| Hello, world! | 4 | ["Hello", ",", " world", "!"] |
| unbelievable | 2 | ["unbel", "ievable"] |
| 你好 | 2 | ["你", "好"] |
| 推理加速 | 4 | ["推", "理", "加", "速"] |
粗略规律: 英文:1 个 token ≈ 0.75 个单词 中文:1 个 token ≈ 1.5 个汉字
一个关键的商业事实:中文 token 效率低
同样一段话表达同样的意思,中文消耗的 token 比英文多 30-50%。
为什么?分词算法(BPE)基于训练语料统计,训练语料以英文为主,所以英文有大量"高频词组合"被合并成单个 token,中文大部分还是一字一 token。
对某 MaaS 平台的商业含义:如果按 OpenAI 的英文 token 定价标杆收费,中文客户实际可能是亏的(token 账单数字大,但 GPU 时间也多,毛利率低)。定价模型应该考虑中英文差异。
Input vs Output Token
Input Token = 用户输入的 token 数(被 Prefill 阶段处理) Output Token = 模型生成的 token 数(被 Decode 阶段生成)
Output Token 通常比 Input 贵 2-4 倍。原因你现在已经懂了:Input 走 Prefill,GPU 效率 60-80%,便宜;Output 走 Decode,GPU 效率 1-5%,贵。OpenAI、Anthropic、阿里都这样定价。
第一部分小结
你应该能用一句话回答下面这些问题:
Q: LLM 为什么慢? A: 因为大部分时间花在 Decode 阶段,Decode 是一个字一个字串行生成,每生成一个字都要把整个模型权重搬运一遍。GPU 算力实际只用了 1-5%。
Q: 为什么要 KV Cache? A: 因为生成每个新字都要"回头看"前面所有字,没有缓存的话计算量是 N²。KV Cache 让历史字的特征算一次就缓存下来。
Q: 显存为什么总不够? A: 模型权重占大头(70B FP16 就是 140 GB),KV Cache 是另一个大头,且按对话长度增长。
Q: 为什么 Output 比 Input 贵? A: 输入走 Prefill 阶段 GPU 效率高,输出走 Decode 阶段 GPU 效率低、成本高。
修订记录
| 日期 | 改了什么 | 为什么 | 谁 |
|---|---|---|---|
| 2026-08-05 | 从整篇拆成第 2/6 章,正文未改动 | 整篇 44 分钟读不完,拆成每章 20 分钟以内 | 工程 |