Skip to content

Instantly share code, notes, and snippets.

@imfht
Created April 6, 2026 03:10
Show Gist options
  • Select an option

  • Save imfht/50c7a77d68835ef0cfdb129f3b21a6a4 to your computer and use it in GitHub Desktop.

Select an option

Save imfht/50c7a77d68835ef0cfdb129f3b21a6a4 to your computer and use it in GitHub Desktop.
RTX 5090 单卡 LLM 推理部署指南 (Qwen3.5-35B-A3B + llama.cpp)

RTX 5090 单卡 LLM 推理部署指南

基于 Qwen3.5-35B-A3B MoE 在 RTX 5090 (32GB) 上的实战经验。 从 vLLM 5 tok/s 折腾到 llama.cpp 190 tok/s 的全过程。

结论先行

指标 最终配置 原始配置 (vLLM)
引擎 llama.cpp vLLM 0.17.1 Docker
模型 Qwen3.5-35B-A3B (MoE, 3B active) Qwen3.5-27B-AWQ (dense)
Decode 速度 190 tok/s 5 tok/s
翻译延迟 0.2s (thinking off) 60s
最大上下文 178K tokens (实测 needle 通过) ~20K
并发 4 路 1 路
日产量 (4路满载) 27M tokens/天 ~2M
启动时间 5s (mlock) 2+ min

一、环境问题

1.1 CUDA 版本

RTX 5090 = Blackwell = sm_120。必须 CUDA 12.8+

  • 系统默认 PyTorch 2.6 + cu124 → no kernel image is available 直接报错
  • 解决:用 ~/llm/vllm_venv (PyTorch 2.10 + cu128) 或 llama.cpp 自编译 (cu130)

1.2 llama.cpp 编译

确认编译时包含 sm_120:

system_info: CUDA : ARCHS = 1200 | USE_GRAPHS = 1 | FA_ALL_QUANTS = 1 | BLACKWELL_NATIVE_FP4 = 1

二、为什么不用 vLLM

在 RTX 5090 上测了 vLLM 0.17.1 和 0.18.1,都有严重问题:

问题 原因
--enforce-eager 必须开 不开 CUDA graphs 会在首次请求时 OOM crash
开了 enforce-eager 后 ~5 tok/s 27B dense 模型在 eager mode 下极慢
--enable-prefix-caching crash Qwen3.5 hybrid attention + Mamba cache "experimental",直接崩
cu130-nightly (0.18.1) 视觉 encoder 吃光显存 KV cache 从 36K 缩到 6K tokens
--gpu-memory-utilization > 0.82 crash 高 util + enforce-eager + 首次请求 = OOM

结论:vLLM 在单卡 5090 + Qwen3.5 hybrid attention 上不好使。

三、llama.cpp 最优配置

3.1 模型选择

模型 格式 大小 tok/s 推荐
Qwen3.5-35B-A3B UD-Q4_K_XL GGUF 19 GB 190 ✅ 最佳
Qwen3.5-35B-A3B MXFP4_MOE GGUF 21 GB 167 ❌ 更慢更大
Qwen3.5-27B Q4_K_M (dense) GGUF 16 GB 66 ❌ 慢 3x

UD-Q4_K_XL = Unsloth Dynamic 量化,重要层用更高精度。

3.2 KV Cache 量化

KV 格式 tok/s 质量 推荐
F16 / F16 195 baseline
Q4_0 K + Q8_0 V 188 无损
Q4_0 / Q4_0 186 无损 OK
Q5_0 / Q5_0 153 无损 ❌ 反而慢
IQ4_NL / IQ4_NL 38 无损 ❌ 5x 慢,别用

IQ4_NL 是坑:理论上信息最优,实际计算开销巨大。

3.3 Thinking 模式控制

Qwen3.5 默认开 thinking (<think>...</think>),翻译一句话花 400 tokens 在推理上。

控制方式 效果 适用
--reasoning off (全局) 所有请求关闭 thinking 纯翻译服务
--reasoning auto (默认) + 客户端控制 按请求开关 ✅ 混合场景
--reasoning-budget 100 限制 thinking 最多 100 tokens ⚠️ 可能截断出错

客户端关闭 thinking(推荐):

{
  "chat_template_kwargs": {"enable_thinking": false}
}

Python SDK:

resp = client.chat.completions.create(
    model="gpt-4o",
    messages=[...],
    extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)

3.4 上下文容量

