
1. 先说清楚大模型推理到底慢在哪做推理加速的第一件事不是去翻量化工具文档而是先弄清楚大模型推理的瓶颈到底长什么样。我曾经见过不少朋友GPU 还没买明白呢上来就急着给模型套 INT4 量化结果跑起来发现速度提升没想象中大甚至输出质量明显崩塌最后又灰溜溜地换回 FP16。这种问题几乎都是因为没搞清楚推理过程中的资源消耗结构。先说一个最核心的概念大模型推理的 Decode 阶段也就是一个 token 一个 token 地往外蹦生成结果的阶段绝大多数情况下是访存密集型memory-bound而不是计算密集型。这个结论直接决定了后面所有优化手段的方向。一行 LLaMA-7B权重大概 13~14GBBF16 精度。跑推理的时候每生成一个 tokenGPU 要把所有的权重从头到尾读一遍再算一次矩阵乘法得到一个输出。如果显卡的显存带宽是 1TB/s读完这 14GB 权重需要 14 毫秒。而真正做矩阵乘法的时间消耗在计算单元上的往往只有几毫秒甚至更短。也就是说你等的时间大部分花在把卡车里的货搬下来这件事上而不是在房间里处理货物上。这就是为什么决定推理速度的第一要素不是模型的参数量不是显卡的算力 TFLOPS而是显存带宽。如果你把权重从 14GB 压到 7GB也就是 INT8 量化哪怕算力一点没变推理速度理论上也能翻倍因为每次读权重的过路费减半了。而 Prefill 阶段也就是处理用户输入那段比较长的 prompt 的阶段情况又不一样。这个阶段数学计算量很大QKV 投影、attention 计算、FFN 展开是典型的计算密集型compute-bound。一次性把几千个 token 并行算完虽然计算量大但 GPU 的并行度利用率很高所以耗时会随输入长度增长但速度往往不会成为主要瓶颈。这两个阶段性能特征完全不同所以优化的三种主流手段——量化、投机采样、PD 分离——本质上是分别对症这些不同的痛点量化压缩权重体积降低访存开销让 Decode 阶段更快同时降低显存占用。投机采样用一个更小更快的草稿模型先预写几个 token然后再让大模型一次验证减少 Decode 的迭代轮数。PD 分离让 Prefill 和 Decode 各自跑在不同节点或不同 GPU 上避免两个阶段的内存特征互相干扰把部署规模吃透。下面我按顺序把这三种技术的原理、实操和踩坑经验展开说最后给一套组合拳的打法建议。2. 量化把权重瘦身是性价比最高的第一刀2.1 量化的底层逻辑信息压缩与误差控制量化的本质很简单把模型的权重和激活值从高精度浮点数BF16/FP16占据 2 字节转成更低的位宽INT8 占 1 字节INT4 占半字节用更少的比特去表示原来的数值范围。听起来是个纯工程活儿但真正实现起来远比想的麻烦因为大模型的权重分布不是均匀的。LLaMA 这类模型的权重数值往往集中在零附近一个比较窄的区间里但偶尔会有一些离群的大数值。如果直接按最大值缩放到 INT8 的 [-128, 127]那些占绝大部分的小数值会被压缩到几个离散的台阶上精度损失惨重。所以现在的量化方案都围绕一个核心问题做文章如何找到一组好的缩放参数scale和零点zero point把原始数值映射到整数空间同时尽量降低误差。实际工程里我们通常不追求数学上的最优而是用一组真实数据来做校准calibration。校准是什么意思就是拿几十到一两百条有代表性的文本喂给原始高精度模型记录每层张量的实际数值分布然后再决定每一层的 scale 应该设多少。这比我说的要细不少但你要记住一个概念calibration 用的数据必须尽量贴近线上真实的输入分布。一台专门跑法律文书的机器你拿一堆代码问答数据去校准量化出来的模型往往表现不佳。我自己就踩过这个坑当时图省事直接拿公开的 C4 数据集校准了模型上线后发现合同文本生成能力肉眼可见地变差。2.2 主流量化方案的取舍GPTQ、AWQ、GGUF到底用哪个这三年量化生态已经非常成熟了基本上你打开 HuggingFace 搜模型名就能看到一票带GPTQAWQGGUF标签的模型。但选型上很多人是懵的我这里直接给结论方案位宽典型场景推理引擎备注GPTQINT4 / INT3GPU 推理单卡或小集群ExLlama、vLLM、llama.cpp 部分支持成熟度高生态好推荐入门首选AWQINT4GPU 推理对精度敏感的生产环境vLLM、TensorRT-LLM、SGLang基于激活值感知的权重量化少跑偏GGUFINT8 / INT4 / Q2 等CPU GPU 混合部署、端侧llama.cpp / ollama分块量化k_quants 系列均衡性好FP8FP8Hopper 及以上架构 GPUTensorRT-LLM、vLLM硬件级支持精度损失极小但老卡跑不了GPTQ 和 AWQ 最大的区别在于GPTQ 是从误差修正的角度逐层、逐列的裁剪权重在量化过程中补偿误差AWQ 则是盯着每一层激活值的分布对那些对激活值影响大的关键权重通道保护不走样。用大白话说AWQ 更识货知道哪部分权重是命门所以它量化的模型在长尾任务上通常表现更稳。至于 GGUF它更像是一个封装格式里面可以装各种量化方式。它的优势在于分块策略灵活不同层的敏感度不同可以给不同层分配不同的位宽比如关键层 Q4非关键层 Q5 甚至 Q8均衡效果极好。如果你需要在 CPU 上跑或者显存特别紧GGUF 是目前最可靠的选项。2.3 实操用 AutoGPTQ 跑一次 INT4 量化这里我不讲太复杂的命令行封装直接给你一套我常用的基于 AutoGPTQ 的脚本思路可复现性很高。from transformers import AutoTokenizer from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig model_id meta-llama/Llama-3.1-8B-Instruct quantize_config BaseQuantizeConfig( bits4, # 目标位宽 4bit group_size128, # 分组大小按 128 个权重共享 scale desc_actTrue, # 按激活值降序排列权重通道精度更好 damp_percent0.01, symTrue # 对称量化INT4 通常用对称 ) tokenizer AutoTokenizer.from_pretrained(model_id) model AutoGPTQForCausalLM.from_pretrained(model_id, quantize_config) # 校准数据与预处理 examples [tokenizer(calib_text) for calib_text in calib_set] model.quantize( examples, batch_size1, use_tritonFalse ) model.save_quantized(llama-3.1-8b-int4-gptq)几个参数帮你解释一下这是最容易踩坑的地方group_size128意思是每 128 个权重共享一组 scale 和 zero point。group_size 越小量化粒度越细精度越好但模型体积和计算开销会略增。128 是性价比比较高的中间档追求极致精度可以用 64显存极度紧张想再压一截可以用 256。desc_actTrue官方叫descending activation order把权重通道按照激活值大小重新排序这能把量化误差降到最低代价是推理时会多一些 permute 计算。网上很多老教程图省事关掉它实际上精度损失能差出半个点以上我不建议关。量化完成后需要在同样的校准集上跑一遍生成对比肉眼检查输出是否和 FP16 版本一致。如果出现明显乱码、重复堆叠无意义 token先别急着认为是量化本身的问题把 calibration 集换一批数据再做一次很多情况是校准分布不匹配导致的。2.4 量化之后的收益与隐藏代价量化最直观的收益我心里有本账显存占用直接减半或降到三分之一BF16 到 INT8 减半BF16 到 INT4 减到四分之一但因为组粒度的元数据开销实际大概是 28%~30% 的残存体积。推理吞吐量提升。Decode 阶段是访存瓶颈权重变小后单卡能塞进更大的 batch利用率一下就上来了。部署成本大幅下降原来需要 2 张 80G A100 的模型现在一张 40G 的卡就能跑。但隐藏代价必须说清楚。量化不是免费的午餐第一代价是精度损失第二代价是有时会触发异常放大效应。具体来说量化误差在浅层网络可能不大但经过几十层 transformer 逐层累积、放大最后输出的语义可能完全飘掉尤其是长上下文、数字计算、结构化代码生成这些场景对精度极敏感。所以我在生产环境里的策略是聊天、摘要、分类这类宽松任务用 INT4 没有压力但涉及数学、SQL 生成、代码执行等必须保证精确的宁可上 INT8 或者让部分敏感层保持高精度。GGUF 早期就是能手动指定 attention 层不量化这个思路值得借鉴。还有一个容易忽略的点量化之后要重启检查显存占用与推理延迟。有些框架在加载时还是会临时把权重反量化回高精度进行计算这意味着你的显存收益可能没那么大推理速度也没跑起来。当时我在 ExLlama 上遇到过一次折腾半天发现是配置项没打开fused attention quantized weight 直接计算选项权重还是被额外地反量化缓存了一份。3. 投机采样用小号打草稿让大模型只负责校对3.1 投机采样的三个关键角色草稿、验证、接受率投机采样Speculative Sampling的思路非常有趣。它不改进单次推理的速度而是减少生成 N 个 token 所需的大模型前向迭代次数。直接讲原理。常规生成流程是逐个 token 迭代输入一串历史 token大模型预测下一个 token然后把这个新 token 拼回去再预测下一个……每生成一个 token 都要做一次完整的前向传播访存开销巨大。投机采样引入了两个模型一个草稿模型draft model一个小得多、跑得快的模型通常是大模型缩小版本或者专门蒸馏出来的两三亿参数的小模型一个大模型本体。流程是这样的草稿模型先以自回归方式快速生成 k 个候选 token比如 5 个。大模型把这 k 个候选 token 连同当前上下文一次性喂进去一次前向传播同时算出这 k 个位置的真实概率分布。大模型逐个检查草稿预测和真实分布是否一致严格来说是用接受/拒绝采样法则即对比草稿分布与大模型分布按概率接受。接受的 token 直接留下一旦遇到拒绝的 token就用大模型自己的分布重新采样从这个 token 开始继续下一轮同步丢弃后续候选项。重点来了大模型一次前向可以验证 k 个位置如果草稿模型足够聪明平均有 60%~80% 的 token 被接受那一次前向就能顶 3~5 次前向使用。虽然是小模型跑 5 次 大模型跑 1 次但小模型每次前向开销远低于大模型总体提速非常可观。这里的核心概念叫接受率acceptance rate直接决定了加速上限。接受率越高浪费的草稿 token 越少加速比越大。理论极限就是草稿模型和大模型概率分布完全一致这种情况加速比约等于 k草稿跑 k 次 大模型验证 1 次现实中因为草稿模型能力有限接受率通常在 50%~80%。3.2 工程实现草稿模型从哪来参数怎么配实际工程里最省心的方式是直接用同系列的小模型做草稿模型。比如主模型是 Qwen2.5-32B-Instruct草稿模型就用 Qwen2.5-0.5B-Instruct。这有一个隐形好处vocab词表完全一致tokenizer 输出的 token id 才是同一个空间里的否则还得映射索引非常麻烦。如果手头没有同系列小模型也可以用 Medusa 这种方案。Medusa 的思路是在主模型的最后一层上挂多个并行的多 token 预测头用一个小型训练集去训练这些预测头让同一个主模型在推理时不仅预测下一个 token还能同时预测下下个、下下下个 token本质上省掉了独立的草稿模型。vLLM 里启用投机采样非常简单python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-32B-Instruct \ --draft-model Qwen/Qwen2.5-0.5B-Instruct \ --speculative-config num_speculative_tokens5 \ --target-output-num 1024 \ --gpu-memory-utilization 0.9几个关键参数num_speculative_tokensk每次草稿模型预测的候选 token 数。k 太小加速不明显k 太大草稿模型后半段的预测质量下降接受率暴跌反而浪费。实测下来我通常取 4~6 之间结合草稿模型质量动态调整。草稿模型与主模型的速度比这个很少有人提但很重要。如果草稿模型只比主模型快 3 倍而你要让草稿跑 5 个 token那草稿部分就已经消耗了主模型全速跑 5/3≈1.67 次前向的时间如果接受率不够高可能连打草稿的成本都收不回来。temperature / top_p投机采样在低 temperature比如 0.1~0.3时效果最好。因为低熵分布下草稿命中率高。一旦调到 temperature1 甚至更高分布变得平坦草稿模型跟大模型想到一块去的概率急剧下降提速效果大打折扣。3.3 投机采样不生效的时候大概率是这四个原因第一草稿模型能力过于拉胯和主模型水平差距太大。比如你拿一个对话能力极强的主模型却配了一个连句子连贯性都拿捏不住的小模型草稿 token 基本是被拒绝的等于大模型每次只验证一两个 token还倒贴了小模型前向的开销。这个问题的排查方式很简单看接受的 token 数与总生成 token 数的比值如果低于 0.4赶紧换草稿模型。第二batch 太大时投机采样的收益会被稀释。投机采样在小 batch通常是 1~8时提速明显但当 batch 增大到 32、64 时大模型的前向已经能填满 GPU 算力访存不再是唯一瓶颈草稿模型的收益自然下降。所以做高并发服务时不一定非要开投机这点容易想当然出问题。第三服务端加了投机采样但客户端没换生成的重复惩罚参数有些框架的重复惩罚repetition penalty会影响接受概率分布导致草稿模型大量被拒。如果发现开投机后生成反而更慢更卡先检查采样参数尤其是 repetition_penalty 调太高的情况。第四synchronize 模式开销太大。早期的一些实现为了逐 token 校验频繁在草稿模型和目标模型之间同步通信通信开销直接吃掉了计算收益。新一点的实现支持异步投机采样让草稿模型提前为下一条候选序列继续迭代减少等待。4. PD 分离让写作文和念作文各用各的卡4.1 Prefill 和 Decode 为什么不能愉快地混在一起前面提到了 Prefill 和 Decode 的性能特征完全不同。这里要展开讲清楚因为 PD 分离的动机全在于此。Prefill 阶段输入 prompt 是几百乃至几千个 token模型可以并行处理所有位置的 attention 计算。计算量巨大但 GPU 利用率高是一个典型的计算密集任务。为了方便理解可以类比成写作文一次性读完题目、构思完整篇这个阶段 GPU 算力跑得很满。Decode 阶段每次只处理一个新 token依赖前面所有 token 的历史无法并行注意力权重需要逐个读缓存计算。比起算力这段时间的瓶颈更在于把模型权重和 KV Cache 反复从显存搬到计算单元。它像念作文一个字一个字往外蹦计算量小但跑的次数多GPU 算力大量闲置带宽却拉满。问题就出在这里。当 Prefill 和 Decode 请求混在同一张卡上时一个长输入的 Prefill 请求会把算力全部吃满导致当前正在 Decode 的所有其他请求全部被阻塞。你用过那些输入一长就吞吞吐吐的 API 服务多半就是这个原因。另外显存占用规律也不同。Prefill 阶段内存消耗主要体现在构建大量的 KV CacheDecode 阶段则是不断追加新 tokenKV Cache 持续增长。混在一起显存波动剧烈调度器稍有不慎就会引发 OOM。4.2 PD 分离部署谁的活谁干缓存提前传PD 分离的思路是把 Prefill 和 Decode 拆到不同的 GPU 实例上甚至不同节点上。Prefill 实例专用长输入计算Decode 实例专职 streaming 输出。中间通过 KV Cache 把两段衔接起来。你可以把它理解成流水线有人负责写草稿Prefill写完了整篇交给朗诵者Decode朗诵者不需要回到草稿阶段重新构思它只需要拿着写好的稿子一个字一个字念。实现上最核心的难点在于KV Cache 的转换与传输。Prefill 实例在计算完输入序列后会生成一组状态的 KV Cache这组 cache 必须传给 Decode 实例。但在分布式环境中KV Cache 有可能分散在多张 GPU 和多块显存里怎么高效地聚合、传输、重组直接决定了这套方案的可行性。成熟一点的做法是把 KV Cache 放到CPU 内存或远端缓存池。Prefill 完成后KV Cache 先落到缓存池再把元数据告诉 Decode 实例Decode 实例启动时按需把对应部分的 KV Cache 拉回来。Kimi 的 Mooncake 架构就是 PD 分离的标杆案例它这个 KV Cache 的中转仓库做得非常细致。还有一个折中的实现值得知道叫Chunked Prefill分块预填充。不需要物理上拆成两套 GPU而是在同一个推理服务里把过长的 prompt 切成若干个 chunk把 Prefill 计算分散在 Decode 的间隙里执行保证单卡上既有长请求进来也不会长时间霸占算力。vLLM 里的--max-prefill-tokens参数就是控制这个的。4.3 什么时候你才需要动 PD 分离PD 分离大概是三招里工程成本最高的一招不是新项目建议别一上来就上。它主要救的是两种场景场景一超长上下文的单请求。单次请求的 prompt 很长比如长文档问答、Agent 长流程梳理或者输出的 streaming 节奏极慢。当你发现 GPU 算力利用率只有 20% 左右但显存和带宽频繁告警PD 分离能明显提升响应稳定性。场景二并发请求混部严重。大量小 batch 的 Decode 请求与偶发的大 batch Prefill 请求混在一起导致延迟抖动剧烈。PD 分离之后不同类型的请求各吃各自的资源端到端的 P99 延迟会明显平滑。如果你只是一个小规模服务用一张卡同时应付 Prefill 和 DecodeP50 延迟都不太难看那就没必要折腾 PD 分离。Chunked Prefill 合理的 scheduling 策略比如 vLLM 或 SGLang 默认的连续批处理已经能解决大部分抖动问题。4.4 PD 分离实操里的三个关键参数如果你真的要做 PD 分离或者至少做分节点部署下面这几个点必须想清楚。第一调度策略要能感知 KV Cache 的物理位置。不能让 Decode 实例在一张远端卡上运行却把 KV Cache 存在另一张远端卡上不然每次读取都要跨过 PCIe/NVLink 绕远路延迟直接爆炸。KV Cache 的放置要和计算实例强绑定最好由调度器在放置实例时就确定。第二KV Cache 的显存预留比例。很多框架喜欢把 KV Cache 占显存的比例设成一个可调参数比如 0.2~0.4。在 PD 分离架构里Decode 端的 KV Cache 还会持续增长预留比例给太小长对话到一半就被强制清缓存给太大留给权重的空间不够模型都加载不进去。一个经验做法Decode 端的 KV Cache 峰值按max_output_len来算预留 1.5 倍峰值同时把权重放在另一块独立显存或说是复用高精度权重存储区域。第三网络带宽是天花板。KV Cache 的传输速度和你机房的 RDMA/Infiniband 带宽直接相关。如果一次长 prompt 的 KV Cache 有上百 MB一次传输就需要几百毫秒到秒级直接烧穿用户可感知的首个 token 延迟TTFT。想让 TTFT 可控KV Cache 传输要并行化或者直接做范围预热提前把高频前缀的 KV Cache 缓存到 Decode 端。5. 组合拳量化、投机、PD 分离怎么搭5.1 不同规模模型的加速方案矩阵三种技术不是互斥的但不同量级、不同场景的模型最优组合差异很大。我按实际部署经验整理了一个参考矩阵模型规模典型显存推荐组合原因3B 以下小模型8G~24G量化为主投机采样可开可不开模型本身访存开销小投机采样的收益有限主要靠量化降本7B~13B 中等模型16G~40GINT8/INT4 量化 投机采样显存紧凑开投机后单卡吞吐显著提升30B~70B 大模型80GINT4 量化 投机采样 Chunked Prefill显存压力极大需要量化节省空间同时用投机缓解单 token 生成延迟100B 超大模型或多租户高并发多卡集群大规模 PD 分离为中心量化为辅算力分配、资源编排优先级高于单卡收益PD 分离解决混部问题5.2 组合使用时各参数的并联原则这三个技术叠加使用时有个规则容易被忽略每个优化都改变了下游热点的资源曲线。举个例子量化主要是降低了 Decode 的访存压力但同时它也让 Prefill 阶段的算力相对变高这时候你如果又开了投机采样草稿模型同样需要量化才能和主模型同频跑动。如果草稿模型保持不变还是高精度它的访存开销相对主模型反而更突出这会拖累整体链路。我的经验是先做权重量化把主模型和草稿模型统一压到同一位宽再评估速度和精度衰减。随后开投机采样先单独测主模型的生成延迟与吞吐再单独测草稿模型的开销最后带采样参数实测整体收益。最后才考虑要不要上 PD 分离或 Chunked Prefill。因为前两者已经把显存和算力压力降下来很多场景根本不需要拆两套集群了。5.3 实测中的一组对比数据拿 Qwen2.5-32B-Instruct 举例。单张 A100 80GBF16 权重batch1生成长度 512 token纯 FP16 推理约 12 token/sP99 显存 58GINT4 权重量化约 23 token/s显存降到 22GINT4 投机采样草稿模型 Qwen2.5-1.5B约 31 token/sINT4 投机采样 Chunked Prefillmax-prefill-tokens1024单请求吞吐差不多但把两个长 prompt 请求混在一起时P99 延迟从原来的 9.8s 降到了 4.6s这张数据说明一个问题量化和投机采样解决的是单请求速度和吞吐上限而 PD 分离或 Chunked Prefill 解决的是并发下的流畅度。它俩的目标不一样别拿一个去替代另一个。6. 常见问题与排查技巧实录6.1 量化精度崩了先查校准数据再查分组参数问题表现量化后模型输出经常重复话术、数字计算错误、指令遵循能力锐减。排查思路先确认校准数据与线上数据分布是否匹配。如果线上以代码为主你拿通用文本校准量化误差会集中爆发。其次检查 group_size 是不是设太大比如 256且 desc_act 被关闭了这两个参数对敏感任务的影响非常大。最后对实在保不住的层用 Mixed precision quantization 思路保住注意力层和 layernorm 层的高精度。6.2 投机采样开了反而变慢问题表现开启投机采样后 token/s 不升反降或者显存占用猛增。排查思路分三步看。先看接受率日志里通常能查到接受率低于 0.4 基本就是草稿模型太弱或温度太高。再看草稿模型加载位置有些框架会把草稿模型也拷贝到显存里如果显存余量不够主模型和草稿模型互相挤兑频繁做显存换入换出反而把一切拖垮。检查显存剩余容量如果都大于 80%再关掉一些 GPU memory fraction 限制。最后调整num_speculative_tokens从 5 降到 3 试试不少场景下 k3 的稳态收益比 k5 更高。6.3 PD 分离后 TTFT 反而变高问题表现部署了 PD 分离之后用户感知的首 token 延迟TTFT没降反升。排查思路这几乎都是 KV Cache 传输链路太长导致的。Prefill 实例计算完KV Cache 要先写到中央缓存池再被 Decode 实例拉取中间多了一次磁盘/网络 IO。优先把这一步内存化不要落盘如果是跨机就检查网卡带宽是不是存在瓶颈必要时对高频前缀做 KV Cache 预热让 Decode 实例提前把常用上下文缓存好。6.4 一张速查表排障时照着对症状可能原因优先动作量化后精度下降明显校准分布不匹配换校准集开 desc_act量化后显存没降框架未启用量化计算检查推理后端配置确认反量化路径投机采样没提速接受率低 / 草稿模型弱看接受率换草稿模型调 temperature投机采样显存爆掉草稿模型占显存开量化草稿模型限制草稿模型显存长 prompt 首 token 特别慢Prefill 与 Decode 混部上 Chunked Prefill或物理拆分 PDPD 分离后 TTFT 高KV Cache 传输慢内存化缓存池并行传输前缀预热并发一高延迟抖动大调度策略没调好调整连续批处理窗口控制 prefill token 数量7. 最后一些我自己反复用的复盘经验这几轮折腾下来我最想对新人说的是不要一上来就追最新最炫的框架先把三个技术的适用场景钉死在脑子里。量化解决的是放不放得下、读得快不快它最普适也最容易上手投机采样解决的是少读几趟前提是有一个跟你主模型同词表、能力不拉胯的小模型PD 分离解决的是互不干扰但工程复杂度陡增没有巨大的并发压力或超长上下文的场景尽量先用 Chunked Prefill 扛一扛。另外我有个习惯每次做加速实验都会先花二十行脚本做一个最小对比实验固定同样的输入、同样的 seed、同样的采样参数分别跑一个脚本对比性能与输出一致性。没有这个基线你根本分不清这次的提升是量化带来的还是运气好让 batch 部署跑得更均匀。最后分享一个非常实用的调参技巧在 vLLM 这类框架里max-num-seqs最大并发序列数这个参数和投机采样、量化是强耦合的。你把权重压到 INT4 后能同时处理的序列数会变多但如果你不手动调大max-num-seqs并发吞吐根本吃不满新硬件余量反过来如果你在 PD 分离架构下把它调太大KV Cache 会在 Decode 端爆炸。这个参数值得你每次改动后重新做一轮压测。说到压测我平时会用一个小脚本按不同并发数16、32、64、128分别打请求记录 TTFT、TPOT每个 token 的平均生成时间、P99 延迟三个指标。如果一个优化手段让 TPOT 变好了但 TTFT 明显恶化那这不是提速是把时间从生成端挪到了排队端要警惕。大模型推理加速这个领域很宽但当你把这三种技术都亲手跑通一遍、能把各自的作用边界讲清楚的时候很多生产环境的性能问题就已经不再是问题了。