跳到主要内容

送到用户面前 — 一百个人同时用,怎么不排长队

这一章讲三件事: 生成第二个词为什么比第一个便宜、以及这件事的代价是什么; 一百个人同时提交请求时,时间到底花在哪儿; 以及第 11、12、13 三章的技法叠起来之后,一笔总账长什么样。

它在全书链条里的位置: 第 11 章压的是「装得下」,第 12 章压的是「训得起」, 这一章压的是「用得起」。 这三章合起来,才把一个「理论上有能力」的模型 变成一个「实际可部署」的模型。

书的开场话说得很直白: 不管我们的训练多优雅, 用户体验到这个模型的地方是推理。 不止一个构思良好、能力很强的模型,是因为推理慢、服务差而失败的。1

1. 先看现象:一百个坐席同时要信

回到那家健康保险公司。 第 12 章那个模型调好了、压好了,现在要上线:

上午 9 点,一百个理赔坐席同时点了「生成拒付说明信」。

第一封:2 秒出来。
第一百封:要等多久?

★ 这个问题的答案,取决于你把下面四件事做没做。
什么都不做的话,答案是「排队等前面九十九封写完」——
以每封 2 秒算,最后那个人要等三分半。

主走查(全章共用): 这一百封信。 每一节各砍掉这三分半里的一段,到第 7 节给出总账。 下面所有时间数字都是为演示编的,不是实测。

先说清楚这一段活为什么特殊

书专门解释了为什么通用的服务设施在这里不好使2:

图像模型那类负载语言模型这类负载
输入尺寸固定序列长度不定
一次前向就出结果一个词一个词地循环生成
主要在算大部分时间在等内存,而不是在算

最后那一条是这一章所有优化的共同前提:瓶颈在搬数据,不在算数据。

2. 顶层全景:四道优化各砍掉一段

一百个请求进来

① 每个位置算过的中间结果存下来复用 ← §3
│ 效果:生成第 2 个词比第 1 个便宜得多
│ 代价:这份缓存随对话变长而吃显存

② 把这份缓存按固定大小的页来管 ← §4
│ 效果:消掉碎片,同样的显存能塞下更多并发请求

③ 谁写完谁的位置立刻补进新请求 ← §5
│ 效果:显卡不再有空转的槽位

④ 让小模型先猜几个词,大模型一次性验完 ← §6
│ 效果:猜对就一次前进好几步

└──► §7:把 11、12、13 三章叠起来,算总账

图说:**前两道省的是显存,后两道省的是时间。**
它们互不冲突,现代的推理服务器通常四道全上。

3. 机制一:第二个词为什么比第一个便宜

现象

这件事你其实已经见过: 让模型写一篇长文,第一句话出来得慢,后面越写越顺。

它解决什么问题

回想第 02 章那个注意力:处理到某个位置时,这个位置要去看前面每一个位置。 而「去看」这件事,需要前面每个位置各自准备好两样东西—— 一样是「我是什么」(键),一样是「我带的是什么信息」(值)。

写第 1 个词: 前面有 200 个位置(提示词),各算一遍键和值
写第 2 个词: 前面有 201 个位置 —— 其中 200 个和上一步一模一样!
写第 3 个词: 前面有 202 个位置 —— 其中 201 个和上一步一模一样!
……
★ 不做任何事的话,每写一个词都要把前面全部重算一遍。

怎么做:把算过的存下来

在生成过程中,模型把已经算出来的键向量和值向量缓存起来,以避免冗余计算。3

这份缓存的名字就叫 KV cache(key-value cache,键值缓存)。 读者在任何一份推理服务的文档、监控面板、显存报错里都会撞见这个词,所以留名。

走查:那一百封信的第一段账

设定:提示词 200 个 token,每封信写 300 个 token(为演示编的)

没有这份缓存:
写第 n 个词要处理 200+n 个位置
写完 300 个词,累计处理约 200×300 + (1+2+…+300) ≈ 10.5 万个位置

