单卡 L20 48GB实测 | 同是 Q8_0,为什么 Qwen3.6 在 llama.cpp 长上下文下比 Qwen3.5 更慢?

关键词: Qwen3.5、Qwen3.6、llama.cpp、GGUF、Q8_0、TTFT、Prefill、长上下文、L20 48GB、推理性能、单卡部署

先看结论

  • 实测: 在同为 Q8_0 的前提下,Qwen3.6-35B-A3Bllama.cpp 单卡长上下文场景下仍然比 Qwen3.5-35B-A3B 更慢。
  • 实测: 在约 32K 输入规模下,Qwen3.6 Q8_0 相比 Qwen3.5 Q8_0 的端到端时延增加约 6.9%TTFT 增加约 7.1%,输出速度下降约 4.1%
  • 实测: 在约 64K 输入规模下,这个差距继续扩大到端到端时延 +11.7%TTFT +13.2%,但 decode 速度几乎一样。
  • 推导: 这说明当前差距主要发生在 Prefill / 首 token 之前,不是生成阶段本身。
  • 实测: 如果把 Qwen3.6 的量化从 Q8_0 换成 UD-Q8_K_XL,在约 32K 输入规模下,还会再额外引入约 5% 左右的端到端性能损失,且主要还是体现在 TTFT
  • 判断: 如果你要比较 Qwen3.5Qwen3.6 的模型代际差异,至少要先把量化格式控制住;否则很容易把"模型更慢"误判成"量化更重"。

一、为什么这篇文章值得写

我最开始做这轮测试时,得到了一组看起来很直观的结果:

  • Qwen3.5-35B-A3B-Q8_0.gguf
  • 对比
  • Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf

结果显示 Qwen3.6 明显更慢。

但这组结论有一个明显问题:

模型版本和量化格式同时变了。

也就是说,当时我比较的其实不是:

  • Qwen3.5 vs Qwen3.6

而是:

  • Qwen3.5 + Q8_0
  • vs
  • Qwen3.6 + UD-Q8_K_XL

这在工程上当然也有参考价值,因为真实部署时"模型 + 量化 + 引擎"本来就是一个整体组合;但如果要回答:

Qwen3.6 本身在 llama.cpp 下是不是比 Qwen3.5 更慢?

那就必须补一组更公平的实验:

  • Qwen3.5-35B-A3B-Q8_0
  • Qwen3.6-35B-A3B-Q8_0

我这篇文章,就是基于补完后的数据,把这个问题尽量拆干净。

二、测试对象与测试环境

1. 测试对象

本文涉及三组模型文件:

模型 文件 用途
Qwen3.5-35B-A3B Qwen3.5-35B-A3B-Q8_0.gguf 和 Qwen3.6 Q8_0 做公平对比
Qwen3.6-35B-A3B Qwen3.6-35B-A3B-Q8_0.gguf 和 Qwen3.5 Q8_0 做公平对比
Qwen3.6-35B-A3B Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf 用来观察量化格式对结果的额外影响

2. 测试环境

  • GPU:NVIDIA L20 48GB 单卡
  • 推理引擎:llama.cpp 服务模式
  • 接口形式:OpenAI 兼容接口
  • 压测脚本:scripts/test_long_context_concurrency.py
  • 测试方式:单并发、热态、每组 warmup 1 轮 + measured 5

这里有两个很重要的口径说明:

  1. scripts/test_long_context_concurrency.py 用的是 按字符数近似构造长上下文 的方法,target_chars=50000target_chars=100000 更接近工程上的"约 32K / 约 64K 输入规模",不是严格按 prompt token 精确对齐。
  2. 这轮测试是 单并发 smoke benchmark,适合看长上下文体感和单路性能差异,不适合直接上升为严格的并发 SLO 结论。

三、压测方法

本文的核心对比都来自同一套脚本、同一套参数骨架:

bash 复制代码
python3 test_long_context_concurrency.py \
  --base-url http://localhost:PORT \
  --model MODEL_NAME \
  --concurrency 1 \
  --target-chars TARGET_CHARS \
  --max-tokens 128 \
  --warmup-rounds 1 \
  --rounds 5

