Workers AI 在靠近用户的 Cloudflare 数据中心的 GPU 上,为一批全球顶尖的开源模型提供推理服务。其中最强大、要求也最高的两个,是 Moonshot 的 Kimi K 系列和 Z.ai 的 GLM。它们都是大型、长上下文的混合专家(mixture-of-experts)模型,用起来非常出色,但受限于内存,要高效地提供服务也非常困难。
我们之前介绍过如何在 Workers AI 上部署大模型,也介绍过把推理的 prefill 和 decode 阶段分离,以便从每块 GPU 中榨取更多性能。本文将介绍我们在此基础上叠加的三项技术,用来让这些模型装进内存并保持高速:量化 KV 缓存、压缩模型权重,以及——因为前两者会让更多请求挤在共享硬件上——保护这些请求共享的缓存。这些优化让我们能以更低的成本服务更多客户,而且模型精度不变。
我们所有的实验和生产流量,都运行在开源推理服务框架 SGLang 上,并以它做基准测试。我们发现 SGLang 提供了市面上最好的性能,并与 SGLang 团队密切合作,把补丁和新功能上游合并,让开源社区也能用上我们的成果。
量化 KV 缓存
模型在生成文本时,会把已经处理过的每个 token 的注意力键(K)和值(V)存放在一种叫作 KV 缓存的结构中。有了这份缓存,模型在延续长对话时,就不必在每生成一个新 token 时重新读取整个上下文。对于长上下文模型,它增长得很快,通常最先占满 GPU 内存的是 KV 缓存,而不是模型权重。
默认情况下,缓存以 16 位精度(BF16)存储。我们改用 8 位浮点(FP8,e4m3)来存储,体积减半。在 Kimi K2.6 上,这使内存中可容纳的上下文从约 686,000 个 token 提升到约 137 万个,翻了一倍。
有必要精确说明收益从何而来,因为它并不是原始速度。量化缓存会给每个 token 增加少量工作,因为 FP8 注意力内核在读取数值时需要进行转换。它真正改变的是我们能同时驻留多少请求。以下测量针对的是 Kimi K2.6 在解耦式 H200 部署上的 decode,并直接对比了注意力内核:
| 并发请求数 | BF16 KV 缓存(tok/s) | FP8 KV 缓存(tok/s) |
|---|---|---|
| 1 | 137 | 125 |
| 8 | 731 | 689 |
| 16 | 1,106 | 1,028 |
| 32 | 1,558 | 1,489 |
| 64 | 内存不足 | 2,192 |
在任意单一并发水平下,BF16 的单 token 速度都要快几个百分点。但 BF16 在 32 个并发请求时就耗尽了缓存,无法接纳第 33 个请求,而 FP8 可以继续扩展到 64 个,达到每秒 2,192 个 token,比 BF16 的峰值高出约 41%,每个 token 的成本则低约 30%。由于我们把 prefill 和 decode 作为独立的池来运行,可以把这一做法用在收益最大的地方:prefill 受计算限制而非内存限制,所以那里我们让缓存保持 BF16,保留其略高的吞吐量。
如果这一切改变了模型的回答,那就毫无意义,所以我们做了验证。在我们的整套评测中,FP8 缓存与 BF16 缓存没有可察觉的差别:
| 基准测试 | BF16 KV | FP8 KV |
|---|---|---|
| GSM8K | 94.24 | 94.09 |
| ARC-Easy | 89.06 | 89.14 |
| ARC-Challenge | 66.72 | 67.49 |
| MMLU | 89.11 | 89.04 |
| MMLU-Pro | 80.29 | 79.29 |
| mcxams(内部基准测试) | 61 / 63 | 61 / 63 |
| 工具调用有效性 | 92.2% | 92.6% |
压缩模型权重
KV 缓存是对 GPU 内存的一项需求,模型权重则是另一项。对于 GLM 5.2,我们把权重从 8 位浮点压缩到 4 位整数(INT4),且精度没有损失。检查点从 705 GB 缩小到 421 GB,约减少 40%;在 8 路张量并行部署中,每块 GPU 的内存占用从约 88 GB 降到 52 GB,这让同样的硬件上可以留出约 118 万个 token 的 KV 缓存空间。
在我们的整套评测中,INT4 权重与 FP8 权重没有可察觉的差别:
| 基准测试 / 能力 | 指标 | FP8 | INT4 |
|---|---|---|---|
| GSM8K | 精确匹配 | 94.39% | 93.56% |
| GSM8K | Flexible | 94.24% | 93.48% |
| ARC-Easy | 准确率 | 86.62% | 86.15% |
| ARC-Easy | Acc (norm) | 84.51% | 85.19% |
| ARC-Challenge | 准确率 | 64.93% | 64.85% |
| ARC-Challenge | Acc (norm) | 67.24% | 66.64% |
| MMLU | 平均 | 86.60% | 86.54% |
| MMLU-Pro | Exact | 80.80% | 80.47% |
| mcxams(内部基准测试) | 通过 | 62 / 63 | 62 / 63 |
权重变小会让 decode 阶段更快,原因很明确:生成每个 token 都需要把模型权重从 GPU 内存中流式读出,所以 decode 速度受内存带宽限制。搬运的数据更少,每个 token 就来得更早。这种效果在低并发时最明显,而低并发正是单请求延迟最重要的场景:
| 并发请求数 | GLM FP8(tok/s) | GLM INT4(tok/s) | INT4 增益 |
|---|---|---|---|
| 1 | 60 | 92 | +55% |
| 8 | 425 | 513 | +21% |
| 16 | 683 | 825 | +21% |
| 32 | 994 | 1,267 | +27% |
| 64 | 1,672 | 1,933 | +16% |
Prefill 的表现则不同。它受计算限制,而 INT4 权重在参与乘法之前必须先展开还原,这一额外步骤使 prefill 变慢而不是变快:GLM 的 prefill 在 FP8 下可持续约每秒 10,160 个 token,INT4 下则为 8,660。与 KV 缓存一样,解耦式设计把这变成了一种选择而非折中:decode 用 INT4,因为那里它占优;prefill 用 FP8,因为那里它占优。在我们运行的所有基准测试中,模型精度与 FP8 模型的差距都在 0.8 个点以内,质量上没有可察觉的差别。
保护共享的 KV 缓存
上述两项技术有同样的效果:让多得多的请求可以同时共享一块 GPU 的内存。这种效率正是关键所在,但也意味着数百个请求在读写同一块物理 KV 缓存的各个页面。让这一切变快的机制——分页注意力(paged attention)、连续批处理(continuous batching)、缓存复用——都依赖于把记账工作做得分毫不差,而在我们的请求量级下,即便十亿分之一的差错也会时常出现。
因此,我们构建了 KV 缓存完整性检查,作为一层防御。思路很简单:每个物理缓存页都带有一个标签,页面一旦被重新分配,标签就会改变;服务器会记录每个请求预期使用的页面和标签。在受支持的 decode 操作读取缓存之前,会先检查这些映射。如果有任何不匹配,受影响的请求就会被中止,而不是被允许返回来自错误页面的数据。
决定一项安全检查能否上线的问题是:它的代价是什么。我们在一个中等规模的生产模型上,以两个 prefill、两个 decode 的配置,使用 8,192 个 token 的输入和 1,000 个 token 的输出进行了测量:
| 并发数 | 吞吐量变化 | p95 延迟变化 |
|---|---|---|
| 1 | −0.53% | +0.42% |
| 2 | −0.38% | +0.54% |
| 4 | −0.79% | +0.63% |
| 8 | −0.43% | +0.80% |
无论是吞吐量还是尾延迟,代价都不到 1%,即使取 95% 置信区间的上界,也仍接近 1%。我们把验证作为一次单独的批量检查来运行,而不是融合进注意力内核,从而保持了很低的计算开销;融合的做法会在 GPU 线程组之间引入竞争条件。它可按部署单独启用,默认路径使用空操作(no-op)的跟踪器,没有可测量的开销,因此不需要它的部署不会付出任何代价。
下一步
高效地服务前沿模型是一个不断移动的目标,这些就是背后持续进行的工作。我们正在把 FP8 KV 缓存推广到更多集群,在 Blackwell(NVIDIA 的 GPU 架构)上验证 NVFP4 权重,并努力让完整性检查能够以可忽略的代价在所有地方常开。这些优化将使我们能够以更低的成本、相同的精度,继续服务更多客户。
如果把最好的开源模型塞进 GPU、再把它们提供给数百万开发者这件事听起来正是你喜欢的挑战,欢迎加入我们。