有这份缓存:
写第 1 个词:处理 200 个位置(这一步叫「预填充」,一次并行算完)
写第 2 到第 300 个词:每步只处理 1 个新位置
累计约 200 + 299 ≈ 500 个位置

★ 差了约 200 倍。这就是「第二个词比第一个便宜得多」的全部原因。

(200 / 300 这两个长度是为演示编的;「缓存键值以避免冗余计算」是书里给的。)

代价:它会吃掉显存,而且越聊越吃

书在同一句话里就给了代价3:

但这份缓存随序列长度增长—— 而且当不同长度的请求陆续到来又陆续完成时,它会把内存搞得七零八落。

★ 这就兑现了第 11 章那条选型启发里那句「装得下要留出对话缓存和上下文窗口的空间」。

一个 4 位量化的 7B 模型,权重占 3.9GB。
一张 24GB 的卡看起来绰绰有余——

★ 但一百个并发请求各自带着自己的这份缓存,
而这份缓存的大小 ∝ 层数 × 每层的宽度 × 序列长度 × 并发数。
** 真正决定「能同时服务多少人」的,往往是这一项,不是权重。**

4. 机制二:把这份缓存按页来管

它解决什么问题

上一节末尾那句「七零八落」就是这一节要治的病。

❌ 朴素做法:给每个请求预留一块**连续**的显存,按「它最长可能写多少」来留

请求 A 预留 8000 个 token 的空间,实际只写了 300 个 → 浪费 96%
请求 B 写完退出 → 它那块连续空间被释放
请求 C 来了,需要一块稍大的连续空间 → 装不下,尽管总空闲量够
★ 这就是碎片:总量够,但没有一块连续的够大。

怎么做:借操作系统管内存的那一招

它把缓存按不连续的块来存,再通过一张页表把它们映射起来, 从而消掉碎片,并让不同请求之间可以高效地共享内存。3

这个做法的名字叫 PagedAttention(分页注意力), 它借的概念来自操作系统的虚拟内存——书自己就是这么说的3

★ 那个主意用一句话说:

程序不需要知道自己的数据在物理内存的哪儿,
它只管用「第几页」这个号码;
一张页表负责把号码翻译成实际位置。

→ 于是物理上零散的一堆小块,在逻辑上是连续的。
→ 于是「留多少」不必按最坏情况预估,写多少要多少。

书给的效果:在多请求负载上吞吐显著更高3

走查:那一百封信的第二段账

❌ 按最坏情况预留:每个请求预留 8000 token 的缓存空间
一张 24GB 卡刨掉 3.9GB 权重,剩 20GB
假设每 token 的缓存占 0.13MB(为演示编的)
→ 8000 × 0.13MB ≈ 1.0GB 一个请求
→ 只能同时服务 20 个人。剩下 80 个排队。

✅ 按页管:实际写多少占多少
每个请求实际用掉 500 token × 0.13MB ≈ 65MB
→ 同一张卡能同时服务约 300 个请求(显存这一侧不再是瓶颈)

★ 一百个人可以同时开始,而不是分五批。

(0.13MB 这个每 token 的缓存开销和 8000 这个预留长度都是为演示编的;
「按页管、用页表映射、消掉碎片」是书里给的机制。)

5. 机制三:谁写完谁的位置立刻补进新请求

现象:两个人的信长度不一样,短的那个要陪着等

先说清楚为什么要把请求打包一起算4:

一次只处理一个请求,会让显卡大部分闲着—— 计算单元空转,等着内存传输。 把很多请求一起处理,能让更多硬件忙起来,把内核启动和访存这些固定成本摊到更多有用的工作上。

但朴素的打包有一个很傻的浪费4:

序列长度不同时,朴素的批处理会把算力浪费在填充上。 如果一批里有 50、100、200 个 token 的序列, 短的必须被填充到和最长的一样长,于是算力花在了没有意义的填充符号上。

怎么做:在 token 这一级管这一批,而不是在整批这一级

不必等一批里所有序列都写完才开始下一批,而是在序列完成时把新请求加进这个正在跑的批里。 一个写了 50 个 token 就结束的请求,会立刻被一个新请求替换, 而不是让它的槽位空着、干等其他序列继续生成。4

这个做法的名字叫连续批处理(continuous batching,也叫动态批处理或迭代级批处理)5

走查:那一百封信的第三段账

一批 20 个槽位,每封信长短不一(为演示编的):
最短的 150 token,最长的 600 token,平均 300

❌ 整批一起开始、一起结束:
每一批的耗时由**最长的那封**决定 → 600 个 token 的时间
100 封 ÷ 20 个槽位 = 5 批 → 5 × 600 = 3000 个 token 的时间

✅ 谁写完谁的槽位立刻补人:
所有槽位几乎全程在干活
总工作量 = 100 封 × 平均 300 = 30000 个 token
÷ 20 个槽位 = 1500 个 token 的时间

★ 快了一倍。而且这一倍完全来自「不再空转」,不是来自算得更快。

(150 / 600 / 300 这三个长度和 20 个槽位都是为演示编的;
「在 token 这一级管批、完成即补位」是书里给的机制。)

顺带说另一类省法:不把那张大表实体化出来

这一类优化针对的是注意力计算本身6:

标准的注意力实现会把一些很大的中间矩阵实体化出来, 而这些矩阵的内存随序列长度按平方增长,限制了实际可用的上下文长度。

做法是重新组织这个计算,不再把中间结果实体化; 把若干步融合起来,并用分块的方式把数据留在快速的片上存储里, 而不是慢速的显存里。 结果:注意力快 2 到 4 倍,内存占用大幅下降。

这个做法的名字叫 FlashAttention。 它的后续版本进一步逼近了硬件的理论上限, 而且多数推理框架现在默认就开着它——它已经是标配,而不是一个可选的优化6

但这里有一条书专门写成警告的话

这一条值得单独抄出来,因为它是全书少数几条「别信通用建议」7:

不是所有版本都一样。 在某一代显卡上,厂商库里的标准注意力实现比第 2 版更快; 第 4 版是专为那一代设计的,比标准实现再快约 20%; 而在某型桌面级机器上,第 4 版可能不稳定、支持也不完整, 那里反倒是标准实现更好。

★ 永远在你的目标硬件上实测。

同样的口径也适用于选推理服务器7:

服务器强在哪代价
vLLM在很多模型上性能都很好要仔细配置才能在生产上稳定
TensorRT-LLM在 NVIDIA 硬件上性能顶尖需要编译步骤,而且支持的模型结构范围更窄
TGI生产就绪:连续批处理、流式输出、模型并行

书给的判据:选哪个取决于部署语境。 研究原型看重灵活,生产系统看重稳定与可观测,成本敏感的部署看重每块钱的吞吐。

6. 机制四:让小模型先猜,大模型一次验完

它解决什么问题

前面三道优化都没有改变一件事:大模型仍然是一个词一个词地吐。 而每吐一个词,那几百亿个参数都要被搬进计算单元一遍。

怎么做

用一个更小的草稿模型预测好几个 token,再让大模型并行地一次性验证它们。 如果草稿模型预测了 5 个 token 而大模型对这 5 个全都同意, 那么生成就前进了 5 个 token——所花的时间大致相当于生成一个 token。 预测错的时候,就采用大模型给出的那个正确 token,然后从那儿继续起草。8

这个做法的名字叫投机解码(speculative decoding)。

为什么这能省时间

★ 关键在第 1 节那句「大部分时间在等内存,而不是在算」。

大模型验证 1 个 token 和验证 5 个 token,
**搬运权重的次数是一样的**(都是把全部权重过一遍),
只是算的量多了 5 倍 —— 而算力本来就是闲着的。

→ 于是「验 5 个」几乎和「生 1 个」一样快。

它什么时候有用、什么时候没用

书给的边界很清楚8:

情况效果
输出可预测(草稿模型经常猜对)加速明显
输出不可预测退化成标准生成,不亏也不赚

走查上的样子: 拒付信是高度模板化的—— 「尊敬的投保人:您于 X 年 X 月 X 日提交的……」这种开头, 草稿模型几乎每次都猜得中这类任务是投机解码的最佳场景。

7. 机制五:三章的技法叠起来,一笔总账

这一节是第 11、12、13 三章的收口,也是书自己给这一整块起的名字:优化栈。

先说为什么这三章必须一起看

一个需要一整个显卡集群才服务得起的 700 亿参数模型, 对多数组织来说是一项理论上的能力,而不是一个可部署的东西。9

它们是可以叠的

书给了一条典型的组合路径10:

① 挑一个有能力的底座
② 压到 4 位,让它服务得起 ← 第 11 章
③ 用「4 位底座 + 高精度旁路」微调,适配到你的领域 ← 第 12 章
④ 用一个带连续批处理和投机解码的推理服务器部署 ← 这一章

★ 每一层各解决一个不同的约束:
② 让它装得进可用的显存
③ 让适配不必付出高得离谱的算力代价
④ 让吞吐高到这次部署在经济上成立

走查:那一百封信的总账

起点(什么都不做):
700 亿模型 16 位装载 = 140GB → 要多张数据中心卡,这家公司买不起
★ 这个方案根本不存在。

── 第 11 章:压到 4 位 ────────────────────────────
140GB → 35GB
★ 从「买不起」变成「两张消费级显卡」[^10]

── 第 12 章:4 位底座 + 秩 16 的旁路,做领域微调 ──
微调这件事从「租数据中心」变成「一台工作站」
★ 从「不能定制」变成「这周试了五个变体」

── 这一章:四道服务优化 ──────────────────────────
键值缓存: 每封信的计算量降约 200 倍
按页管缓存: 同一张卡的并发从约 20 个升到约 300 个
连续批处理: 一百封信的总耗时快约一倍
投机解码: 模板化内容上再快一截

★ 那一百个坐席:从「最后一个人等三分半」
变成「所有人几乎同时拿到信」。

(除了 140GB→35GB 之外,这一整栏的数都是为演示编的,
而且是各节走查里那些编造数字的汇总。)

而这些取舍常常是划算的

书给了一句很好用的总结11:

技法代价但是
量化引入误差4 位模型通常保住全精度九成五以上的能力
只训一小块旁路训的参数少但它们常常正好抓住了那部分要紧的适配
蒸馏模型变小而继承了老师知识的小模型,胜过从零训出来的同尺寸模型
剪枝去掉了权重但去掉的那些本来贡献就很小

书给的共同模式:神经网络里含有大量可以被消除的冗余, 而它们惯常使用的精度,超过了它们实际需要的。 「网络需要什么」和「网络惯常拥有什么」之间的这道缝,就是这些技法赖以存在的机会。

8. 机制六:别从「刚好放得下」的最大模型起步

这一节是这一章唯一一条反直觉的操作口径,而且它反的正是多数人的第一反应。

现象

要在一台设备上跑模型时,人的第一反应是:选那个刚好装得下的最大的。

书说这是错的12:

要抵抗「从技术上刚好放得下的最大模型起步」这个诱惑。 模型带来的内存压力,会让上下文、键值缓存和应用本身没有余地。 ★ 一个「在 100 个 token 上下文下放得下」的模型,是不可部署的。

正确的起步方式

从「在你这个具体任务上能达到可接受质量的最小模型」起步,然后再从那里优化。12

而书给了一条会让人吃惊的经验12:

对许多**受约束的**任务 —— 实体抽取、分类、函数调用、简单问答 ——
**10 亿参数以下的模型表现得出人意料地好。**

★ 五亿参数和七十亿参数之间的能力差距:
开放式生成上 → **很大**
受约束的任务上 → **常常可以忽略**

书还给了一个极端的例子来支撑这条13:

有一个只有 2.8 亿参数的模型,专门为「函数调用与工具使用」训练。 它不追求通用能力,只专注于理解用户意图并生成结构化的函数调用它证明了:极端的专门化,可以补偿极端的尺寸约束—— 它能可靠地做函数调用(而几乎别的什么都不会), 尺寸只有通用指令跟随所需要的一小部分。

参照物: 2.8 亿参数只有一个 70 亿模型的四十分之一; 而一个 20 亿参数的模型压到 4 位大约占 1GB,小到能装进许多手机13

硬件分层,以及一个可以自动化的路由决定

书列了四档硬件,并给了一条组合口径14:

什么样取舍
数据中心级显卡显存大、带宽高、支持跨卡并行能以低延迟服务最大的模型,代价可观
消费级显卡两张 4090 共 48GB,能跑 4 位量化的 700 亿模型有量化带来的质量损失,吞吐也不如数据中心硬件
CPU任何现代服务器都能跑,靠专门的 CPU 推理工具吞吐更低;适合低流量或者成本敏感的部署
边缘设备手机、笔记本上跑小模型避开网络延迟,数据不出设备

★ 书给的组合口径:最优的部署常常是把这几档混着用—— 简单请求路由到便宜的硬件,把昂贵的显卡留给那些需要最大能力的复杂查询。 而这个路由决定本身也可以自动化:用一个小分类器来预判。14

9. 作者的判断与证据

说法是哪一类说明
不止一个好模型死在推理慢上作者的观察没有配案例,是行业经验陈述1
这类负载「大部分时间在等内存」有据的工程事实它是本章所有优化的共同前提2
按页管缓存能消掉碎片、大幅提高吞吐有据书交代了它的来历(借操作系统虚拟内存的概念)3
注意力那套优化快 2 到 4 倍有据书给了两篇论文的尾注6
不同硬件上哪个实现最快不一样作者的实测口径书专门写成警告框,并给出「永远在目标硬件上实测」这条行动建议7
投机解码「猜对就一次前进五步」机制的直接后果那个 5 是书举的例子,不是固定值8
4 位保住九成五以上能力书给的量级没有配具体基准;和第 11 章那张「掉 1%–2%」的表在同一个量级上11
「刚好放得下」不可部署作者的判断 + 机制理由是「上下文、缓存和应用本身没有余地」12
5 亿和 70 亿在受约束任务上差距常可忽略作者的经验判断没有配基准数据;但书举了一个 2.8 亿专用模型作为佐证1213
那个 2.8 亿的函数调用模型有据的实例书点了名并描述了它的定位13
路由决定可以用小分类器自动化作者的建议没有配实现细节14
冗余 + 精度富余 = 机会全章总纲这是作者把三章串起来的那句话11

10. 边界与局限

  1. 这一章几乎不给数字。 书本身在服务这一段就很少给量化数据—— 它给的是机制和取舍所以这一章走查里的数比别的章更多是编的, 我们每一处都标了。
  2. 各推理服务器的配置细节不在这里。 书点了三个的名字和各自的强弱, 属于会随版本变的东西;要看实现请查我们的前沿框架书架15
  3. 书没有给「一份键值缓存到底占多少显存」的公式。 我们在走查里用了一个编造的每 token 开销来演示这笔账, 真实数值取决于层数、宽度和缓存本身的精度——这一块书没交代。
  4. 书里那个「让编码助手来编排优化流水线」的专栏,我们按全书口径不覆盖。
  5. 这一章不讲「怎么监控线上服务」。 它讲的是让它跑起来; 跑起来之后怎么持续验收,是第 10 章那门功课。

11. 可带走的

  1. 训得再好,用户体验到的地方是推理。 不止一个好模型死在这一段;
  2. 这类负载和别的机器学习负载不同:序列长度不定、一个词一个词生成、 ★ 大部分时间在等内存而不是在算——后面所有优化都建立在这一条上;
  3. 把每个位置算过的键和值存下来复用,所以第二个词比第一个便宜得多; 这份缓存叫 KV cache;
  4. 它的代价是随序列长度增长、并把显存搞得七零八落; ★ 真正决定「能同时服务多少人」的,常常是这份缓存,不是模型权重;
  5. 把这份缓存按固定大小的页来管、用一张页表拼接—— 这是从操作系统的虚拟内存借来的主意;效果是消掉碎片、请求之间还能共享;
  6. 朴素批处理会把算力浪费在填充上(短序列被补齐到最长的那条);
  7. 连续批处理在 token 这一级管批:谁写完谁的槽位立刻补进新请求, 而不是让它空着等别人;
  8. 另一类优化是不把注意力那张大中间表实体化出来,靠分块把数据留在快速的片上存储里, 快 2 到 4 倍;多数框架已经默认开着它;
  9. 但哪个实现最快取决于你的硬件——同一代卡上厂商库可能比某个版本更快, 而某型机器上最新版可能不稳永远在目标硬件上实测;
  10. 投机解码:小模型先猜五个词,大模型并行一次验完;全对就一次前进五步; 猜错就用大模型的那个词,继续起草;
  11. 它省时间的原因也是第 2 条:验 1 个和验 5 个搬同样多的权重,而算力本来闲着; 所以它对模板化的输出最有效;
  12. 11、12、13 三章的技法是叠着用的:4 位量化 + 只训一小块旁路的微调 + 连续批处理 + 投机解码;每一层解决一个不同的约束;
  13. 而这些取舍常常划算:4 位通常保住九成五以上的能力; 只训一小块常常正好抓住要紧的那部分;剪掉的权重本来贡献就小;
  14. 别从「刚好放得下」的最大模型起步。 一个「在 100 个 token 上下文下放得下」的模型是不可部署的;
  15. 从「达到可接受质量的最小模型」起步; ★ 五亿和七十亿的差距,在开放式生成上很大,在抽取/分类/函数调用这类受约束任务上常可忽略;
  16. 一个 2.8 亿参数的专用模型能可靠做函数调用(而几乎别的什么都不会)—— 极端专门化可以补偿极端的尺寸约束;
  17. 硬件分层混着用:简单请求走便宜硬件,复杂查询留给贵的; 路由本身可以用一个小分类器自动化;
  18. 全章总纲:网络里有大量冗余,而它们惯用的精度超过实际需要—— 这道缝就是这三章所有技法的机会。

12. 原文地图

主题原书章原文位置
用户体验到的是推理 · 这类负载的特殊性The Last Mile: Serving at Speedtext/105-fm-the-last-mile-serving-at-speed.txt:3(搜「inference is where end users experience the model」) · :7(搜「waiting for memory rather than computing」)
键值缓存 · 按页管 · 三个服务器The Last Mile: Serving at Speedtext/105-fm-the-last-mile-serving-at-speed.txt:9(搜「borrowed from operating system virtual memory」)
不实体化中间矩阵The Last Mile: Serving at Speedtext/105-fm-the-last-mile-serving-at-speed.txt:11(搜「avoid materializing these intermediates」)
别信通用建议,在目标硬件上实测WARNINGtext/106-fm-warning.txt:3(搜「Always benchmark on your target hardware」) · :5(搜「requires compilation steps」)
批处理为什么有用 · 填充的浪费 · 连续批处理VIBE CHECK: OPTIMIZATION PIPELINE AUTOMATIONtext/107-fm-vibe-check-optimization-pipeline-automation.txt:9(搜「computing on meaningless padding tokens」) · :11(搜「iteration-level batching」)
投机解码VIBE CHECK: OPTIMIZATION PIPELINE AUTOMATIONtext/107-fm-vibe-check-optimization-pipeline-automation.txt:13(搜「the generation advances by five tokens」)
硬件分层 · 路由VIBE CHECK: OPTIMIZATION PIPELINE AUTOMATIONtext/107-fm-vibe-check-optimization-pipeline-automation.txt:19(搜「command premium prices」) · :21(搜「fits in 48GB across two RTX 4090s」) · :23(搜「routing simple requests to cheaper hardware」)
极小的专用模型 · 边缘部署VIBE CHECK: OPTIMIZATION PIPELINE AUTOMATIONtext/107-fm-vibe-check-optimization-pipeline-automation.txt:27(搜「extreme specialization can compensate」) · :29(搜「occupies roughly 1GB」)
别从最大的起步THE SMALLEST VIABLE MODELtext/108-fm-the-smallest-viable-model.txt:3(搜「is not deployable」)
优化栈可以叠 · 取舍常常划算The Optimizations Stacktext/109-fm-the-optimizations-stack.txt:3(搜「a theoretical capability rather than a deployable one」) · :5(搜「assemble combinations suited to specific constraints」) · :7(搜「retain 95 percent or more」) · :9(搜「substantial redundancy that can be eliminated」)
效率就是战略灵活性Summarytext/110-fm-summary.txt:3(搜「the key to strategic flexibility」)

Footnotes

  1. 出处:「The Last Mile: Serving at Speed」第 3 段(text/105-fm-the-last-mile-serving-at-speed.txt:3,搜「inference is where end users experience the model」)。原文的完整说法是:企业 AI 的一条冷酷真相是,不管我们的训练多优雅,用户体验到这个模型的地方是推理;不止一个构思良好、能力很强的模型,因为推理慢、服务差而失败书没有为这句话配具体案例。 2

  2. 出处:「The Last Mile: Serving at Speed」第 7 段(text/105-fm-the-last-mile-serving-at-speed.txt:7,搜「waiting for memory rather than computing」)。原文的对照对象是图像模型——它们在单次前向里处理固定尺寸的输入;而语言模型处理变长序列、通过自回归循环一次生成一个 token、并且大部分时间在等内存而不是在计算;所以为「固定尺寸输入的批处理」设计的标准服务设施在这类负载上表现很差 2

  3. 出处:「The Last Mile: Serving at Speed」第 9 段(text/105-fm-the-last-mile-serving-at-speed.txt:9,搜「borrowed from operating system virtual memory」)。这一段里书连着讲了三件事:模型在生成期间缓存算出来的键与值向量以避免冗余计算,但这份缓存随序列长度增长、并随着不同长度的请求到来与完成而把内存碎片化;那个按页管理的做法把缓存块非连续地存放、通过页表映射,消掉碎片并让请求之间高效共享内存,结果是多请求负载上的吞吐大幅提高;同段还点了另外两个推理服务器的名字与各自的特点。 2 3 4 5 6

  4. 出处:「VIBE CHECK: OPTIMIZATION PIPELINE AUTOMATION」第 9 段(text/107-fm-vibe-check-optimization-pipeline-automation.txt:9,搜「computing on meaningless padding tokens」)与第 11 段(text/107-fm-vibe-check-optimization-pipeline-automation.txt:11,搜「iteration-level batching」)。第 9 段那个例子是:一批里有 50、100、200 个 token 的序列,短的必须被填充到和最长的一样长。第 11 段的收口是:结果是更高的吞吐,而且不需要人为的等待,把可用硬件用得更好。 2 3

  5. 补充(不在书里,依据我们的 frontier 书架):「完成即补位」这个调度循环具体怎么实现、抢占和换出怎么处理,书没有讲。 依据: shelf=ai-frontier-reference/vllm#02-continuous-batching-scheduler.md 事实=那一篇拆的就是这个调度器每一轮怎么决定哪些请求进入这一步、以及显存不够时怎么把请求换出去。

  6. 出处:「The Last Mile: Serving at Speed」第 11 段(text/105-fm-the-last-mile-serving-at-speed.txt:11,搜「avoid materializing these intermediates」)。书给了两篇论文的尾注。原文说明标准实现会实体化出随序列长度按平方增长的中间矩阵,从而限制了实际的上下文长度;新做法融合运算、用分块把数据留在快速的片上存储而不是慢速显存里,结果是快 2 到 4 倍、内存占用大幅下降;并说多数推理框架现在默认集成它,使它成为标准而不是一个可选项 2 3

  7. 出处:「WARNING」第 3 段(text/106-fm-warning.txt:3,搜「Always benchmark on your target hardware」)与第 5 段(text/106-fm-warning.txt:5,搜「requires compilation steps」)。第 3 段逐条给了那几种硬件与实现的组合关系,结论是那句加了感叹号的行动建议。第 5 段给了三个推理服务器的取舍,并说选哪个取决于部署语境,收口是:因此,对多个推理服务器都有把握、并知道什么时候用哪个,是有帮助的。 2 3

  8. 出处:「VIBE CHECK: OPTIMIZATION PIPELINE AUTOMATION」第 13 段(text/107-fm-vibe-check-optimization-pipeline-automation.txt:13,搜「the generation advances by five tokens」)。原文明说这个技法为可预测的输出加速(也就是草稿模型经常猜对的那些场景),而对不可预测的内容则退回到标准生成;同段还提到它和缓存优化结合起来,能达到在内存约束下本来不可能的批量与吞吐那个 5 是书举的例子,不是固定值。 2 3

  9. 出处:「The Optimizations Stack」第 3 段(text/109-fm-the-optimizations-stack.txt:3,搜「a theoretical capability rather than a deployable one」)。原文把这一整块技法的共同目的概括为一句:让有能力的模型变得实用。

  10. 出处:「The Optimizations Stack」第 5 段(text/109-fm-the-optimizations-stack.txt:5,搜「assemble combinations suited to specific constraints」)。原文给的那条路径正是我们抄进走查里的四步,并逐条说明每一层解决了什么约束。

  11. 出处:「The Optimizations Stack」第 7 段(text/109-fm-the-optimizations-stack.txt:7,搜「retain 95 percent or more」)与第 9 段(text/109-fm-the-optimizations-stack.txt:9,搜「substantial redundancy that can be eliminated」)。第 9 段那句共同模式是这三章的总纲:网络需要什么和网络惯常拥有什么之间的那道缝,创造了这些技法所利用的机会。 2 3

  12. 出处:「THE SMALLEST VIABLE MODEL」第 3 段(text/108-fm-the-smallest-viable-model.txt:3,搜「is not deployable」)。这是书里一个独立的方框。原文列的那几类受约束任务是实体抽取、分类、函数调用和简单问答,并说 10 亿参数以下的模型在这些任务上表现得出人意料地好;结论那句是:五亿和七十亿之间的能力差距,对开放式生成来说很大,对受约束任务来说常常可以忽略。 书没有为这条配基准数据。 2 3 4 5

  13. 出处:「VIBE CHECK: OPTIMIZATION PIPELINE AUTOMATION」第 27 段(text/107-fm-vibe-check-optimization-pipeline-automation.txt:27,搜「extreme specialization can compensate」)与第 29 段(text/107-fm-vibe-check-optimization-pipeline-automation.txt:29,搜「occupies roughly 1GB」)。第 27 段那个模型书点了名(Google 的 FunctionGemma,2.8 亿参数);原文那句括号里的话很实在:它能可靠地做函数调用(但几乎别的什么都不会)。第 29 段还提到一类用浏览器图形接口在网页里直接跑量化模型的项目,从而不需要任何安装就能在设备上推理 2 3 4

  14. 出处:「VIBE CHECK: OPTIMIZATION PIPELINE AUTOMATION」第 19 段(text/107-fm-vibe-check-optimization-pipeline-automation.txt:19,搜「command premium prices」)、第 21 段(text/107-fm-vibe-check-optimization-pipeline-automation.txt:21,搜「fits in 48GB across two RTX 4090s」)与第 23 段(text/107-fm-vibe-check-optimization-pipeline-automation.txt:23,搜「routing simple requests to cheaper hardware」)。第 21 段还有一句给读者的鼓励:乐观的开发者可以把这看成一个熟悉多卡训练的好机会,而那是一项抢手的技能——过了某个模型尺寸之后,分布式训练是唯一的选项。 2 3

  15. 补充(不在书里,依据我们的 frontier 书架):那个按页管理键值缓存的做法,书只给了机制描述,没有讲块怎么划、页表怎么维护。 依据: shelf=ai-frontier-reference/vllm#01-paged-attention-kv-cache.md 事实=那一篇拆的就是这份缓存怎么被切成固定大小的块、以及页表怎么把它们拼成逻辑上连续的一段。