“模型回答得慢”还不够具体。可能是输入太长、缓存占满显存,也可能是大量请求互相等待。先分清发生在哪一步,优化才有方向。
沿着一次请求走
输入文本 → token IDs → prefill → 第一个 token
↓
更新 KV cache ← decode → 采样下一个 token
↓
停止并回收状态
这是自回归生成的简化路径,不表示每个服务的调度方式都相同。Prefill 处理已有上下文;decode 利用缓存继续生成。采样策略决定选哪个 token,缓存策略决定保存与读取哪些状态,不是同一个问题。
名字相近,改的东西却不同
| 方法 | 主要改变什么 | 不能因此推断什么 |
|---|---|---|
| Temperature / top-p | 如何从输出分布选 token | 随机性更强不等于能力更强 |
| KV cache | 复用前缀的 keys / values | 缓存不等于后续 token 不再读历史 |
| MQA / GQA | KV heads 的数量与共享方式 | 显存减少比例不等于端到端加速比例 |
| RoPE / YaRN | 位置表示及其长上下文处理 | 能接收长输入不等于能利用其中的证据 |
| NoPE | 不另加显式位置编码(positional encoding),检查顺序信息的其他来源 | 不等于没有顺序信息,也不等于免训练扩长 |
| FlashAttention | attention 计算中的数据搬运 | Dense attention 的所有配对没有消失 |
| PagedAttention | KV cache 的物理分配与共享 | 不等于把 attention 改成稀疏的 |
| MLA | 每个位置保存的表示 | 压缩状态和少读位置不是一件事 |
| 稀疏注意力 | 哪些 query–key 配对参与计算 | 被省掉的配对不一定都不重要 |
先读下面的生成与缓存,再看长上下文和高效注意力。已经懂 decoder 时,可以直接找你分不清的那一种机制。
本章目录
想知道实际用什么跑服务,读 vLLM 与 SGLang:把应用、引擎与算子分开,再比较 batching、前缀复用、HiCache 和压测方法。基础概念放在这里,完整产品的接线与分工放在工程实践。
想从头跟一次真实服务的处理过程,读一次 LLM 请求怎样跑完。它把输入处理、排队、缓存、模型计算和输出放在同一条线上,再用一个分块算例解释首 token 延迟(TTFT)和持续输出之间的取舍。已有模型部署经验,也可以直接看 KV 显存预算和缓存回收。
已经理解 decode 与缓存,想看怎样减少目标模型的调用轮数,可以接着读 DFlash 与 MTP:先跟一轮草拟和验证,再看拒绝、缓存回滚与成本。初学时不用先读完所有加速方法。
生成、长上下文与推理
10 篇区分如何选下一个 token、如何缓存状态,以及怎样少搬数据或少算配对。
01 · 生成与缓存6
知道 decoder 怎样预测 token 后,再分开看采样策略和 prefill / decode 的计算。
02 · 长上下文与高效注意力4
按改变了什么来比较:位置编码、数据搬运、缓存布局、状态压缩,还是读取哪些位置。
一个小小的性能判断
假设一个请求先等 800 ms 才收到首 token,之后每个 token 间隔 20 ms。这两段时间回答的问题不同:前者可能涉及排队、prefill 和首步生成,后者更接近持续 decode 的体验;小 batch 时它为什么主要受显存带宽限制,见 decode 的 roofline 算例。只报平均 tokens/s,会把两种等待混在一起。
如果输入变长,先看 prefill 与缓存读取;如果并发增加后首 token 变慢,检查排队、调度与资源竞争。这个例子只是说明怎么拆测量,不表示某个组件已被诊断为瓶颈。
| 比较时要固定 | 同时报告 |
|---|---|
| 模型、权重、tokenizer、精度 | 输出质量与数值容差 |
| 输入/输出长度分布、并发条件 | 首 token 延迟、token 间隔、端到端延迟 |
| 硬件、batch、缓存状态 | 有效吞吐、峰值显存与尾部延迟 |
训练端的内存问题放在预训练与训练工程,不会与这里的推理缓存混成一张清单。具体模型版本也要回到它的报告和实现核对。
本页术语 1
- 位置编码 positional encoding
- 把「第几个 token」的信息注入表示