其中:

  • target_chars=50000:作为约 32K 输入规模参考
  • target_chars=100000:作为约 64K 输入规模参考
  • max_tokens=128:固定输出长度上限,避免 completion token 差异过大

脚本默认会统计这些指标:

  • Round overall elapsed
  • Per-request TTFT
  • Per-request output speed
  • Per-request completion throughput (E2E)

四、先看"容易误判"的结果:不同量化会明显污染比较

先放一组很有代表性的结果:在约 32K 输入规模下,Qwen3.6 Q8_0Qwen3.6 UD-Q8_K_XL 的表现并不一样。

1. Qwen3.6 同模型不同量化(约 32K)

指标 Qwen3.6 Q8_0 Qwen3.6 UD-Q8_K_XL 差异
总耗时 10.28s 10.82s +5.3%
TTFT 9.02s 9.55s +5.9%
输出速度 101.48 tok/s 100.80 tok/s -0.7%
E2E completion throughput 12.48 tok/s 11.86 tok/s -5.0%

2. 这组结果说明什么

这组对比非常重要,因为它直接说明:

  • 实测: 即使模型版本不变,只改量化格式,llama.cpp 下的端到端性能也会发生明显变化。
  • 推导: UD-Q8_K_XLQwen3.6 的额外开销,主要也落在 TTFT / Prefill 阶段,而不是 decode 阶段。

换句话说,如果你拿:

  • Qwen3.5 Q8_0
  • 去对比
  • Qwen3.6 UD-Q8_K_XL

那么你看到的差距,不会只来自模型代际升级,还会被量化格式进一步放大。

五、真正公平的核心对比:Q8_0 vs Q8_0

下面才是这篇文章最核心的对照组。

1. 约 32K 输入规模对比

Qwen3.5-35B-A3B-Q8_0

指标 数值
总耗时 9.62s
TTFT 8.42s
输出速度 105.81 tok/s
E2E completion throughput 13.32 tok/s

Qwen3.6-35B-A3B-Q8_0

指标 数值
总耗时 10.28s
TTFT 9.02s
输出速度 101.48 tok/s
E2E completion throughput 12.48 tok/s

对比结论(约 32K)

指标 差异
总耗时 +6.9%
TTFT +7.1%
输出速度 -4.1%
E2E completion throughput -6.3%

这说明:

  • 实测: 在同为 Q8_0 的情况下,Qwen3.6 仍然比 Qwen3.5 慢。
  • 推导: 但真实差距更接近 6% ~ 7%,而不是之前混入 UD-Q8_K_XL 后看上去的 11% ~ 13%

2. 约 64K 输入规模对比

Qwen3.5-35B-A3B-Q8_0

指标 数值
总耗时 11.99s
TTFT 10.67s
输出速度 96.93 tok/s
E2E completion throughput 10.70 tok/s

Qwen3.6-35B-A3B-Q8_0

指标 数值
总耗时 13.39s
TTFT 12.08s
输出速度 96.70 tok/s
E2E completion throughput 9.57 tok/s

对比结论(约 64K)

指标 差异
总耗时 +11.7%
TTFT +13.2%
输出速度 -0.2%
E2E completion throughput -10.6%

这组数据比 32K 更有意思:

  • 实测: 到约 64K 输入规模时,Qwen3.6Qwen3.5 的 decode 速度已经几乎一样。
  • 推导: 差距几乎全部集中在 首 token 之前 ,也就是 Prefill / TTFT

六、把 32K 和 64K 放在一起看,趋势就很清楚了

如果把前面的两组 Q8_0 vs Q8_0 结果放到一起,趋势非常稳定:

场景 Qwen3.5 总耗时 Qwen3.6 总耗时 总耗时差异 Qwen3.5 TTFT Qwen3.6 TTFT TTFT 差异
约 32K 9.62s 10.28s +6.9% 8.42s 9.02s +7.1%
约 64K 11.99s 13.39s +11.7% 10.67s 12.08s +13.2%

再看两者各自从 32K 走到 64K 的退化:

