本文整理自 26 年 9 月 22 日 SGLang Meetup 北京站活动的同名主题演讲。
在公众号回复「百度百舸 2609」,可以获得此次 Meetup 下午的 3 个演讲主题材料。
各位嘉宾、各位社区的开发者,大家好。
随着大模型不断发展,旗舰模型的权重存储规模已经进入 TB 级,给推理部署带来了巨大的显存压力。
今天的分享主要分为三个部分:第一部分,介绍主流旗舰模型面临的显存压力;第二部分,针对模型权重,介绍两种零冗余分布式部署方案;第三部分,针对 KV Cache,介绍我们分别从算法、后训练和运行时三个维度所做的优化,以降低动态显存占用,进一步扩大 KV Cache 的可承载容量。
1. 主流旗舰模型面临的显存压力
在进入正式内容之前,我们先回顾一下主流旗舰模型面临的显存压力。
我们以一个具有代表性的旗舰模型 Kimi-K3 为例,分析它在推理部署中的显存构成:约 74% 的显存用于存放模型权重,约 18% 用于运行时的 KV Cache,留给激活值和其他运行时开销的空间只有约 8%。也就是说,模型权重和 KV Cache 已经占用了绝大部分显存。
接下来再看旗舰模型的发展趋势。首先,模型的总参数量还在持续增长:从 GLM-5.2 的 744B,到 DeepSeek-V4-Pro 的 1.6T,再到 Kimi-K3 的 2.8T;未来,旗舰模型的参数规模还可能进一步增长到 5T,甚至 10T。总参数量不断增长,意味着部署时需要存储的权重也越来越多。
但从计算侧来看,模型每个 Token 实际激活的参数量并没有同步增长。GLM-5.2 和 DeepSeek-V4-Pro 的激活参数量基本在 40B 左右,Kimi-K3 提升到了约 100B。即使达到 100B,与 2.8T 的总参数量相比,二者仍然存在十倍以上的差距。
这意味着,旗舰模型需要存储的权重规模在快速增长,但每个 Token 实际参与计算的参数量增长相对有限。存储需求和有效计算量之间的不平衡越来越明显,最终会出现一种情况:显存被大量权重占用,但算力却无法得到充分发挥。
再看运行时的显存压力。随着 Agent 应用快速发展,任务链路越来越复杂,需要处理的上下文也越来越长。但现有 KV Cache 压缩方法与模型架构高度相关,还不能在不同旗舰模型上获得一致的压缩效果。
以 60K 上下文为例,在当前测试配置下,GLM-5.2 和 Kimi-K3 的单请求 KV Cache 显存占用仍然超过 3 GB,而 DeepSeek-V4-Pro 可以压缩到约 300 MB。不同模型之间虽然存在明显差异,但整体趋势是一致的:上下文越长,KV Cache 带来的动态显存压力越大。
所以,旗舰模型部署同时面临两类显存压力:一类是模型权重带来的静态显存占用,另一类是 KV Cache 随上下文长度和并发请求增长带来的动态显存占用。接下来,我们将分别针对这两类问题展开优化。
面对这样的显存压力,它会对推理部署造成什么影响?我们的核心判断是:显存容量已经成为制约算力发挥的主要瓶颈。
显存为什么会影响算力利用率?关键在于推理的 Batch Size,也就是 BS。只有把 BS 提升到足够大的规模,才能让算力卡保持较高的利用率。但在旗舰模型和长上下文场景下,模型权重和 KV Cache 会占用大量显存,留给扩大 BS 的空间非常有限。
我们仍然以 Kimi-K3 为例。在当前实验配置和长上下文场景下,受显存容量限制,它的 BS 只能达到 40 多,对应吞吐约为 16.8k tokens/s。如果假设显存容量不再构成约束,BS 可以提升到 256 以上,此时算力才能得到更加充分的发挥,吞吐可以达到约 38.6k tokens/s。
换句话说,受显存容量限制,实际吞吐只有理想状态的 44% 左右,超过一半的潜在吞吐没有得到释放。因此,我们要解决的并不只是「显存够不够放下模型」,而是如何释放更多显存,把它转化为更大的 BS 和更高的吞吐。
针对这个问题,我们从两条主线展开优化。
第一条主线是权重优化,目标是实现权重的零冗余部署。针对 Decode,我们保留多路 DP,并采用 DP Attn-sharding,将 Attention 权重均匀切分到不同卡上;针对 Prefill,我们将多路 DP 合并为单路 DP,并通过全路 CPP (Chunked Pipeline Parallelism) 将模型权重按 Stage 均匀部署。
第二条主线是 KV Cache 优化,目标是降低动态运行阶段的显存占用,扩大 KV Cache 的可承载容量。围绕这个目标,我们从三个维度展开:在算法侧,我们推出 LU-KV 系统,通过全局显存规划压缩 KV Cache;在后训练侧,我们重新设计 Draft 模型的 Attention 结构,降低 Draft KV Cache 的显存占用;在运行时侧,我们优化 SGLang 的 PD 握手机制,减少传输过程中的显存预留,进一步提高显存利用率。
接下来,我将分别介绍权重优化和 KV Cache 优化的具体方案。
2. 权重优化:Attn-sharding + 全路 CPP 实现权重 0 冗余分布式部署
第一部分是针对权重的优化。我们的目标是,在推理部署中,将权重均匀分布到各个 Rank 上,并尽可能消除权重冗余。在当前部署配置中,每个 Rank 对应一张卡,也就是说,我们希望每张卡只保存实际需要的权重。
针对 Decode 和 Prefill 不同的执行特点,我们设计了两条权重零冗余路径:在 Decode 阶段,我们保留多路 DP,通过 DP Attn-sharding 消除 Attention 权重冗余;在 Prefill 阶段,我们将多路 DP 合并为单路 DP,并通过全路 CPP 实现权重的均匀部署。
在介绍这两条路径之前,我们先看一下:当前的推理部署为什么会出现权重冗余。
随着模型规模不断增长,越来越多的旗舰模型开始采用 MoE 稀疏架构。在这类模型的推理部署中,大 EP 是一种典型的吞吐优化方案,而大 EP 通常会配合多路 DP 使用。
多路 DP 主要有三个优势。第一,每一路 DP 都保留完整的 Attention 模块,不需要对 Attention 权重进行切分,因此通信开销比较小。第二,各路 DP 可以独立接收和处理请求,从而聚合更多请求参与 Group GEMM,扩大有效 BS,更容易发挥算力。第三,全局 BS 可以相对均匀地分配到各张卡上,使单卡承担的 BS 较小,从而减少中间激活所需的预留显存。
正是因为这些特点,大 EP 配合多路 DP,成为面向吞吐优化的一条重要部署路径。
但它也会带来一个明显的问题:每一路 DP 都需要保存一份完整的 Attention 权重。因此,在同一个部署实例中,Attention 权重会随着 DP 路数增加而重复存储,形成显存冗余。
在长上下文和大规模旗舰模型场景下,这部分冗余会占用大量显存,限制运行时 BS 的进一步扩大,使算力无法运行在更高效的区间。
针对这个问题,我们设计了两种解决思路。
第一种是 DP Attn-sharding,主要用于 Decode 阶段。我们保留多路 DP 的吞吐优势,但将原本在各路 DP 中完整复制的 Attention 权重切分到不同卡上,使权重均匀分布,从而消除多路 DP 带来的 Attention 权重冗余。
第二种是单路 DP 收敛,主要用于 Prefill 阶段。既然多路 DP 会产生重复的 Attention 权重,我们就将多路 DP 合并为一路,从架构上消除 DP 副本之间的权重冗余;在此基础上,再通过全路 CPP 将模型权重按 Stage 分布到不同卡上,实现权重的均匀部署。
接下来,我将分别介绍这两种方案的具体设计和实验效果。
针对 Decode 的部分,我们实现了完全均匀部署的策略,叫做 Attn-sharding。这个在训练里面其实经常用到,但在推理里面我们还是首次用到。它的思路非常简单:让每张卡上常驻的 Attention 权重是 N 分之一。真正计算时,再通过 AllGather 把 N 张卡上的分片临时聚合起来,恢复成完整权重。这样的话,这部分释放出来的显存可以用于承载更多运行时 KV Cache。
它主要有三个优势:第一,Attention 权重可以在各卡之间均匀切分,消除多路 DP 带来的重复部署;第二,它保留了多路 DP 的吞吐优势;第三,经过通信与计算重叠优化,Attn-sharding 没有带来明显的端到端性能损失。
在整个实践过程里面,我们发现用了这个策略之后,DeepSeek-V4-Pro 上面每卡大概能释放 16.57 GiB 的显存,Kimi-K3 每卡大概能释放 29.8 GiB 的显存。
不过,要真正落地 Attn-sharding 并不容易。我们在权重组织、通信调度和显存管理上做了很多细节优化。整个实践下来,可以总结为两个关键点。
第一个关键点,是权重重排、通信合并和双 Buffer 流水设计。
所谓权重重排,就是把原本离散存储、需要进行 Sharding 的权重重新组织成连续的存储空间。在此基础上,我们将多个分散的通信操作合并成一次 AllGather,在计算前聚合出当前层所需的完整权重。这样,通信次数就从原来的 N 次减少到一次,提升了通信效率,使单层通信耗时降低约 20%。
为了进一步减少通信对计算的阻塞,我们还设计了双 Buffer 流水。在一块 Buffer 为当前层提供计算所需权重的同时,另一块 Buffer 可以接收下一层的权重,两个 Buffer 交替读写,从而让下一层的通信与当前层的计算尽可能并行。
双 Buffer 会引入少量临时显存,但其占用仅约为 Attn-sharding 所释放显存的 4%。而且这两块 Buffer 可以在不同层之间重复使用,因此额外显存不会随着模型层数增加。
第二个关键点,是进一步优化计算与通信的重叠。围绕这一点,我们主要做了三方面工作。
第一,我们引入专用的 Copy Engine 执行数据搬运,减少 AllGather 对 SM 计算资源的占用,从而降低通信与计算之间的资源争用。
第二,我们重新设计了跨层通信调度。在第 N 层执行计算时,系统会提前启动第 N+1 层权重的 AllGather;等到第 N+1 层开始计算时,通常对应的通信已经完成,或者只需要等待很短的尾部时间。通过这种预取式调度,我们进一步降低了通信带来的额外开销。
第三,我们采用 FP8 表示参与通信的权重,减少 AllGather 需要传输的数据量,进一步缩短通信时间,使通信更容易被当前层的计算覆盖。
通过权重重排与通信合并、双 Buffer 流水、专用 Copy Engine、跨层预取调度以及 FP8 通信,我们把 Attn-sharding 引入的通信开销尽可能隐藏在计算过程中,最终没有带来明显的端到端性能损失。
接下来介绍第二条路径,也就是针对 Prefill 的单路 DP 收敛方案。我们将多路 DP 合并为一路,再通过全路 CPP 对模型进行切分和部署。
所谓全路 CPP,就是将 Pipeline 的不同 Stage 分布到每张卡上,也就是每个 PP Stage 独占一张卡,而不是由多张卡共同承载一个 PP Stage。
它主要有三个优势。第一,可以消除 TP 通信和 DP 链路之间的通信;第二,权重可以按层分布到不同 Stage,做到几乎均匀切分,避免权重冗余;第三,它具有较好的部署灵活性,可以通过线性扩展节点数量,适配不同规模的模型和不同显存容量的算力卡。
从实验结果来看,在我们的测试配置下,随着节点数量增加,全路 CPP 的 TTFT 可以近似线性降低。不过,全路 CPP 的主要难点,是如何减少 Pipeline 执行过程中产生的 bubble。针对这个问题,我们分别从前处理、执行过程和后处理三个阶段进行了优化。与社区原始方案相比,优化后的吞吐提升接近 50%,TTFT 降低约 60%。
接下来,我分别介绍这三个阶段的优化方案。
首先来看前处理。这里所说的前处理,是指从请求进入 Pipeline,到请求被送入 GPU、开始执行 Forward 计算之间的过程。
这部分优化的基本思路,是把社区原有的环状同步共识机制,改造成中心式异步共识机制。
在原有机制中,一个请求进入 PP Stage 后,并不会立即开始执行 Forward,而是先沿着环状路径通知下一个 Stage,表示当前 Stage 已经收到请求。下一个 Stage 收到后,再继续通知后续 Stage。直到最后一个 Stage 收到请求并完成确认,系统才会通知第一个 Stage,表示所有 Stage 已经就绪,可以开始计算。
整个共识过程是同步串行执行的,耗时会随着 Stage 数量增加而近似线性增长。如果 PP Stage 数量较少,例如只有两个 Stage,这部分开销可以忽略;但在全路 CPP 场景下,Stage 数量通常与卡数相同。卡数越多,共识链路越长,这部分耗时也越明显,约占整个端到端 bubble 的三分之一。
优化后,我们将 PP 共识路径改造成中心式结构。各个 PP Stage 收到请求后,会通过后台线程异步向 PP0 汇报就绪状态。原来沿环状链路依次传递的确认过程,变成了各个 Stage 向中心节点并行汇报。
这样,共识耗时不再随着 Stage 数量线性增长,而是接近一次通信迭代的时间。经过这个改造,前处理阶段的 bubble 基本可以降到接近零。
接下来是执行过程中的 bubble。这部分通常比较容易理解,我们从两个层面解决:第一,在 Stage 之间重新划分模型层,使各个 Stage 的计算量更加均衡;第二,在 Stage 内部动态切分 Chunk,使每个 Chunk 的计算量更加均衡。
先看 Stage 之间的模型层划分。
这个问题看起来简单,实际上比较复杂。原因是当前的旗舰模型的层结构具有异质性,不同层的计算结构并不完全相同,例如 KDA 层和 MLA 层可能交替排列。如果只按照层数平均切分,各个 Stage 虽然承载的层数相近,但实际 FLOPs 并不相同,因此执行时间也会天然不均衡。
我们的解决思路,是结合模型结构和不同 Stage 的特点,按照 FLOPs 而不是层数进行切分。这样,各个 Stage 承载的层数可能不同,但计算量可以保持相对均衡。经过这个改造,在 Kimi-K3 这类异质模型上,各个 Stage 的计算负载能够得到更均匀的分布。
再看 Stage 内部的 Chunk 划分。
这部分的核心,是对社区的 Dynamic Chunk 算法进行改造。社区原有方案会预先使用一元二次模型拟合计算量,再据此决定如何划分 Micro Chunk。但这一方案存在三个问题:第一,不支持 Prefix Cache;第二,没有充分考虑异质模型中不同层的计算差异;第三,没有覆盖一个 Batch 中包含多个 Sequence,以及多个 Batch 并行执行的情况。
针对这些问题,我们把静态的预估方式改成了运行时动态计算。系统会根据当前 Batch 中的请求数量、Prefix Cache 命中情况以及模型结构,实时估算计算量,再按照各个 Micro Chunk 的目标计算负载进行均匀切分。
这样,系统可以根据运行时状态动态调整 Micro Chunk 的划分,尽可能保证各个 Chunk 的计算量均衡。通过 Stage 间的模型均匀部署和 Stage 内的 Chunk 均匀切分,我们将执行过程中的 bubble 降低了 70% 以上。
最后是后处理。我们核心的改造,是解耦 Token 输出和 KV Cache 传输之间的依赖关系。
先回顾一下 SGLang 当前的实现。在 Pipeline Parallel 中,一个 Batch 会被切分成多个 Macro Chunk,并沿着多个 PP Stage 依次执行。每个 Stage 完成一个 Macro Chunk 的计算后,并不会立即发送对应的 KV Cache,而是要等待这个 Batch 按照当前的调度流程完成计算。之后,系统再通知 PP0 统一触发 KV Cache 的发送;PP0 发送完成后,再依次通知后续 Stage 发送。
这种实现方式会在不同 Stage 之间形成比较强的串行依赖。虽然从表面上看,不同卡之间的计算和 KV Cache 传输可以并行执行,但由于后续 Stage 需要等待前面 Stage 的发送流程完成,实际执行过程中会形成一块空闲区域。
最终,这部分看似可以并行的工作,因为依赖关系的限制,整体上仍然接近串行执行。根据我们的统计,这部分开销约占端到端 bubble 的三分之一。
我们的改造方案,是解耦 Token 输出和 KV Cache 传输之间的依赖,只保留 PP0 与最后一个 Stage 之间、为完成 Token 输出所必需的依赖。对于其他 Stage,在完成当前 Macro Chunk 的计算后,就可以立即发送对应的 KV Cache,不需要等待前面 Stage 的发送流程完成。
这样,各个 Stage 的 KV Cache 传输就可以更充分地与后续计算并行。从整个实例的角度看,从计算完成到所有 Stage 完成发送,新增的尾部时间只相当于一次 Forward 的时间。随着 PP Stage 数量增加,这部分时间在整个 Pipeline 执行时间中的占比会逐渐降低,因此可以近似忽略。
通过这一改造,我们有效减少了后处理阶段由 Token 输出和 KV Cache 传输依赖造成的 bubble,进一步提升了全路 CPP 的执行效率。
3. KVCache 优化:无损驱逐 + Draft 后训练 + 运行时优化实现 KVCache 极限扩容
接下来我要给大家讲 KV Cache 这部分的优化。这部分内容我们主要分三个部分来讲。
首先第一部分,讲一个算法维度的事情。
去年,在 SGLang Meetup 上,我们发布了 ESS 系统,主要解决 MoE 稀疏模型在长上下文推理过程中 KV Cache 占用过大的问题。ESS 的思路是从 AI Infra 的角度出发,围绕特定模型的缓存结构和运行特征进行优化,通过系统层面的缓存管理与资源调度,降低 GPU 显存压力、提升推理效率。
ESS 论文地址:arxiv.org/abs/2512.10…
今年,我们进一步把关注点从「如何管理缓存」推进到「哪些缓存真正值得保留」,推出面向算法层的 LU-KV,也就是 Long-horizon Utility KV。它不再依赖某一种特定模型的缓存结构,而是从 KV Cache 中 token 和 attention head 的长期效用出发,判断哪些信息对后续推理仍然重要,并对缓存预算进行更合理的分配。这使得 LU-KV 具备更强的模型泛化能力:在尽可能保留长期语义信息的同时,可以将 KV Cache 对显存的占用压缩约 80%,并将效果损失控制在接近于零的水平。
Token 驱逐已经在业界研究了很长时间,但现有方法仍然面临两个问题。第一,很多方法基于瞬时、局部的分数来评价 Token 的重要性,容易受到噪声影响,进而带来较明显的精度损失;第二,Token 重要性的计算通常发生在推理过程中,会引入额外的运行时开销,增加 TTFT。
针对这些问题,我们提出了 LU-KV 系统。它在给定显存预算的条件下,对不同层、不同 Head 的 KV Cache 进行全局规划;同时采用离线 Profile 与在线 Lookup 相结合的方式,将复杂的分析和求解放在离线阶段完成,在线阶段直接查询并应用相应的预算配置。因此,LU-KV 不会引入明显的在线计算开销,TTFT 基本不受影响。LU-KV 的相关研究成果已被 ICML 2026 收录,代码也已经开源到百度百舸的 GitHub 仓库。
接下来,我将从六个方面介绍 LU-KV。前面三个方面主要讲理论,包括如何评价 KV 的重要性、如何重新定义压缩问题,以及如何进行近似求解;后面三个方面主要讲系统实践,包括系统构建、精度效果和系统优势。
首先看理论部分。我们重新思考了一个基础问题:应该如何评价 Token 的重要性?这里有三个发现。第一,现有评分方式大多是瞬时、局部的,容易受到噪声影响,不能准确代表 Token 的长期价值;第二,不同 Head 对应的 KV,对同一个 Token 重要性的判断并不相同,不能一概而论;第三,Prefill 阶段每个 Token 的重要性,不应该只由 Prefill 阶段的信息决定,而应该从 Decode 阶段的生成结果反向评估。
基于这三个发现,我们需要从全局视角,逐 Token、逐 KV、逐 Head 地评价信息的重要性;同时引入长期效用,也就是 LU 指标,从 Decode 阶段反向评估 Prefill 阶段每个 Token 的价值。我们的研究还表明,LU 指标与具体数据集无关,具有较好的泛化性。
在此基础上,我们进一步把 KV Cache 压缩重新定义为一个全局显存规划问题。压缩率本质上对应一个显存预算,压缩算法要解决的,就是在给定显存预算的情况下,把显存分配给最有价值的信息。换句话说,LU-KV 要确定的是:在给定显存配置或压缩率的情况下,每一层、每一个 Head 应该分配多少显存预算。
这是一个 NP-hard 的非凸离散优化问题。我们通过凸包松弛和贪心算法进行近似求解,最终得到接近理想解的预算配置。
理论部分讲完,下面再看系统实践。我们设计了离线 Profile 和在线 Lookup 两套相互配合的机制:离线阶段采集数据、计算不同显存配置下的预算方案;在线阶段直接查找对应配置,不需要重新计算,因此不会引入明显的运行时开销。
从效果来看,在 LongBench 长文本评测中,LU-KV 的精度损失只有 0.52%。同时,这套系统具有较强的灵活性,可以适配不同的显存配置和压缩率;它也具有较好的泛化性,与具体数据集无关;此外,主流的 Top-K 等压缩方法也可以集成到这套系统中。
除了算法维度,我们还从后训练维度解决 Draft 模型带来的 KV Cache 占用问题。
投机推理已经成为当前常见的推理优化手段。通常在 Target 模型之外,还需要配套一个更小的 Draft 模型,用它提前生成候选 token,再由 Target 模型进行验证。在这个过程中,Target 模型和 Draft 模型都需要维护各自的 KV Cache。因此,如果 Draft 模型的 Attention 架构设计不合理,它的 KV Cache 也会随着上下文增长,占用较多显存。
针对这个问题,我们将 Draft 模型中的 Attention 改造成固定窗口长度的滑动窗口 Attention,也就是 SWA,窗口大小固定为 128。这样,Draft 模型的 KV Cache 容量就不再随上下文长度线性增长,而是基本保持为一个常量。在我们的实验配置下,单机显存可以节省约 100 GB。
同时,我们通过后训练对模型进行适配,使投机推理的接受率基本保持不变,在显存占用显著下降的情况下,推理效果和投机收益没有明显损失。
最后一部分是运行时优化,主要解决 SGLang PD 分离架构中的握手问题。通过这个优化,我们释放了约 20% 的显存。
在 PD 分离架构中,P 负责 Prefill,D 负责 Decode。一个请求到来之后,P 会生成 KV Cache,并传输给 D;D 在接收 KV Cache 的同时,还要继续执行 Decode。
现有实现为了让 KV 传输和 Decode 计算 overlap,D 会提前预留一部分显存,用来接收 P 传输过来的 KV Cache。问题在于,这部分显存在传输发生之前不能用于 Decode,相当于一直处于预留状态。随着请求运行,这部分预留显存会限制 D 能够承载的 BS,造成显存利用率下降。
我们的改造重点不是取消 KV Cache 传输,而是调整 PD 握手和传输的时机:不再为了前置 overlap 长时间预留这部分显存,而是把握手和传输安排到更合适的后置时机。这样,Decode 生命周期内的大部分显存都可以直接用于计算,避免显存被提前占用。
经过优化后,整体显存占用释放了约 20%,D 侧能够承载更大的 BS,理论 BS 达到了理想配置下的水平。
最后我们简单小结一下。以上所讲的内容,其实分两部分:从权重的维度去实现零冗余,从 KV Cache 的角度里面实现极限扩容,也就是要把显存都换成吞吐。
在权重侧,Decode 保留多路 DP,通过 DP Attn-sharding 消除 Attention 权重冗余;Prefill 将多路 DP 合并为单路 DP,并通过全路 CPP 实现权重均匀部署。Attn-sharding 在不同模型上每卡释放约 16~30 GiB 显存;与社区原始方案相比,全路 CPP 的吞吐提升接近 50%,TTFT 降低约 60%。
在 KV Cache 侧,我们分别从算法、后训练和运行时三个维度进行优化:算法侧通过 LU-KV 压缩 KV Cache,后训练侧通过 Draft SWA 降低 Draft 模型的 KV Cache 占用,运行时侧则优化 PD 握手机制,减少传输过程中的显存预留。通过这三条路径,我们持续扩大动态运行阶段的可用显存,其中 LU-KV 在特定实验配置下可以将 KV Cache 占用压缩约 80%。
今天我的分享就到这里,谢谢大家。