K8s Lab 把当前仓库文档整理成一个可阅读的网页站点

Repository Reading Site

第二十一课:大模型推理、量化、KV Cache、vLLM、吞吐/延迟与部署发布链路原理

上一课我们把这些边界已经钉住了: 但到这里,你还没有真正走到“线上服务”。 因为训练结束之后,真正困难的问题才刚刚开始: 1. 为什么一个训练好的模型,不能直接等于线上服务? 2. 为什么同样是一个 7B 模型,有的机器能跑,有的根本装不下? 3. 为什么提示词一长,首 token 延迟就突然变高? 4. 为什么多用户并发一上来,吞吐和延迟会互相打架? 5.

Markdown21-第二十一课-大模型推理-量化-KV-Cache-vLLM-吞吐延迟与部署发布链路原理.md2026年4月13日 07:43

第二十一课:大模型推理、量化、KV Cache、vLLM、吞吐/延迟与部署发布链路原理

为什么这一课必须紧接着“训练产物”来学

上一课我们把这些边界已经钉住了:

  • checkpoint 不等于最终上线模型
  • adapter 不等于 base model
  • merged model 不等于 runtime package
  • 模型版本不只是一个权重文件名

但到这里,你还没有真正走到“线上服务”。

因为训练结束之后,真正困难的问题才刚刚开始:

  1. 为什么一个训练好的模型,不能直接等于线上服务?
  2. 为什么同样是一个 7B 模型,有的机器能跑,有的根本装不下?
  3. 为什么提示词一长,首 token 延迟就突然变高?
  4. 为什么多用户并发一上来,吞吐和延迟会互相打架?
  5. 为什么大家在讲推理优化时,总绕不开 KV Cache、continuous batching、PagedAttention、量化?
  6. vLLM 到底解决了什么问题,它又没有解决什么?
  7. 一个“能上线的模型”到底包括哪些工程产物?
  8. 从模型 registry 到发布、回滚、观测,这条链路怎么打通?

所以这一课的目标,不是教你“把某个推理框架跑起来”,而是要帮你建立一套真正能用于架构设计和线上排障的脑内模型。

如果你以后要做:

  • 大模型平台
  • 推理服务
  • GPU 容量规划
  • 线上延迟排查
  • 模型发布治理

这一课是绕不过去的。


先给你一张总图:训练产物如何变成线上推理服务

base model / adapter / merged model
  -> runtime package
  -> 推理引擎加载(如 vLLM)
  -> tokenizer / chat template 组织请求
  -> prefill 处理输入 prompt
  -> 建立 KV cache
  -> decode 逐 token 生成
  -> HTTP / OpenAI-compatible API 对外服务
  -> 指标采集与告警
  -> 金丝雀发布 / 回滚 / 版本治理

这一整条链里,至少有五层对象你不能混:

  1. 训练产物
  2. 运行时包
  3. 推理引擎
  4. 服务部署配置
  5. 线上发布版本

很多团队的问题,本质上就是这五层没有分开。


第一章:为什么“训练完成的模型”不等于“最终上线的模型”

上一课你已经知道:

  • checkpoint 更偏训练恢复
  • adapter 更偏微调增量
  • merged model 更偏部署友好
  • runtime package 更偏推理加载

但到了线上,还要再多想一步:

真正被发布的,不是“一个抽象模型概念”,而是一整套可加载、可运行、可观测、可回滚的服务单元。

也就是说,线上真正需要的通常不是单独一个:

  • model.safetensors

而是一整组东西:

  • 权重文件
  • config.json
  • tokenizer 文件
  • generation config
  • chat template 来源
  • engine 参数
  • 量化方式
  • 并行方式
  • 部署资源规格
  • 健康检查
  • 指标规则
  • 流量发布策略

所以“最终上线模型”在工程上更接近:

可推理的权重
  + 正确的 tokenizer
  + 正确的模板
  + 正确的引擎配置
  + 正确的资源规格
  + 正确的发布规则
  = 一个真正可上线的服务版本

这也是为什么两个团队即使拿着“同一个模型版本”,最后线上表现也可能完全不同:

  • 一个团队用 FP16
  • 一个团队用 AWQ INT4
  • 一个团队开了 prefix cache
  • 一个团队没有调 batch scheduler
  • 一个团队 2 卡 tensor parallel
  • 一个团队 4 卡 tensor parallel