A3B MoE 只有 10 个 full-attention 层(64 层中),KV cache 极其省:

Context Prefill 时间 VRAM 增长 Needle 命中
9K 1.2s +0 MB
53K 6.6s +88 MB
107K 16.3s +192 MB
178K 34.9s +330 MB

模型训练长度 262K。32GB 卡实测可到 178K+。

3.5 并发性能

并发 聚合吞吐 单请求 tok/s
1 190 190
2 290 145
4 356 96

混合负载 30 秒压测(2 agent + 2 翻译):313 tok/s → 日产 27M tokens

四、systemd 配置

主服务:A3B (GPU)

# /etc/systemd/system/sglang.service
[Unit]
Description=Qwen3.5-35B-A3B via llama.cpp (Text + Vision)
After=network.target

[Service]
Type=simple
Restart=always
RestartSec=5
TimeoutStartSec=300

ExecStart=/16tb/llm/llama.cpp/build/bin/llama-server \
  -m /16tb/llm/Qwen3.5-35B-A3B-GGUF/Qwen3.5-35B-A3B-UD-Q4_K_XL.gguf \
  --mmproj /16tb/llm/Qwen3.5-35B-A3B-GGUF/mmproj-F16.gguf \
  -ngl 99 \
  -c 131072 \
  -np 4 \
  --host 0.0.0.0 \
  --port 18082 \
  --flash-attn on \
  -ctk q4_0 \
  -ctv q8_0 \
  --mlock \
  --cont-batching \
  --cache-prompt \
  --reasoning-format deepseek

[Install]
WantedBy=multi-user.target

翻译服务:1.5B (CPU,零 GPU)

# /etc/systemd/system/llm-translate.service
[Unit]
Description=Qwen2.5-1.5B Translation (CPU only)
After=network.target

[Service]
Type=simple
Restart=always
RestartSec=5

ExecStart=/16tb/llm/llama.cpp/build/bin/llama-server \
  -m /16tb/llm/Qwen2.5-1.5B-Instruct-Q8.gguf \
  -ngl 0 \
  -c 4096 \
  -np 4 \
  --host 0.0.0.0 \
  --port 18083

[Install]
WantedBy=multi-user.target

如果有 GTX 1060 6GB 等闲置小卡,改成 -ngl 99 offload 到 GPU,翻译速度从 14 tok/s → ~50 tok/s。

五、TurboQuant / KV Cache 压缩

结论:在 llama.cpp 上不需要

方案 压缩 在 llama.cpp 上
llama.cpp -ctk q4_0 4x ✅ 一个参数,原生内核
TurboQuant (0xSero) ~5x ❌ 需要 Python + vLLM
我们的 Tiered (Hot/Warm/Cold) 理论 7.5x ❌ 研究阶段
vLLM FP8 KV 2x ❌ 只在 vLLM

llama.cpp 原生的 Q4 KV cache 已经 4x 压缩、质量无损、速度几乎不掉。 TurboQuant 的理论更优(无偏估计),但工程上 llama.cpp 的简单 per-group 量化更实用。

对 TurboQuant 的发现(如果你用 vLLM)

  • Layer 0 必须跳过:Qwen2.5 第一层 K 的 norm 是其它层的 40x,TurboQuant 旋转假设失效
  • 2-bit V 不可用:39% 相对误差,生成崩溃
  • cos sim 骗人:attention output cos=0.88 看起来 OK,但实际生成是乱码
  • 真正有效:2-tier (hot 5% FP16 + warm 95% 4b+4b) 在 1.5B 上 100% greedy match

六、避坑清单

现象 解决
默认 PyTorch 不支持 sm_120 CUDA kernel error 用 vllm_venv 或 llama.cpp
vLLM enforce-eager 5 tok/s 换 llama.cpp
vLLM CUDA graphs 首次请求 OOM crash 加 --enforce-eager(治标)或换 llama.cpp
vLLM prefix-caching + Qwen3.5 启动后 crash 别用(experimental)
cu130-nightly 视觉 encoder KV cache 缩到 6K 用 0.17.1 latest 或 llama.cpp
IQ4_NL KV cache 5x 慢 用 Q4_0
MXFP4 模型权重 比 UD-Q4_K_XL 慢 10% 用 UD-Q4_K_XL
Thinking 模式吃 token 翻译一句话 400 tokens enable_thinking: false--reasoning off
Q5 KV cache 比 Q4 还慢 用 Q4 K + Q8 V
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment