SGLang 部署 Qwen3.8-27B 参数调优全记录

SGLang 部署 Qwen3.8-27B 参数调优全记录

硬件: 双 RTX 3090 24GB (GPU1 部署), Ryzen 5950X, 64GB RAM
模型: dbirks/Qwen3.8-27B-W4A16-AutoRound (compressed-tensors W4A16, 19.5GB)
引擎: SGLang 0.5.17 (lmsysorg/sglang:latest), 容器 sgl-qwen27b-gpu1
端口: :15433, GPU1 (CUDA_VISIBLE_DEVICES=1)
场景: 单人 coding agent (opencode), 子代理可能并行 2-3 请求

一、背景与选型

1.1 为什么用 SGLang 跑 Qwen3.8-27B

维度 SGLang (GPU1) llama.cpp (GPU0, 已有)
模型格式 AutoRound W4A16 (19.5GB) IQ4_XS GGUF (15.7GB)
单请求速度 46.1 t/s ~73 t/s (MTP)
3 并发聚合 130 t/s 73 t/s (串行)
工具调用 原生结构化
上下文 (单请求) 65511 131072
核心优势 并发批处理 (coding agent 多子代理) 单请求速度 + MTP

结论: 并发是 SGLang 相对 llama.cpp 的核心优势。单人 coding agent 派发多个子代理时, SGLang 的连续批处理可让 3 个请求同时高效运行 (130 vs 73 t/s 聚合)。

1.2 模型格式选型(为什么 AutoRound 而非 AWQ/GGUF)

SGLang 锁定 AWQ/Safetensors 格式 (Marlin kernel)。Qwen3.8-27B 无知名团队官方 AWQ。候选包括 dbirks AutoRound (19.5GB) 和 philbert440 AWQ (19.6GB)。

选定 dbirks AutoRound: 保留 DeltaNet 关键层 (in_proj_a/b) + 视觉塔 + MTP 头为 BF16, 9/9 校验通过。

二、核心参数结论速查

参数 说明
--dtype bfloat16 必选 GDN 混合架构 conv_states 类型
--mem-fraction-static 0.95 27B 精确甜点 (0.96+ 推理 OOM)
--kv-cache-dtype fp8_e4m3 KV 池翻倍 (比 bf16 更快 + 省显存)
--max-mamba-cache-size 15 3 并发 × S5 (coding agent 子代理场景)
--context-length 65536 单请求上限 = min(ctx, KV池 66638)
--attention-backend flashinfer fp8 必须 (triton 崩溃 fp8e4nv)
--mamba-ssm-dtype bfloat16 GDN state 减半 (79.2MB/slot)
--mamba-full-memory-ratio 0.5 显式 cache 时是死参数 (auto 模式才生效)
--reasoning-parser qwen3 勿用 qwen3-thinking (强制思考)
--tool-call-parser qwen3_coder 结构化工具调用

最终推荐配置 (docker-compose)

sgl-qwen27b-gpu1:
  image: lmsysorg/sglang:latest
  container_name: sgl-qwen27b-gpu1
  ports: ["15433:30000"]
  environment:
    - CUDA_VISIBLE_DEVICES=1
    - SGLANG_MAX_NEW_TOKENS_LIMIT=32000
    - PYTORCH_CUDA_ALLOC_CONF=expandable_segments:False
  command: >
    python3 -m sglang.launch_server
      --model-path /models/Qwen3.8-27B-W4A16-AutoRound
      --port 30000 --host 0.0.0.0
      --dtype bfloat16
      --context-length 65536
      --mem-fraction-static 0.95
      --mamba-full-memory-ratio 0.5
      --max-mamba-cache-size 15
      --attention-backend flashinfer
      --mamba-ssm-dtype bfloat16
      --kv-cache-dtype fp8_e4m3
      --trust-remote-code
      --reasoning-parser qwen3
      --tool-call-parser qwen3_coder
      --sleep-on-idle

最终性能: 1并发 46.1 / 2并发 88.9 / 3并发 130.2 t/s, KV 池 66638, 单请求上限 65511, CUDA Graph 192s 成功

三、mem-fraction 实验系列(27B 独立验证)

官方定义: mem_fraction_static = (模型权重 + KV cache 池) / GPU 总显存
35B 的 0.92 甜点不适用 27B (27B 模型轻 1GB, 可到 0.95)

3.1 fp8 KV (32.8KB/token) + flashinfer

mem-fraction KV 池 (tokens) CG 余量 CUDA Graph 推理 结论
0.92 56991 1.37GB ✅ 195s 安全
0.95 78608 0.57GB ✅ 193s ✅ 48.8 t/s 精确甜点
0.96 85813 0.49GB ✅ 194s ❌ OOM 捕获成功但推理 OOM
0.97 93019 0.24GB ✅ 201s ❌ OOM 推理完全不可用
0.98 100224 0.05GB ❌ CUBLAS失败 CG 捕获失败

关键: 0.96/0.97 捕获成功但推理 OOM (activation 需 256MB) — 这是独立于捕获的失败模式。0.95 = 捕获成功 + 推理可用的精确边界。

3.2 显存边界分析 (0.95 × 24GB = 22.8GB)

项目 大小
模型权重 17.67 GB
Mamba cache 0.80 GB (15 slots)
KV 池 2.04 GB (66638 tokens)
边界内余量 ~1.9 GB (CG buffer + activation)

用户洞察验证: KV 池被 0.95 边界锁死。定制 CG bs 无法增加 KV (KV 池在 CG 捕获前分配), 0.96+ 的 activation OOM 是硬限制 (无参数可解)。

四、并发 vs 上下文权衡

4.1 max-mamba-cache-size 数据表

> 公式: max_running_requests = cache_size // S (S=5 extra_buffer)

> 每 +1 并发 (5 slots) = -12000 KV tokens

cache-size 并发 KV 池 聚合吞吐 单请求上下文
5 1 90578 48.8 65536*
10 2 78608 89.4 65536*
15 3 66638 130.2 65511
20 4 54668 175.0 ~54000*

4.2 关键发现:单请求上下文与并发无关

实测证明: 单请求上下文 = min(context-length, KV 池), 与并发数无关:

3 并发各 48012 tokens (共144K > 池66638) 全部成功 — chunked prefill 动态复用。单请求超过 KV 池 → 报错 (不是截断)。context-length 提到 65536 → 单请求可用满 65511。

这推翻了”2 并发换更长上下文”的假设: cache15 (3并发) + ctx 65536 严格优于 cache10 (2并发) + ctx 49152 (上下文 +33%, 并发 +1)。

4.3 并发基准 (cache15 配置)

并发 墙钟 总 tokens 聚合吞吐
1 4.3s 200 46.1
2 4.5s 400 88.9
3 4.5s 591 130.2

CUDA Graph 捕获 bs=[1,2,3] = 并发甜点, 第 4 并发超捕获范围退化。

五、fp4 KV cache 慢 4 倍根因分析 (c1skill)

5.1 实验数据

配置 KV dtype backend 速度
fp8 fp8_e4m3 flashinfer 48.8
bf16 bf16 triton 49.1
fp4 fp4_mx_block16 triton 11.6
fp8 fp8_e4m3 triton ❌ 崩溃 (fp8e4nv 不支持)

5.2 根因:反量化不融合

SGLang: batched_dequantize (torch.compile 逐元素) 每层每次 KV 读取全量反量化 bf16 临时张量。llama.cpp: dequantize_V_q4_0 (forceinline) 融合在 FA kernel 内部, 零开销。

本质: 不是硬件限制, 是框架工程差异。

5.3 反量化 kernel 原型

手写 Triton kernel: diff=0 (bit-identical), 2.4-3.1x 反量化加速。但反量化只占总时间 5%, fp4 总速度仅 11.7 → ~12 t/s。fp4 补丁投入产出比低 (复杂 + 收益 3%)。

六、3090 GDN 突破方案论证

6.1 GDN kernel 硬限制 (SM86)

kernel 架构要求 3090
triton 任意 ✅ (唯一可选)
flashinfer GDN SM90+ ❌ RuntimeError
cutedsl SM100+ ❌ 启动成功但 decode 卡死
ReplaySSM batch≥64 ❌ 单并发无效

6.2 为什么 49 vs llama 73 t/s

CUDA Graph 已捕获生效 → 非 launch-bound。差距 = triton kernel GPU 执行效率 vs llama 手写 CUDA (gated_delta_net.cu 273行 1 kernel 融合)。突破需手写 CUDA kernel (成本高, 理论 49→70 t/s)。

6.3 35B 日志的启发(验证无效)

35B 用 –mamba-backend flashinfer 快 (130 t/s), 但:

35B MoE 仅 ~10 层 GDN, 27B dense 48 层。flashinfer GDN 需 SM90+, 3090 不支持。实测 27B: mamba-backend flashinfer 后 GDN 仍 Triton, 更慢 (44 vs 49)。

七、避坑记录

一、fp8 + triton 崩溃: fp8e4nv not supported — fp8 KV 必须 flashinfer

二、cutedsl 假成功: 启动显示 CuteDSLGDNKernel 但 decode 卡死 — 必须实测

三、mamba-backend 不影响 GDN kernel: 需 –linear-attn-decode-backend

四、0.96/0.97 假成功: 捕获成功但推理 OOM (activation 硬限制)

五、context-length 不影响 KV 池: KV 池由 mem-fraction 决定

六、显式 cache 时 ratio 是死参数: –mamba-full-memory-ratio 仅 auto 模式生效

七、单请求超 KV 池报错: context-length 应 = 池容量 (或略低)

八、bs=1 是坑 (llama.cpp): GGML_CUDA_GRAPH_OPT=1 多轮上下文变化致 CG 重录, 65→10-13 t/s

八、双引擎策略

场景 引擎 配置
高并发/多子代理 SGLang (GPU1) sgl-qwen27b-gpu1 :15433
单请求速度 llama.cpp (GPU0) lla-qwen27b-gpu0 :11434
长上下文 llama.cpp 131072 ctx

各取所长: SGLang 3 并发 130 t/s, llama.cpp 单请求 73 t/s + 更长上下文。

相关文档

docs/review/sglang-qwen3.8-27b-parameter-tuning-experiments-2026-08-15.md — 参数优化完整实验记录 (9章)

docs/review/c1skill-sglang-fp4-kv-slow-rootcause-2026-08-15.md — fp4 根因 c1skill 分析

docs/qwen3.8-27b-deployment-research.md — 27B 部署研究总纲

docs/sglang-35b-moe-deployment-and-tuning.md — 35B MoE 权威配置 (对比参考)

docs/24gb-vram-long-context-challenge.md — 35B 长上下文挑战

文档生成: 2026-08-15, 基于当日全部实验数据


皖ICP备2025105865号-2|皖公网安备34010402704739号