它们在线上的:

  • 显存占用
  • 吞吐
  • 延迟
  • 稳定性
  • 成本

都会不同。

所以从现在开始,你要把“模型版本”和“服务版本”区分开来。


第二章:一条推理请求到底经历了什么

很多人理解推理,停留在一句:

用户发一个 prompt,模型回一个答案。

这句话几乎没有信息量。

真实链路更像这样:

用户请求
  -> API 网关 / 鉴权
  -> 请求进入推理服务队列
  -> tokenizer / chat template
  -> prompt tokens
  -> prefill
  -> 建立或扩展 KV cache
  -> decode
  -> 逐 token 流式返回
  -> 记录 metrics / tracing / logs

请注意,这里面至少有三个完全不同的耗时来源:

  1. 排队时间
  2. prefill 计算时间
  3. decode 逐 token 时间

如果你不把这三段拆开,你就根本不知道“慢”到底慢在哪里。

一个最容易犯错的观察误区

用户说:

这个模型响应很慢。

这句话可能对应三种完全不同的问题:

  • 首 token 很慢,但后面输出很快
  • 首 token 很快,但后面每个 token 都很慢
  • 模型本身不慢,但请求在队列里堵住了

这三种问题,排查路径完全不同。


第三章:Prefill 和 Decode 是两种完全不同的阶段

这是推理原理里最关键的边界之一。

什么是 prefill

prefill 指的是:

模型先把“已经给定的输入 prompt”完整跑一遍,得到后续生成所需的上下文状态。

例如用户输入:

请解释 Kubernetes 中 Deployment、ReplicaSet、Pod 三者的关系,并给一个 rollout restart 的排障思路。

模型不会一上来就直接“知道答案”。

它需要先把整段输入:

  • 分词
  • 编码
  • 过多层 Transformer
  • 为每一层准备后续生成要用到的 Key / Value 状态

这个过程,就是 prefill。

什么是 decode

decode 指的是:

在已有上下文的基础上,一次生成一个新 token,再继续生成下一个 token。

所以生成:

Deployment

这 10 个字符背后,可能对应多个 decode step。

每个 step 大致都会经历:

  1. 读取已有 KV cache
  2. 用当前 token 做前向计算
  3. 算出下一个 token 的概率
  4. 采样或贪心选出 token
  5. 追加到输出序列
  6. 把新的 K / V 再写回 cache

为什么必须把两者分开

因为 prefill 和 decode 的性能特征差别极大:

  • prefill 更吃 prompt 长度
  • decode 更吃输出 token 数
  • prefill 更影响首 token 时间
  • decode 更影响每 token 间隔和总完成时间

你可以先把它粗暴理解成:

  • prefill 决定“第一口气什么时候出来”
  • decode 决定“后面说话流不流畅”

这就是为什么线上常看两个指标:

  • TTFT: time to first token
  • ITL: inter-token latency

第四章:为什么 prompt 一长,TTFT 会明显变差

这是最常见的线上体感问题之一。

直观理解

如果用户只发一句:

解释什么是 Pod。

那 prefill 很短。

但如果用户发的是:

  • 很长的 system prompt
  • 很长的历史对话
  • 很长的 RAG 检索上下文
  • 很长的工具调用结果

那 prefill 负担就会迅速上升。

原理直觉

输入 token 越多,模型在 prefill 阶段要处理的上下文就越长。

这意味着:

  • 参与计算的 token 更多
  • 中间激活更多
  • KV cache 初始化更多
  • batch 中每个请求的“入场成本”更高

所以首 token 之前,系统要先把这段长上下文“吃进去”。

这就是 TTFT 上升的根本原因。

工程上最常见的诱因

TTFT 飙升,常见不是模型突然变笨,而是这类原因:

  • system prompt 过长
  • 对话历史不做裁剪
  • RAG 一次塞太多文档
  • 工具调用返回原始大 JSON
  • batch scheduler 把很多长请求挤在一起
  • GPU 显存紧张,导致调度受限

所以在 LLM 系统里,“控制输入长度”本身就是性能优化。


第五章:为什么 decode 阶段不像 prefill 那样看 prompt,而更看生成过程

decode 阶段已经不是“重新读整篇 prompt”了,而是在已有上下文上逐步续写。

但你不能误解成:

decode 就是常数时间。

这也不对。

因为每次新 token 生成时,当前 query 仍然要和已有上下文对应的 K / V 交互。

所以更准确的理解是:

  • 有了 KV cache 之后,不需要把旧 token 的完整前向反复重算
  • 但新 token 仍然需要参考已经缓存的上下文
  • 上下文越长、并发越多,decode 成本和显存压力仍然会上升

为什么用户感觉“后面越说越慢”

这通常可能来自:

  • 上下文持续增长
  • active sequence 数变多
  • KV cache 逼近上限
  • 调度器开始更频繁做取舍
  • GPU memory bandwidth 成为瓶颈

也就是说:

decode 不是免费的,它只是比“每次都重算整段上下文”便宜得多。


第六章:TTFT、ITL、吞吐量到底分别在看什么

如果你以后要和平台、算法、SRE 讨论线上效果,这几个词必须说准。

1. TTFT

TTFT = Time To First Token

表示:

从请求进入系统,到第一个输出 token 返回给用户所经历的时间。

TTFT 往往由这些部分组成:

排队
  + tokenizer / 模板处理
  + prefill
  + 第一个 decode step

TTFT 影响的是:

  • 用户是否感觉“系统卡住了”
  • 流式输出是否足够快地开始

2. ITL

ITL = Inter-Token Latency

表示:

连续两个输出 token 之间的平均时间间隔。

ITL 影响的是:

  • 用户感受到的“输出流畅度”
  • 流式回复是否顺滑

3. Throughput

吞吐量通常看:

  • 每秒处理的 request 数
  • 每秒生成的 output tokens 数
  • 每秒处理的 total tokens 数

吞吐量影响的是:

  • 单机利用率
  • GPU 成本摊薄效果
  • 高并发时系统能扛住多少流量

为什么它们经常互相打架

因为想要更高吞吐,通常会:

  • 聚更多请求一起算
  • batch 变大
  • GPU 利用率更高

但这样又可能导致:

  • 单个请求排队更久
  • TTFT 变差

反过来,如果你极度追求单请求低延迟:

  • 就会少攒 batch
  • 让请求尽快上卡

但这样又会降低:

  • GPU 利用率
  • 总吞吐

所以真实系统永远在做权衡:

更像“公交车按点发车”还是“人一到就发专车”。


第七章:为什么大模型推理不能只靠“静态 batch”

在传统离线推理里,静态 batch 很常见:

  • 先凑 32 条
  • 一起跑一轮
  • 返回结果

但 LLM 在线生成场景不一样。

因为每个请求:

  • prompt 长度不同
  • 生成长度不同
  • 有的很快结束
  • 有的还在继续输出

如果你还用简单静态 batch,就会遇到很多问题:

  • 短请求被长请求拖住
  • 某些序列已经结束,但 batch 还得等别人
  • GPU 利用不稳定
  • 队列里的请求得不到及时穿插

这就是为什么出现 continuous batching

continuous batching 的核心直觉是:

batch 不是一次性组好就不变,而是在生成过程中动态进出。

也就是说:

  • 某个请求 decode 完成了,可以退出
  • 新来的请求如果合适,可以插进来
  • 调度器持续维持 GPU 上有活干

这能显著改善:

  • 资源利用率
  • 总吞吐
  • 多请求混跑时的效率

但代价是:

  • 调度逻辑更复杂
  • KV cache 管理更复杂
  • 内存碎片问题更突出

第八章:KV Cache 到底是什么,为什么它这么重要

如果没有 KV cache,大模型推理几乎无法在在线聊天场景里高效运行。

先说最朴素的理解

KV cache 本质上是在保存:

每一层 Transformer 里,历史 token 对应的 Key 和 Value 表示。

这样当你生成下一个 token 时,就不需要把前面的 token 全部重新计算一遍。

为什么叫 K 和 V

因为 attention 机制里常会涉及:

  • Query
  • Key
  • Value

在生成时:

  • 新 token 的 query 会去“看”历史上下文的 key
  • 再结合对应 value 取回信息

所以历史上下文的 K / V 如果能缓存下来,后续步骤就能省掉大量重复计算。

你可以把它粗略想成什么

一种有帮助但不完全准确的类比是:

  • prefill 像先把整本资料做完索引
  • KV cache 像这本资料的多层索引结果
  • decode 像后面不断查索引,而不是重读整本书

