踩坑分享:SGLang,attention backend 请用 flashinfer,别用 triton —— 适用于消费级 Blackwell
-
我的AI主机是 RTX PRO 5000 48G, 之前一直用的是 vLLM + Qwen3.8 27B NVFP4. 后来在 @terry 以及 Hermes 的帮助下, 部署了 SGLang + Qwen3.8 27B NVFP4. 不过部署好之后, 总感觉长上下文时候变慢, 所以又切换回了 vLLM.
这个10.1假期, 让Agent彻底搞了一遍, 把 attention backend 从 triton 改成了 flashinfer, 结果大有改观: 长上下文从 10+ token/s 提升到了 100+ token/s.
我的AI主机配置:
项 值 GPU NVIDIA RTX PRO 5000 Blackwell, 48G (SM120), 驱动 595.91.07, CUDA 13.2 CPU AMD Ryzen 7 9700X (8C/16T) 内存 128 GB SSD WD_BLACK SN850X 4TB 系统 Ubuntu 26.04 LTS + Docker 引擎: SGLang v0.5.21(官方镜像), Qwen3.8 27B NVFP4 (RadixArk) + DFlash2 投机解码, 256K 上下文; vLLM (MTP x2) 作备用一键回退.
以下为AI生成的详细总结, 注意不同轮次的数据有差异, 是因为脚本和数据的差异, 不能相互比较. 同一轮次的A/B测试有比较意义.
总体上来说, 短coding轻松上200; 长coding 160多; 散文则只能跑到 60多到80多.
背景
之前做了一轮同口径 A/B 测试:SGLang vs vLLM(MTP x2),结果长上下文下 SGLang 惨败:
上下文长度 SGLang(旧档) vLLM MTP x2 8K 73.6 tok/s 77.6 32K 38.7 78.5 120K 12.9 70.3 当时我下的结论是:长上下文下投机解码是净亏的,交叉点大概在 20–25K,归因给了"算法性质"。生产环境不得以切回 vLLM,SGLang 搁置。
这次彻底排查发现:结论是错的,根因是一行配置
前两天找时间把 SGLang 从头查了一遍。先用隔离变量法(同镜像、同模型、同 bench,只改一个参数)逐窗口测下来,发现:
同样的镜像、同样的模型,只把
--attention-backend从triton改成flashinfer,120K 场景每步成本从 193ms 降到 28ms(便宜 6.8×),接受长度几乎不变。机制上:DFlash2 的验证阶段是"多个草稿 token 共享一次 KV 读"的路径,这条路径 flashinfer 在长上下文下做对了,triton 的后端实现在长上下文下退化。所以慢的不是"投机猜得准不准"(accept length 两臂几乎一样),而是每步的验证成本。
改完之后的成绩:
上下文 改前(triton+DFlash2) 改后(flashinfer+DFlash2) 8K 73.6 119.4 32K 38.7 111.5 120K 12.9 116.7 120K 直接 9 倍,而且反超 vLLM 66%。
顺带做了一轮 vLLM vs SGLang 同输入回放
既然 SGLang 修好了,切不切回去需要证据。对两个引擎发逐字节相同的请求(thinking off、temp 0),每场景重复 3 次取中位:
场景 vLLM SGLang 冷 prefill @129K 3,322 tok/s 4,169 (+26%) decode @54.5K 67.4 93.0 (+38%) decode @129K 63.4 80.3 (+27%) 短上下文 decode 80.8 79.4(打平) 并发 4 聚合 210–229 380–401 (~1.7×) 能耗 / 1K 输出 token 5,519 J 3,386 J(−39%) 原尺寸扫描图(1275×1650) HTTP 400 OK 结论:SGLang 在 prefill、长上下文解码、并发、vision 上全面领先(短上下文解码打平),能耗低 39%,而且只有它吃得了原尺寸扫描图(vLLM 直接 400 拒绝)。主力切回 SGLang,vLLM 留作一键回退。
上网查了一圈:不是孤例
写这篇之前我上网搜了下,发现这个坑社区早有反应:
-
SGLang 官方 issue #2271《Optimize triton decoding kernels for long context》直接点题:官方自己测出 triton decode kernel 在长上下文掉速严重,而 flashinfer 几乎不掉。原帖数据(同模型同机):
后端 上下文 200 上下文 2000 triton 147.64 tok/s 126.41(↓14%) flashinfer 144.17 143.35(基本不掉) 那个时代的差距还不算夸张,但方向一致——triton 的 decode 路径对上下文长度敏感,flashinfer 不敏感。到我这张卡(消费级 Blackwell)+ DFlash2 上,这个退化被放大成了 6.8 倍。
-
官方文档的 attention backend 选型指南 里,Blackwell 的默认/推荐就是
flashinfer;消费级 Blackwell(RTX PRO 5000/6000、RTX 50 系列这一档,内部代号 SM120)的 full attention 官方支持triton或flashinfer二选一——也就是说我旧档挂triton不算违规,但官方推荐的那条路一直摆在旁边,我没走。 -
SGLang 还有一个 SM120 性能优化专项 thread(#19637),社区一直在给这批新卡抠 attention backend 的选择——能看出消费级 Blackwell 是新架构、坑比较多,不只是我一个人踩。
给大家的几点教训
- "投机解码在长上下文赚不赚"这类结论,必须带上当时的 attention backend。 我的"净亏"结论只在 triton 下成立,后端一换就反转。先定后端,再谈投机,顺序反了会得出可移植性为零的结论。
- 判断投机赚不赚的通式是
accept length ÷ 每步成本相对倍数 > 1,accept 长度本身不是判据——两臂 accept 几乎一样,结论却可以相反。 - 官方 cookbook 对 Blackwell 消费卡就是建议用
flashinfer,我旧档一直挂着triton,血泪教训。 - 诚实说一个局限:我这轮 A/B 里两边跑的是不同的 NVFP4 检查点(vLLM 侧是 orcarouter 版,SGLang 侧是 RadixArk 版),"SGLang 更快"里混着模型因素,想彻底拆干净需要同一检查点双引擎各服务一次。
最终生产配置(供参考)
Docker 运行 SGLang(官方镜像,v0.5.21 系列),启动参数:
sglang serve \ --model-path /models-ai/Qwen3.8-27B-NVFP4-RadixArk \ --context-length 262144 \ --max-total-tokens 262144 \ --kv-cache-dtype fp8_e4m3 \ --mem-fraction-static 0.90 \ --max-running-requests 4 \ --max-mamba-cache-size 20 \ --mamba-ssm-dtype bfloat16 \ --mamba-radix-cache-strategy extra_buffer \ --speculative-algorithm DFLASH \ --speculative-draft-model-path /models-ai/Qwen3.8-27B-DFlash2 \ --speculative-num-draft-tokens 8 \ --attention-backend flashinfer \ --linear-attn-backend triton \ --chunked-prefill-size 2048 \ --max-prefill-tokens 8192 \ --cuda-graph-max-bs-decode 8 \ --cuda-graph-max-bs-prefill 1024 \ --cuda-graph-backend-prefill disabled \ --tool-call-parser qwen3_coder \ --reasoning-parser qwen3关键改动就是其中一行:
--attention-backend triton → flashinfer(唯一影响大的改动)。
注意--linear-attn-backend保持triton——消费级 Blackwell 上 linear attention 没有 flashinfer 可选,已实测否证。改一行配置,120K 解码从 12.9 到 116.7 tok/s。希望有人从中少走弯路。
-
-
-
-
-
,
W williamlouis 引用了 此主题


