推理服务:自建还是调 API,以及 KV Cache 这本账

T6-1模块 6 · 部署与成本面试权重 更新于 2026-08-19
关联题目Q6-01Q6-02Q6-03

这篇学完你能回答什么

  1. 直接调 API 和自建开源模型推理,这笔账到底怎么算?什么时候自建才划算?
  2. vLLM 为什么快?PagedAttention 和 continuous batching 各自解决什么问题?到了 2026 年,这个答案还成立吗?
  3. KV Cache 是什么?为什么上下文一长,显存就爆、吞吐就塌,而 GPU 算力却一直闲着?

从一个真实故障讲起

一个企业文档问答服务,单张 H100 跑 Llama-3.1-8B,用 vLLM 起服务。压测阶段用的是内部准备的样例,平均 8K 上下文,能稳定跑 50 多路并发,P95 首字延迟 400 毫秒出头。团队据此算出"一张卡够撑到 DAU 三万",把容量规划写进了立项文档。

上线两周后来了一批客户,用法是把整本产品手册直接传上来问。监控上的现象很怪:

  • GPU 的算力利用率一直在 20% 上下晃,从来没打满过
  • 但请求排队时间从 50 毫秒涨到 12 秒
  • 日志开始刷 vLLM 的 preemption 警告
  • 实际同时在跑的请求数,从 50 多掉到了个位数

团队第一反应是加卡。加到两张,排队时间只降了不到一半。第二反应是"模型太大了",换成 3B,好一点,但没解决。

真因是一行算术。上下文从 8K 拉到 128K,每条请求的 KV Cache 从 1 GiB 涨到 16 GiB。这张 80 GB 的卡刨掉权重(16.1 GiB)和激活与临时缓冲,能留给 KV Cache 的约 54 GiB——8K 时装得下 50 多条并发,128K 时只装得下 3 条。序列长 16 倍,并发掉 16 倍,吞吐跟着掉 16 倍。而算力单元始终是闲的,所以加卡只能线性地多加那三条,加不出数量级。

三层教训,恰好是本篇的三条主线:

  • 长上下文的瓶颈是显存和带宽,不是算力——"加卡"是最贵也最低效的一条路;
  • 容量规划不能用"压测能跑多少并发",要用 goodput(满足延迟约束的有效吞吐);
  • "自建还是调 API"这笔账,本质上算的就是你有没有本事把卡的利用率喂到足够高

闲着的是算力,不够的是显存
压测 8K 稳跑 50 多路,据此写进容量规划;上线两周后客户开始传整本手册

  1. 压测 8K,稳跑 50 多路

    P95 首字 400 毫秒出头,写进立项文档

  2. 客户传整本产品手册

    上下文从 8K 拉到 128K

  3. 每条 KV:1 → 16 GiB断点

    54 GiB 的 KV 池只装得下 3 条

  4. 排队 50 毫秒 → 12 秒

    日志开始刷 vLLM 的 preemption 警告

  5. 加到两张卡

    排队只降了不到一半,换 3B 也没解决

上下文长度8K128K —— 整本手册直接传上来
单条请求的 KV Cache1 GiB16 GiB,顶得上一整份 8B 权重
同一张卡的并发50 多条约 3 条 —— 长 16 倍,并发掉 16 倍
排队时间 / 算力利用率50 毫秒 / 打不满12 秒,算力始终在 20% 上下晃
「加卡」在这里是最贵也最低效的一条路:多加一张,只是线性地多加那三条,加不出数量级。真正该改的是容量规划的口径 —— 别用「压测能跑多少并发」,要用 goodput。

核心概念:先打比方,再给定义

KV Cache(键值缓存)。模型每生成一个字都要"回看"前面所有字,不缓存的话生成第 1000 个字时要把前 999 个重算一遍,总计算量是平方级的。KV Cache 把每个 token 的 Key / Value 向量存下来供直接查表。一句人话:用显存换算力,这笔交易几乎总是划算的——代价是显存变成了新瓶颈。