KV cache 的最大价值

它解决的不是“模型能不能答”,而是:

模型能不能在可接受的延迟和成本下持续生成。


第九章:为什么 KV Cache 同时也是线上容量的核心压力源

很多人第一次学 LLM 推理时,以为显存大头只有模型权重。

这只说对了一半。

真正上线后,显存里通常至少有几个大头:

  1. 模型权重
  2. 推理框架和运行时开销
  3. KV cache
  4. batch 调度带来的中间缓冲

而 KV cache 的特点是:

  • 随上下文长度增长
  • 随并发请求数增长
  • 随层数增长
  • 随 hidden size 增长
  • 随数据类型字节数增长

所以你可以先记一个方向性的公式直觉:

KV cache 占用 ~= 序列数 × 上下文长度 × 层数 × 隐藏维度 × K/V × dtype bytes

不用把它背成精确数学题,但你一定要建立这个直觉:

长上下文 + 高并发,往往先把你打爆的不是算力,而是显存里的 KV cache。

这解释了很多线上现象

为什么明明权重能装下,服务还是顶不住?

可能不是模型加载失败,而是:

  • 请求一多,KV cache 不够
  • 上下文一长,batch 放不下
  • scheduler 被迫压小并发
  • 结果吞吐掉下去

所以在 LLM 时代,容量规划不能只问:

这个模型多少 B?

你还得继续追问:

  • 上下文多长?
  • 平均输出多长?
  • 并发多少?
  • KV cache 什么 dtype?
  • batch scheduler 怎么设?

第十章:PagedAttention 和 vLLM 到底在解决什么问题

KV cache 很有用,但也会带来一个现实问题:

内存管理会变得很难。

因为在线生成场景里,请求长度不整齐:

  • 有的 prompt 很短
  • 有的 prompt 很长
  • 有的生成 20 个 token 就停
  • 有的生成 1000 个 token 还没停

如果你用很朴素的连续内存方式来管理 KV cache,就容易遇到:

  • 大量碎片
  • 频繁搬移
  • 空间浪费
  • 调度困难

PagedAttention 的核心直觉

它借鉴了“分页”思路:

  • 不把一个序列的 KV cache 强行看成必须连续的一整块大内存
  • 而是拆成较小 block / page
  • 由映射关系把逻辑序列和物理块关联起来

这样做的好处是:

  • 更容易复用空闲块
  • 降低碎片浪费
  • 更适合动态请求进出
  • 更利于 continuous batching

那 vLLM 是什么

你可以先把 vLLM 理解成:

一个面向大模型在线推理的运行时引擎,它重点优化了调度、KV cache 管理和吞吐效率。

它的价值不只是“能跑模型”,而是它把很多线上难题作为一等公民来处理,例如:

  • continuous batching
  • KV cache block 管理
  • 更高吞吐的请求调度
  • OpenAI-compatible API 暴露
  • 对量化模型和并行配置的工程集成

但你也不能把 vLLM 神化

vLLM 解决了很多运行时问题,但它没有自动替你解决:

  • 模型好不好
  • prompt 设计对不对
  • 安全策略是否完善
  • 数据是否合规
  • 网关和业务超时是否合理
  • GPU 资源是否足够
  • 发布策略是否安全

所以 vLLM 是:

  • 推理引擎层的关键组件

但它不是:

  • 整个 LLM 平台的全部

第十一章:量化到底在压缩什么,为什么它总和推理绑定在一起

量化的根本目标,是让模型在推理时:

  • 更省显存
  • 更省带宽
  • 有时更快
  • 更容易上更便宜的硬件

最朴素的理解

原来权重可能是:

  • FP16
  • BF16
  • FP32

量化之后,可能变成:

  • INT8
  • INT4
  • FP8

本质上是在用更低位宽表示数值。

为什么量化在推理阶段这么重要

因为在线推理时,系统经常受限于:

  • 显存容量
  • 显存带宽
  • 可同时容纳的 batch
  • 可同时保留的 KV cache

如果量化能让权重更小,就可能带来:

  • 同一张卡能放下更大模型
  • 同样显存下能留更多 KV cache
  • 更高并发
  • 更低成本

但量化不是白捡的

量化通常会引入权衡:

  • 精度可能下降
  • 某些任务退化更明显
  • 某些算子或硬件兼容性有限
  • 某些量化格式需要特定引擎支持

所以量化从来不是一句:

压成 INT4 就好了。

真正要问的是:

  1. 压的是权重、激活还是 KV cache?
  2. 是训练时感知量化,还是后训练量化?
  3. 引擎是否支持该格式?
  4. 对我们自己的任务指标影响多大?
  5. 换来的是更低成本,还是更差体验?

第十二章:最容易混的量化边界

你至少要区分下面几类:

1. Weight-only quantization

主要压缩权重。

这类方式常见于:

  • 为了让模型更容易装进显存
  • 降低权重读取带宽

但要注意:

就算权重量化了,KV cache 仍然可能很大。

所以它不能自动解决“长上下文高并发”的全部问题。

2. Weight + activation quantization

不仅压缩权重,也压缩计算过程中的激活。

通常优化空间更大,但:

  • 工程复杂度更高
  • 精度风险也可能更大

3. KV cache quantization

直接压 KV cache,可以更直接打击长上下文和高并发带来的显存压力。

但代价也要看:

  • 精度损失
  • 引擎支持
  • 稳定性验证

4. Offline quantization vs runtime support

你还必须分清:

  • “模型已经被量化”
  • “推理引擎能正确加载并高效运行这个量化模型”

这是两件事。

也就是说:

  • 量化产物
  • 引擎兼容性
  • 部署参数

三者必须同时成立,线上才能跑稳。


第十三章:Runtime Package、Engine Config、Serving Deployment 不是一回事

这是上一课往下一课过渡时最关键的工程边界。

1. Runtime package 是什么

runtime package 更偏:

  • 模型可被推理引擎加载所需的产物集合

通常包括:

  • 权重
  • config
  • tokenizer
  • generation config
  • 特定运行时需要的附加元数据

它关注的是:

  • 能不能被加载
  • 能不能被推理

它不直接等于:

  • 线上怎么分配 GPU
  • 副本数多少
  • 流量怎么切

2. Engine config 是什么

engine config 更偏:

  • 让某个推理引擎以什么方式运行这个 runtime package

例如:

  • 用哪个引擎
  • tensor parallel 大小
  • dtype
  • quantization 参数
  • max model len
  • max num seqs
  • gpu memory utilization
  • 是否开启 prefix caching

这一层决定的是:

  • 性能形态
  • 显存利用
  • 容量上限

3. Serving deployment 是什么

serving deployment 更偏:

  • 在 K8s 或其他环境中,把这个推理服务真正跑起来的部署对象

例如:

  • Deployment / StatefulSet
  • Service / Gateway
  • GPU 资源申请
  • PVC / 对象存储挂载
  • readiness / liveness
  • autoscaling
  • node affinity

4. 线上发布版本是什么

发布版本还要再往上加一层:

  • 当前稳定流量指向谁
  • 当前 canary 流量指向谁
  • 告警阈值是什么
  • rollback 指向谁

所以你现在应该能分清:

模型产物
  != runtime package
  != engine config
  != deployment
  != rollout release

如果这些边界不清,团队很容易出现:

  • 一出问题不知道找谁
  • 版本号混乱
  • 服务回滚困难
  • 排查责任不清

第十四章:Prefill、Prefix Cache、KV Cache 也不是一回事

这三个词经常被一起提,但它们不是同一个概念。

Prefill

是阶段。

表示模型先处理已有输入上下文。

KV cache

是运行时状态。

表示历史 token 在各层里缓存下来的 Key / Value。

Prefix cache

是复用策略。

表示如果多个请求共享相同前缀,就尽量复用已经算过的 prefill 结果,而不是重复算。

所以它们的关系更像:

prefill 负责先把输入吃进去
  -> 过程中建立 KV cache
  -> 如果前缀重复,系统可能通过 prefix cache 复用一部分结果

这个边界很重要,因为很多性能优化讨论,说的不是一回事。


第十五章:为什么“加载成功”离“服务稳定”还很远

你可能见过一种过度乐观的说法:

模型已经能在 vLLM 里跑起来了,说明上线没问题。

这远远不够。

因为一个服务“能起”只代表:

  • 基本加载成功
  • 至少能处理少量请求

但离真正稳定上线,还差很多:

1. 并发下是否稳定

单请求跑通,不代表高并发跑得稳。

2. 长上下文下是否稳定

短 prompt 没问题,不代表长上下文不会爆显存或显著抖动。

3. 流式输出是否平滑

有的服务首 token 快,但后面输出卡顿。

4. 超时和取消是否处理正确

用户断开连接后,服务是否及时释放资源?

5. 观测面是否够用

如果线上慢了,你能不能快速回答:

  • 是排队时间长?
  • 是 prefill 慢?
  • 是 decode 慢?
  • 是 GPU 满了?
  • 是 KV cache 满了?

6. 发布和回滚是否可靠

如果新版本质量下降或延迟恶化,能不能快速切回旧版本?

所以:

加载成功只是“可运行性”,而稳定上线要求“可运营性”。


第十六章:从 model registry 到线上 endpoint,中间到底要经过哪些环节

这一段你必须能顺着讲出来。

训练 run 完成
  -> 产出 adapter / merged model / runtime package
  -> 模型 registry 记录 lineage、评测、审批状态
  -> 选择一个 runtime package 进入发布流程
  -> 生成或确认 engine config
  -> 生成 serving deployment
  -> 在预发环境压测和验收
  -> 金丝雀发布
  -> 观察 TTFT / ITL / 错误率 / 业务指标
  -> 放量或回滚

为什么 registry 不应该直接等于“线上在跑什么”

因为 registry 更偏:

  • 产物登记
  • 血缘和元数据
  • 评测结果
  • 审批状态

但线上发布还涉及:

  • 当前资源情况
  • 当前引擎参数
  • 当前流量策略
  • 当前依赖版本

同一个 model version,可能会对应多个线上服务版本,例如:

  • candidate-awq-int4
  • prod-fp16-low-latency
  • prod-awq-high-throughput

它们底层模型 lineage 可以相同,但运行策略不同。


第十七章:为什么线上要同时记录“模型版本”和“服务版本”

这是企业里极其重要的一条治理边界。

模型版本关注什么

  • base model 来源
  • 训练数据版本
  • 训练代码 commit
  • adapter / merged model / runtime package URI
  • 离线评测结果

服务版本关注什么

  • 当前镜像版本
  • 引擎参数
  • GPU 并行配置
  • autoscaling 配置
  • 网关超时
  • 安全策略
  • 当前灰度比例
  • 发布窗口和审批人

为什么不能只留一个版本号

因为同一个模型,可能反复以不同方式上线:

  • 第一次是 FP16
  • 第二次是 AWQ
  • 第三次把 max_model_len 调小
  • 第四次开了 prefix caching

如果你只留一个“模型版本号”,出了问题时你就很难回答:

  • 是模型质量变了?
  • 还是推理配置变了?
  • 还是部署策略变了?

第十八章:容量规划时,真正要问的不是“几张卡”,而是负载画像

很多团队做 LLM 容量规划时,只问:

这个模型需要几张 GPU?

这还远远不够。

更正确的问题应该是:

  1. 平均 prompt token 长度是多少?
  2. P95 prompt token 长度是多少?
  3. 平均输出 token 数是多少?
  4. 峰值并发是多少?
  5. TTFT 和 ITL 的目标值是多少?
  6. 是否流式输出?
  7. 是否多轮对话?
  8. 是否带 RAG,上下文增长多少?
  9. 是否用量化?
  10. 是否做 prefix cache?

为什么“负载画像”这么重要

因为一个同样的 7B 模型:

  • 纯短问短答
  • 长文总结
  • 多轮客服
  • 带大段检索上下文的 RAG

对系统的压力完全不是一个级别。

所以容量规划不是纯模型参数问题,而是:

模型大小 + 负载画像 + 服务目标 的联合结果。


第十九章:哪些指标最值得盯

线上大模型服务,如果只盯 CPU 和内存,基本等于没盯。

至少应该重点看这些:

1. 请求层

  • QPS
  • 并发请求数
  • 队列深度
  • 错误率
  • 超时率
  • 请求取消率

2. 体验层

  • TTFT P50 / P95 / P99
  • ITL P50 / P95 / P99
  • 完成时延
  • 每请求输出 token 数

3. 引擎层

  • active sequences
  • batched tokens
  • scheduler delay
  • prefix cache hit rate
  • KV cache usage

4. GPU 层

  • GPU utilization
  • 显存占用
  • HBM 带宽压力
  • 多卡通信瓶颈

5. 业务层

  • 用户成功率
  • 会话完成率
  • 用户中断率
  • 每次调用成本

为什么一定要多层一起看

因为只看单一层很容易误判。

例如:

  • GPU 利用率很高,不一定是好事,可能是队列已经堵死
  • GPU 利用率很低,也不一定是好事,可能是 batch 太碎

所以指标必须放到系统上下文里理解。


第二十章:最常见的线上坏味道

如果以后你做 LLM 平台,这些症状很常见。

坏味道 1:只看平均延迟,不看 TTFT / ITL 分拆

结果你知道“整体慢”,但不知道慢在:

  • 排队
  • prefill
  • decode

坏味道 2:只看模型能否加载,不做长上下文压测

结果上线后,一旦遇到真实大 prompt,立刻抖动。

坏味道 3:只做短基准,不做多并发混合负载

结果离线 benchmark 很好看,线上一拥塞就塌。

坏味道 4:只量化权重,却没重新评估任务指标

结果吞吐上去了,但回答质量明显掉了。

坏味道 5:模型版本和服务版本混成一个号

结果回滚和排障都非常痛苦。

坏味道 6:没有把 tokenizer / chat template 当成一等公民

结果同一权重,在不同服务上行为不一致。

坏味道 7:把 runtime package 当成最终部署清单

结果“模型文件是对的”,但服务规格、引擎参数、流量策略全丢了。


第二十一章:把这一条链讲顺,你就真正越过了“只会跑模型”的阶段

如果你要成长为架构师或 CTO,你应该能用自己的话把下面这条链完整讲出来:

训练阶段产出 checkpoint、adapter、merged model 和 runtime package,
但真正上线时,服务加载的不是抽象意义上的“模型”,而是某个具体 runtime package。

推理引擎会依据 engine config 把权重、tokenizer 和相关配置加载进来,
然后对用户请求先做 tokenizer 和模板拼装,
进入 prefill 阶段处理输入上下文,
建立或复用 KV cache,
再进入 decode 阶段逐 token 生成。

系统要同时权衡 TTFT、ITL 和吞吐,
因此常用 continuous batching、prefix cache、分页式 KV cache 管理等策略。

如果显存或带宽压力太大,还可能引入量化,
但量化是性能和精度之间的工程权衡,不是无代价优化。

最终,一个真正可上线的版本,不只是模型权重,
而是 runtime package、引擎参数、部署规格、观测指标和发布策略共同组成的服务版本。

如果你能把上面这段讲顺,并且能解释每个名词的边界,那你已经开始具备真正的平台思维了。


第二十二章:这一课最容易被记错的 12 个边界

最后我帮你把最容易混的地方再钉一遍。

  1. 训练产物不等于线上服务版本。
  2. merged model 只是部署友好形态,不等于完整发布单。
  3. runtime package 面向“可加载推理”,deployment 面向“可运行上线”。
  4. prefill 是阶段,KV cache 是状态,prefix cache 是复用策略。
  5. TTFT 看首 token 体验,ITL 看连续输出流畅度,吞吐看总体处理能力。
  6. 更高 batch 往往提升吞吐,但不一定改善单请求延迟。
  7. KV cache 解决重复计算问题,但也会带来显存容量压力。
  8. vLLM 是推理引擎层能力,不是整个平台治理方案。
  9. 量化解决的是容量和带宽压力,不保证业务质量一定不掉。
  10. 权重量化不等于 KV cache 压力同时消失。
  11. 模型版本记录 lineage,服务版本记录运行方式和发布状态。
  12. “能启动”只是起点,“可观测、可灰度、可回滚”才叫可上线。

本课配套样例

这一课建议你一定把样例目录也一起看掉:

建议你的阅读顺序是:

  1. 先读本课正文,建立“从 runtime package 到线上 endpoint”的总图。
  2. 再看 000506,理解模型版本、服务版本和部署对象如何衔接。
  3. 再看 020307,把 prefill、decode、KV cache 和观测指标串起来。
  4. 最后看 0408,理解量化和金丝雀发布为什么都是工程权衡。

如果你能把这四步走通,那你对“大模型如何真正变成线上服务”这件事,就不再停留在口号层了。