Qwen3.5

  • 总耗时:9.62s -> 11.99s,增加约 24.6%
  • TTFT:8.42s -> 10.67s,增加约 26.7%

Qwen3.6

  • 总耗时:10.28s -> 13.39s,增加约 30.3%
  • TTFT:9.02s -> 12.08s,增加约 33.9%

这说明:

  • 实测: 两个模型都会随着上下文变长而变慢。
  • 推导: Qwen3.6 在当前 llama.cpp 单卡配置下,对上下文长度增长更敏感。
  • 判断: 如果你的业务是长 prompt、代码库理解、RAG 长文分析、Agent 大上下文拼装,那么 Qwen3.6 的用户体感劣势会主要表现成"等第一口回答更久"。

七、为什么这件事值得关注:问题主要不在 decode,而在 Prefill

很多人做模型性能对比时,只盯着:

  • tok/s
  • 输出速度

但这轮实验里最值得记住的,其实不是 decode 速度,而是:

同为 Q8_0Qwen3.6 相对 Qwen3.5 的主要损失,发生在 TTFT / Prefill

这对工程判断很重要,因为:

1. 如果你的业务更像"长 prompt + 短回答"

比如:

  • RAG 总结
  • 长文归纳
  • 大仓库阅读后回答
  • 工单材料汇总后给建议

那用户最敏感的往往不是每秒多吐几个 token,而是:

为什么我点了发送之后,要多等一秒多才开始回答?

在这种场景下,Qwen3.6 的这部分差距会非常可感知。

2. 如果你的业务更像"短 prompt + 长输出"

Qwen3.6Qwen3.5 的体感差距可能不会像长上下文场景里这么大。

因为从现有数据看,至少在约 64K 输入规模下,两者 decode 速度已经接近重合。

八、这能不能直接说明"Qwen3.6 不如 Qwen3.5"?

不能这样下结论。

更准确的说法是:

在当前 llama.cpp 单卡 L20 48GB、GGUF Q8_0、单并发长上下文测试组合下,Qwen3.6-35B-A3B 的端到端性能弱于 Qwen3.5-35B-A3B,而且差距主要出现在 TTFT / Prefill,并会随着上下文长度增加而扩大。

这里我特意强调"当前组合",是因为这类结果还可能同时受这些因素影响:

  • llama.cpp 对不同模型结构的 kernel 路径差异
  • GGUF 转换与量化实现差异
  • MoE/长上下文下的 runtime 行为差异
  • 推理引擎本身对模型的适配成熟度

也就是说,这更像是一个:

  • 模型 + 量化 + 引擎 + 硬件

组合结论,而不是抽象层面的"模型智力结论"。

九、对开发者的工程建议

基于这轮实测,我会给出下面几条更偏工程化的建议。

1. 比较模型代际差异时,先把量化控制住

这是本文最想强调的一点。

如果你要比较:

  • Qwen3.5Qwen3.6

那尽量至少满足:

  • 同引擎
  • 同量化格式
  • 同上下文规模
  • 同并发
  • 同输出长度上限

否则你最后很容易比较成:

  • 模型版本差异
  • 量化差异
  • 引擎差异

三者一起混合的总效果。

2. 做长上下文压测时,不要只看输出速度

在这轮测试里,如果只盯 output speed,你会得出一个很容易误导的结论:

两个模型差不多。

但真正影响用户体感的,是:

  • TTFT
  • E2E elapsed

所以长上下文场景下,至少要同时看:

  • TTFT
  • output speed
  • completion throughput (E2E)

3. 如果你更在意长上下文体感,当前 Qwen3.5 Q8_0 更稳

至少在这套单卡 llama.cpp 组合下,可以先做一个相对保守的判断:

  • 判断: 如果优先目标是"长上下文首 token 更快、单卡体感更稳",当前 Qwen3.5-35B-A3B-Q8_0 仍然是更省心的选择。

4. 如果你更在意 Qwen3.6 的能力增益,后续值得继续补引擎对照

这篇文章只回答了:

  • llama.cpp 下会怎样

但还没有回答:

  • 换到 SGLang + FP8
  • vLLM + FP8

之后,这个差距会不会缩小,甚至反转。

如果后续补完这组测试,才能进一步判断:

  • 这是 Qwen3.6 本身的长上下文成本更高
  • 还是当前 llama.cpp 路径对它不够友好

十、最后收个尾

这轮实验最有价值的地方,不是简单得到一句:

Qwen3.6Qwen3.5 慢。

而是把这件事拆成了三层:

  1. 量化不同,会污染比较结果。
  2. 量化控制到 Q8_0 之后,Qwen3.6 仍然更慢。
  3. 这个"更慢"主要体现在 Prefill / TTFT,并且上下文越长,差距越明显。

如果你也在做本地部署、长上下文 RAG、代码仓库问答或者 Agent 场景,这三个判断会比一句泛泛的 benchmark 更有参考价值。

因为它们更接近真实系统里的那个问题:

用户为什么会觉得慢,慢到底慢在哪一段。

附:本文涉及的关键原始数据

约 32K:Qwen3.5 Q8_0

text 复制代码
Round overall elapsed: mean=9.62s
Per-request TTFT: mean=8.42s
Per-request output speed: mean=105.81 tok/s
Per-request completion throughput (E2E): mean=13.32 tok/s

约 32K:Qwen3.6 Q8_0

text 复制代码
Round overall elapsed: mean=10.28s
Per-request TTFT: mean=9.02s
Per-request output speed: mean=101.48 tok/s
Per-request completion throughput (E2E): mean=12.48 tok/s

约 32K:Qwen3.6 UD-Q8_K_XL

text 复制代码
Round overall elapsed: mean=10.82s
Per-request TTFT: mean=9.55s
Per-request output speed: mean=100.80 tok/s
Per-request completion throughput (E2E): mean=11.86 tok/s

约 64K:Qwen3.5 Q8_0

text 复制代码
Round overall elapsed: mean=11.99s
Per-request TTFT: mean=10.67s
Per-request output speed: mean=96.93 tok/s
Per-request completion throughput (E2E): mean=10.70 tok/s

约 64K:Qwen3.6 Q8_0

text 复制代码
Round overall elapsed: mean=13.39s
Per-request TTFT: mean=12.08s
Per-request output speed: mean=96.70 tok/s
Per-request completion throughput (E2E): mean=9.57 tok/s
相关推荐
d1z8888 天前
(二十)32天GPU测试从入门到精通-llama.cpp CPU/GPU 混合推理day18
人工智能·llama·显卡·llama.cpp
gergul10 天前
在llama-cpp-python中使用自己编译的llama.cpp,解决pip install llama-cpp-python报错
python·llama·llama.cpp·llamacpppython
晨欣13 天前
单卡 48GB 实测:Gemma 4 26B A4B、Gemma 4 31B、gpt-oss-20b 三模型部署与并发对比
google·openai·nvidia·vllm·llama.cpp·gpt-oss-20b·gemma4
belldeep16 天前
AI: ggml llama.cpp 与 BitNet 模型介绍
人工智能·llama.cpp·bitnet·gguf·ggml
love530love24 天前
【独家资源】Windows 本地部署微软 BitNet b1.58: Flash Attention + CUDA GPU 加速 (sm_86) + AVX2 优化 + 1.58bit 量化
人工智能·windows·microsoft·llama.cpp·bitnet·flash attention·bitlinear_cpp
love530love1 个月前
OpenClaw搭配LM Studio VS Ollama:Windows CUDA实战深度对比与完全配置指南
人工智能·windows·vllm·ollama·llama.cpp·lm studio·openclaw
晨欣1 个月前
llama.cpp 设计巧思:多模态模型拆分加载,按需使用视觉能力(配图由谷歌的Nano Banana模型倾情生成)
llm·谷歌·cursor·llama.cpp·gguf模型·gpt5.4
JohnCHsu1 个月前
性能干翻235B,单卡私有化部署OpenClaw
ai·agent·llama.cpp·openclaw
illuspas2 个月前
MI50运行GLM-4.7-Flash的速度测试
glm·llama.cpp·mi50