prefill / decode(预填充 / 解码)。一次请求分两段:prefill 把整个 prompt 一次喂进去算出全部 KV,一步处理几千个 token;decode 逐个吐字,每步只处理 1 个 token。像把一整箱货一次搬上传送带,和从箱子里一粒一粒往外掏。这两段性能特征完全相反,是本篇几乎所有结论的源头。

continuous batching(连续批处理,又叫 in-flight batching、迭代级调度)。旧的 static batching 像跟团游,一车人得等最慢那位逛完才能走;它像急诊分诊,谁看完谁走,空出的床位立刻给下一位。定义上是把调度粒度从"一次请求"降到"一次迭代"。

PagedAttention(分页注意力)。操作系统的虚拟内存分页搬到 KV Cache 上:不给每条请求预留一整块连续显存(那必然要按"最多会生成多长"预留),而是切成固定大小的 block 按需分配,共享前缀的请求还能指向同一批 block。

goodput(有效吞吐)在满足延迟约束的前提下每秒能完成的请求数。一句人话:throughput 是"你跑了多少",goodput 是"其中有多少是用户还愿意等的"。


一箱一次搬完,一粒一粒地掏
一次请求分两段,性能特征完全相反 —— 本篇几乎所有结论都从这里长出来

一整箱货一次上传送带

一步就把整箱搬完

搬得动,是因为一次搬得够多

对应
prefill · 预填充

一步处理几千个 token

算术强度 ≈ 这一步的 token 总数;4000 ≫ 295 → compute-bound(卡算力)

一次算出全部 KV单条长请求就能打满 GPU
从箱子里一粒一粒往外掏

每次只掏出一粒

手快没用,来回那趟路才是瓶颈

对应
decode · 解码

每步只处理 1 个 token

算术强度 ≈ 并发数;batch=32 时 32 ≪ 295 → memory-bound(卡带宽)

每步重读权重与整个 KVbatch=512 又变回卡算力
KV Cache 是这两段共同的前提:不缓存,生成第 1000 个字要把前 999 个重算一遍,总计算量是平方级的。用显存换算力这笔交易几乎总是划算 —— 代价是显存变成了新瓶颈。

原理拆解

一张卡能跑几条,是除出来的
公式里唯一会写错的是 H_kv:Llama-3.1-8B 有 32 个注意力头,只有 8 个 KV 头

一行必须背对的公式
KV_bytes2×L×H_kv×D_head×S×B×P
代进官方 config
Llama-3.1-8B32 层 · 8 KV 头 · 128
Llama-3.1-70B80 层 · 8 KV 头 · 128
DeepSeek-V3 · MLA结构不同,另算一套
每 token 要存多少
128 KB / 320 KBMLA 的 V3 只要 68.6 KB
一张 H100 能留多少
剩余法分配KV 池 ≈ 54 GiB73.2 预算刨权重 16.1
除出来的并发数
8K → 54 条约 44 万 token 的容量
128K → 3 条开篇那个故障
手算一遍(H100 80GB 跑 8B,bf16,gpu_memory_utilization 0.92)
算什么怎么算得数读法
每 token 的 KV2 × 32 × 8 × 128 × 2 字节128 KBH_kv 写成 32 就错 4 倍;70B 是 64 比 8,错 8 倍
128K 单条要多少128 KB × 13107216.0 GiB顶得上 16.1 GiB 的一整份权重
卡上留给 KV 多少79.6 × 0.92 − 16.1 − 约 3≈ 54 GiB权重与激活先扣,KV 走剩余法
8K 能并发几条54 GiB ÷ 1 GiB≈ 54 条54 GiB ÷ 128 KB ≈ 44 万 token
128K 能并发几条54 GiB ÷ 16 GiB≈ 3 条长 16 倍,并发掉 16 倍,吞吐跟着掉 16 倍
FP8 KV 何时才划算存储减半,每 token 成本降到 54%约 7000 token 打平短上下文下反而更慢,所以默认不开

瓶颈要分两段答:prefill 一步塞进 4000 个 token,4000 ≫ 295 → 卡算力;decode 每步只出 1 个 token,算术强度 ≈ 并发数,batch=32 卡带宽,batch=512 又变回卡算力 —— 「decode 卡带宽」是关于 batch size 的陈述

带宽账(H100 的 HBM 3.35 TB/s):batch=1 / 8K 每步读 17.1 GiB → 最快 5.5 ms;128K 读 32.1 GiB → 10.3 ms;batch=32 / 32K 读 144.1 GiB → 46.2 ms,KV 占 89% 流量

讲吞吐塌陷要用并发数,不要用显存 GB。「同一张卡,上下文长 16 倍,并发掉 16 倍」这一句比任何显存曲线都有说服力 —— 而这段时间里算力单元自始至终是闲的。

一、KV Cache 到底占多少显存

标准公式(这一行必须背对):

原文示意
KV_bytes = 2 × L × H_kv × D_head × S × B × P

  2      :K 和 V 各存一份
  L      :层数           num_hidden_layers
  H_kv   :KV 头数        num_key_value_heads   ← 不是注意力头数!
  D_head :头维度         head_dim
  S      :序列长度(prompt + 已生成)
  B      :并发请求数
  P      :精度字节数     bf16=2, fp8=1, int4=0.5

H_kv 是最容易写错的地方。 不少资料写的是注意力头数,因为它们举的例子是 Llama 2 7B——MHA 模型,两个数恰好相等。换成现代 GQA 模型就会错得离谱:Llama-3.1-8B 是 32 个注意力头但只有 8 个 KV 头,写错就是 4 倍;70B 是 64 比 8,写错就是 8 倍。

代入具体数字(bf16,参数取自官方 config):

模型 L H_kv D_head 每 token KV
Llama-3.1-8B 32 8 128 128 KB
Llama-3.1-70B 80 8 128 320 KB
DeepSeek-V3(MLA) 61 68.6 KB

一个值得记住的对照:Llama-3.1-8B 的权重是 16.1 GiB,而它在 128K 上下文下,batch=1 的 KV Cache 就是 16.0 GiB——一条长请求的 KV,顶得上一整份模型权重。

再看显存怎么分(H100 80GB 跑 8B,vLLM 的 gpu_memory_utilization 默认 0.9,截至 2026-08 主线已调到 0.92):

原文示意
┌──────────────── H100  80 GB ──────────────────────────┐
│ 预算 = 79.6 × 0.92 = 73.2 GiB                          │
│  ├── 模型权重      16.1 GiB  ████                      │
│  ├── 激活+CUDA图    ~3 GiB   █                         │
│  └── KV Cache 拿走 ~54 GiB   ████████████████          │  ← 剩余法分配
│                                                        │
│  54 GiB ÷ 128 KB = 约 44 万 token 的缓存容量           │
│     8K 上下文  →  可并发 ~54 条                        │
│   128K 上下文  →  可并发  ~3 条     ← 开头那个故障      │
└────────────────────────────────────────────────────────┘

讲"吞吐塌陷"要用并发数讲,不要用显存 GB 讲。「同一张卡,上下文长 16 倍,并发从 54 掉到 3」这一句比任何显存曲线都有说服力。

二、为什么瓶颈分成两段

判断一个计算卡算力还是卡带宽,看算术强度(从显存搬一个字节能摊到多少次浮点运算)。对 Transformer 的矩阵乘法,它约等于这一步参与计算的 token 总数;H100 的临界值约 295 FLOPs/byte(峰值算力÷HBM 带宽)。

原文示意
prefill:一步塞进 4000 个 token   →  4000 ≫ 295  →  compute-bound(卡算力)
         推论:单个足够长的请求,一条就能把 GPU 打满

decode :每条请求每步只出 1 个 token
         算术强度 ≈ 并发数
         batch=32   →  32 ≪ 295   →  memory-bound(卡带宽)
         batch=512  →  512 > 295  →  又变回 compute-bound

所以"decode 是 memory-bound"是关于 batch size 的陈述,不是 decode 的本质属性。 这是面试里的强分水岭,也直接推出下一层:vLLM 官方明确说投机解码(speculative decoding)只在"中低 QPS、memory-bound"下有效——高 QPS 时 decode 已卡算力,多出的验证开销纯亏。

带宽账可以直接算(H100 的 HBM 带宽 3.35 TB/s,decode 每步要把权重和整个 KV Cache 读一遍):

场景(8B, bf16) 每步要读 理论最快 ITL
batch=1, 8K 16.1 + 1.0 = 17.1 GiB 5.5 ms
batch=1, 128K 16.1 + 16.0 = 32.1 GiB 10.3 ms
batch=32, 32K 16.1 + 128 = 144.1 GiB 46.2 ms(KV 占 89% 流量)

batch 一大、上下文一长,权重读取被 KV 读取彻底淹没——此时加算力毫无用处,只有减小 KV 体积或复用 KV 才有效。

三、PagedAttention 与 continuous batching 各解决什么

这两件事常被混为一谈,其实解决的是两个不同的浪费。

continuous batching 解决"等"的浪费。

原文示意
static batching(旧)
  req A ████████████░░░░░░░░  ← 早就完事了,但坑位不释放
  req B ████░░░░░░░░░░░░░░░░
  req C ████████████████████  ← 全车人等它
  新请求 ......................(只能等下一批)

continuous batching(现在)
  req A ████████████→ 走人,坑位立刻给 D
  req B ████→ 走人,坑位立刻给 E
  req C ████████████████████
  req D      ████████████
  req E          ████████

源头是 Orca(OSDI 2022),机制是迭代级调度 + 选择性批处理。Anyscale 那篇经典测评给的是相对朴素 static batching 约 8 倍吞吐,但有个必须说出来的条件:增益只在输出长度方差大时成立——如果所有请求输出长度都差不多,static batching 本来也没浪费多少。

PagedAttention 解决"占"的浪费。 论文(SOSP 2023)测出当时系统里真正存住 token 状态的显存只占 20.4%–38.2%,其余是三类浪费:为未来生成预留的槽位、按最大长度分配的内部碎片、分配器造成的外部碎片。分页后官方博客的说法是浪费降到"低于 4%"。

报倍数之前必须先问"跟谁比",这是这道题最有效的过滤器:

对比对象 倍数
vs 裸 HuggingFace Transformers 最高 24×
vs HuggingFace TGI(已有 continuous batching) 最高 3.5×
vs Orca(论文正文) 1.7–2.7×

张口就是"vLLM 快 24 倍"的人,等于承认自己没看过论文正文。

一个 2026 年的反转(截至 2026-08)。 vLLM 在 v0.25.0(2026-07-11)的 release notes 里写着「PagedAttention has been removed」——那份 V0 时代手写的 paged_attention_*.cu 内核确实被删了,因为 FlashAttention / FlashInfer 生态里的 paged 变体更快。但分块 KV 管理机制完全健在block_poolkv_cache_managerblock_table 全都在),只是改由上游注意力库消费 block table。准确的说法是:概念赢了并成为行业地基,那份专用内核输给了上游生态。 说"vLLM 不用 PagedAttention 了"是错的。

四、goodput:为什么 throughput 会骗人

DistServe 给了最好用的例子:系统 throughput 是 10 rps,但只有 3 rps 落在延迟约束内,goodput 就是 3——你按 10 rps 付了 GPU 的钱,只交付了 3 rps,有效成本是账面的 3.3 倍

而 throughput 与延迟之间只有一个旋钮:batch size。

原文示意
batch ↑ → 权重读取被摊薄 → 吞吐 ↑↑
       → 排队 + 单步计算量 ↑ → TTFT ↑、TPOT ↑
       → KV 占用 ↑ → 触发抢占重算 → 尾延迟 ↑↑

batch ↓ → GPU 大量空转 → 吞吐 ↓,但单请求延迟最优

所以唯一正确的优化目标是 goodput:它把延迟约束内生化,逼你在 SLO 边界上找最大 batch,而不是无脑推吞吐或压延迟。NVIDIA 的 AIPerf 已支持直接测,可同时对 TTFT 和 ITL 设阈值。


工程实践(截至 2026-08)

自建 vs 调 API:这笔账的四个维度

别一上来算单价,真正决定结论的是这四条:

维度 倒向调 API 倒向自建
利用率 流量有明显波峰波谷、日调用量不稳 有稳定的高基线负载,能把卡喂到 60% 以上
数据主权与合规 无特殊要求 数据不能出域、行业强监管、需要物理隔离
模型控制 用通用能力就够 要跑自己微调的权重、要改采样逻辑、要 LoRA 多租户
团队 没有专职推理工程 有人能读懂 preemption 日志、会调 chunk size

最容易被漏掉的是最后一条。 自建的隐性成本不是卡钱,是"有人得懂这个"——开头那个故障里两次试错的人力成本,够买很久的 API。

算账的三条硬判据:

  1. 用 goodput 而不是 throughput 折算单位成本。峰值吞吐除以 SLO 内的达标率,才是你真正能卖出去的量。
  2. 算利用率,别算峰值。一张卡包月的钱是固定的,跑 20% 和跑 80% 一样贵;API 按 token 计费,天然只为用掉的部分付钱——这是 API 最被低估的优势
  3. 自建要打平的不是 API 的标价,是打完折之后的价:批处理四家一律五折、prompt 缓存命中是输入价的 0.1 倍(详见 T6-4)。

推理引擎选型(截至 2026-08)

2026 年功能集已高度趋同——continuous batching、分块 KV、前缀缓存、chunked prefill、投机解码、P/D 分离三家都有。选型看的是别的:

场景 选型 理由
通用生产、模型覆盖最广、多种硬件 vLLM 社区最活跃,硬件矩阵最全,KV connector 生态最厚
高前缀复用(agent 多轮、长 system prompt、大规模 MoE) SGLang RadixAttention + 按最长共享前缀重排请求的调度
纯 NVIDIA 集群、要最新数值格式(FP4)首发 TensorRT-LLM Blackwell 特性首发,代价是硬件锁定

两个容易过时的认知要更正:

  • "TensorRT-LLM 必须提前 build engine、换模型要重编译"是 2023–2024 的老答案。 截至 2026-08,官方主推的是 PyTorch-native 架构 + trtllm-serve
  • vLLM 与 SGLang 的前缀缓存差别不在"有没有",在"调度器会不会为命中率重排请求"。 vLLM 是哈希索引 + LRU、调度默认 FCFS;SGLang 用基数树,把"最长共享前缀优先"做成一等公民并证明了最优性。

别问"谁更快"。 三家的相对性能完全取决于你自己的输入输出长度分布、并发度和 SLO,只能实测。上来就报某个倍数,是只读过没做过的最明显信号。

压 KV Cache 的四条路(按成熟度排序)

手段 效果 代价 / 什么时候不该用
GQA / MLA(结构级) GQA 压 4–16×(= Q 头数 / KV 头数);MLA 等效 2.25 组的 GQA,比 GQA-8 再压 3.5× 已是模型自带,选型时就定了。MLA 不能用现成 Llama 权重,内核生态窄
FP8 KV Cache 存储直接减半;decode 每 token 成本降到 bf16 的 54%(不是 50%,有反量化开销);128K MRCR 恢复 97–98% 有约 7000 token 的盈亏平衡线,短上下文下反而更慢;head_dim=256 的模型 TTFT 恶化约 1.6×。默认不开
前缀复用 / KV 卸载 命中时 TTFT 可降数倍 有带宽临界点:32 Gbps 互联下,输入要超过 256K 才比重算划算。低带宽时"搬 KV 比重算还慢"
KV 驱逐(H2O / SnapKV 等) 纸面能压到 6–25% 生产上基本不可用,见下

KV 驱逐为什么是这一章最值得讲的"反向判断":

  1. 生产用 FlashAttention,它从不把注意力分数矩阵写进显存——驱逐方法想看的打分信号根本不存在。参考实现是靠退回 eager attention 绕过的,这在生产里等于不可用。
  2. 分页布局下,驱逐 90% 的 token 几乎释放不了显存:幸存者散落在几乎每个 block 里,块不空就不回收。
  3. 现有 benchmark 普遍是"问题已拼进上下文之后"才压缩,真实部署却是"先压缩、后来问题"。在公平设定下,部署最广的 SnapKV 平均输给"保留开头 + 最近窗口"这个最朴素的基线

避坑清单

  • max_num_batched_tokens 是跷跷板:小(如 2048)ITL 好、TTFT 差;大(>8192)吞吐好。想清楚你在优化哪个。
  • 看到 preemption 警告就别再调延迟了,先看 KV Cache 占用率——那是显存不够,不是调度问题。
  • 前缀缓存在 vLLM V1 默认开启,命中率为 0 时吞吐损失也小于 1%;但分布式下真正的杀手是路由——负载均衡器把同前缀请求打散到不同实例,缓存局部性就没了。
  • 别把"KV 卸载"和旧的"GPU↔CPU swap"搞混:后者为处理抢占而生、在 vLLM V1 已被移除(抢占直接重算),前者是为提高跨请求命中率。

决定这笔账的从来不是单价
四条里最容易被漏掉的是最后一条 —— 自建的隐性成本不是卡钱

自建 vs 调 API:这笔账的四个维度
维度倒向调 API倒向自建
利用率流量有明显波峰波谷、日调用量不稳有稳定的高基线负载,能把卡喂到 60% 以上
数据主权与合规无特殊要求数据不能出域、行业强监管、需要物理隔离
模型控制用通用能力就够要跑自己微调的权重、要改采样逻辑、要 LoRA 多租户
团队最容易被漏掉没有专职推理工程有人能读懂 preemption 日志、会调 chunk size
经验值与避坑(截至 2026-08)
算账三判据
用 goodput 而不是 throughput 折算单位成本;算利用率别算峰值;打平的是折后价
引擎选型
通用生产 vLLM;高前缀复用(agent 多轮、大 MoE)SGLang;要 FP4 首发 TensorRT-LLM
别问谁更快
三家功能已高度趋同,相对性能取决于你的输入输出长度分布、并发度和 SLO,只能实测
FP8 KV Cache
存储直接减半、decode 每 token 降到 54%;盈亏平衡线约 7000 token,默认不开
KV 驱逐别上生产
FlashAttention 不写注意力分数矩阵;分页下驱逐 90% 也释放不了显存;SnapKV 输给最朴素基线
看到 preemption
先看 KV Cache 占用率 —— 那是显存不够,不是调度问题,别再去调延迟参数
自建要打平的不是 API 的标价,是打完折之后的价:批处理四家一律五折、prompt 缓存命中是输入价的 0.1 倍。而 API 按 token 计费天然只为用掉的部分付钱,这是它最被低估的优势。

面试视角

三道题连着问,答空一环就没下文
决策 → 引擎 → 瓶颈,一路下沉;链条上任何一环答得空,后面就不问了

  1. 别先报单价先说这笔账取决于四件事:利用率、数据主权、模型控制、团队
  2. 用 goodput 收尾「我们按 goodput 折算单位成本,不是按压测峰值」
  3. vLLM 拆成两件事continuous batching 治「等」,PagedAttention 治「占」
  4. 报倍数先说跟谁比vs 裸 HF 24×、vs TGI 3.5×、vs Orca 论文正文 1.7–2.7×
  5. KV 分两段再收尾容量限并发、带宽限单步;同卡 8K 跑 54 条、128K 只剩 3 条
只读过:这些回答会暴露你
  • 公式里写成「注意力头数」,或根本不知道 GQA 会改这个数
  • 「vLLM 快 24 倍」—— 不问跟谁比,等于承认没看过论文正文
  • 把长上下文慢一律归因为注意力的平方复杂度,然后提议加卡
  • 说「我们上了 H2O / SnapKV 压 KV,省了 90% 显存」
  • 谈自建 vs API 只报单价对比,不提利用率
真做过:这些细节骗不了人
  • 脱口而出 8B 每 token 128 KB、70B 320 KB,并说清 4 倍与 8 倍的来历
  • 知道 8× 只在输出长度方差大时成立,也说得出「内核删了、机制还在」
  • 把瓶颈拆成 prefill 卡算力、decode 卡带宽,用并发数而不是 GB 讲塌陷
  • 说得出 FP8 KV 的盈亏平衡线约 7000 token —— 知道它什么时候不该开
  • 分得清 throughput 与 goodput,算过「有效成本是账面的 3.3 倍」
满分那一句落在 2026 的现状上:vLLM v0.25.0 的 release notes 写着「PagedAttention has been removed」—— 删的是那份手写内核,分块 KV 管理机制完全健在。说「vLLM 不用它了」是错的。

面试官怎么问

这三道题通常连着问,构成一条从工程决策到底层机制的下沉链:

  1. 决策题(Q6-01):"你们自己部署还是调 API?账怎么算的?"——看你有没有算过账。
  2. 下沉到引擎(Q6-02):"自建用的什么?vLLM 为什么快?"——看你是照文档起了个服务,还是知道它在优化什么。
  3. 落到瓶颈(Q6-03):"上下文拉长之后遇到过什么问题?"——看你有没有把服务跑到过极限。

链条上任何一环答得空,后面就不问了。

答题结构建议

Q6-01(自建 vs API):别先报单价。先说"这笔账取决于四件事"——利用率、数据主权、模型控制、团队能力,再落到自己的场景。收尾一定要有一句:"我们按 goodput 折算单位成本,不是按压测峰值。"

Q6-02(vLLM 为什么快):先拆成两件事——continuous batching 解决"等"的浪费,PagedAttention 解决"占"的浪费,报数字时主动说"跟谁比"。想拿满分就补上 2026 的现状:内核删了、机制还在。

Q6-03(KV Cache):先给公式并强调是 KV 头数,再分两段答瓶颈(容量限制并发数、带宽限制单步延迟),最后用"同一张卡 8K 并发 54 条、128K 只剩 3 条"这个对照收尾。

分水岭信号

什么回答暴露只读过:

  • 公式里写成"注意力头数",或者根本不知道 GQA 会改这个数
  • "vLLM 快 24 倍"——不问跟谁比
  • 把"长上下文慢"一律归因为注意力的平方复杂度,然后给出"加卡加算力"的扩容方案
  • 说"我们上了 H2O / SnapKV 压 KV,省了 90% 显存"
  • 谈自建 vs API 只报单价对比,不提利用率
  • 把 P/D 分离说成"提升吞吐的优化"(官方文档原话是它提升吞吐,买的是 TTFT 与 ITL 可独立调)

什么证明真做过:

  • 能脱口而出"Llama-3.1-8B 每 token 128 KB、70B 每 token 320 KB",并解释为什么 8B 是 4 倍压缩而 70B 是 8 倍
  • 把瓶颈拆成 prefill 卡算力、decode 卡带宽,并指出**"decode 卡带宽"是关于 batch size 的陈述,并发推到 500 以上它也会变成卡算力**
  • 用并发数而不是显存 GB 来讲吞吐塌陷
  • 主动区分 throughput 和 goodput,并算过"有效成本是账面的几倍"
  • 说得出 FP8 KV 的盈亏平衡线(约 7000 token)——"知道它什么时候不该开"比"知道它能省一半"值钱
  • 谈引擎选型时拒绝报倍数,改成"取决于你的输入输出长度分布,得实测"

小结与延伸

三条主线收成一句话:推理服务的成本,本质是"这张卡的显存喂多满、算力用多久"的乘积。

  • KV Cache 把计算换成显存,于是显存容量决定并发多少,显存带宽决定每步多快
  • continuous batching 与 PagedAttention 分别消灭了"等"和"占"两种浪费,它们是地基不是加分项——2026 年单独夸这两件事已经拿不到分。
  • goodput 是唯一诚实的容量指标:跑得快但用户不愿等的那部分,你是白付了钱的。

延伸方向:本篇只讲单机视角,跨实例的 KV 复用与前缀感知路由是 2026 年真正的战场;成本侧的三刀归因T6-4

  • 上游概念:T0-1(token 与上下文窗口)、T1-4(prompt 缓存的设计)
  • 平级:T6-2(流式与实时链路)、T6-3(网关侧的限流、缓存与路由)
  • 下游:T6-4(token 成本治理与排查)
  • 关联题目:Q6-01Q6-02Q6-03;成本视角另见 Q3-23Q6-09

继续深入

本篇归属第 6 章「部署与成本」,去做这一章的题