Qwen3.6-35B-A3B 推理速度实测:MoE 高并发甜点在哪?

Qwen3.6-35B-A3B 推理速度实测:MoE 高并发甜点在哪?

架构解析:MoE 稀疏激活下的算力效率

要理解 Qwen3.6-35B-A3B 为何能在有限硬件上跑得动,首先得打破一个常见的直觉误区:很多人看到“35B”就下意识觉得需要巨大的显存来存储所有参数,看到“3B”又以为推理时只加载 3B 的权重。这种线性思维在 MoE(混合专家)架构面前完全失效。MoE 的核心逻辑,就像一家拥有 35 位资深顾问的咨询公司。当客户(Token)走进来时,并不是所有 35 位顾问都同时参与讨论,而是由路由机制挑选出最相关的几位(激活参数 3B)进行解答。

然而,这里有一个致命的硬件陷阱:“只算 3B”不等于“只存 3B”。在 MoE 模型中,推理时全部专家权重必须完整驻留显存。稀疏激活只降低了计算量(FLOPs),并没有降低显存占用(Memory Footprint)。这就好比那 35 位顾问虽然只有 3 位在开会,但公司必须为所有 35 人提供工位和档案柜,否则路由机制无法随时调用其他专家。

这一特性直接决定了我们的硬件选型逻辑。Qwen3.6-35B-A3B 在 Q4_K_M 量化下,权重体积约为 22GB。这意味着,无论激活参数多小,你的显卡必须能装下这 22GB 的“全员档案”。

为了精确计算显存需求,我们需要将系统开销和 KV Cache 纳入考量。以下是基于权威数据的显存预算计算:

import math

# 基础参数
weight_gb = 22.0          # Q4_K_M 量化权重体积
system_overhead_gb = 1.5  # 系统基础开销
kv_cache_per_1k_gb = 0.075 # KV Cache 每 1K 上下文占用 (根据 4K=0.3GB 反推: 0.3/4=0.075)

def calculate_vram(context_length_k):
    """
    计算指定上下文长度下的总显存需求
    """
    kv_cache_gb = kv_cache_per_1k_gb * context_length_k
    total_vram_required = weight_gb + system_overhead_gb + kv_cache_gb
    return total_vram_required

# 验证 4K 上下文
context_4k = 4
total_4k = calculate_vram(context_4k)
print(f"4K 上下文下总显存需求: {total_4k:.1f} GB")

# 验证 8K 上下文
context_8k = 8
total_8k = calculate_vram(context_8k)
print(f"8K 上下文下总显存需求: {total_8k:.1f} GB")

根据上述计算,在 4K 上下文下,总显存占用为 23.8GB(22GB 权重 + 22GB 系统 + 1.5 GB KV Cache)。这解释了为什么 16GB 显卡(如 RTX 4060 Ti)完全无法运行该模型,而 24GB 显卡(如 RTX 4090/3090)虽然能跑,但剩余空间仅为 -7.5 GB,极其紧张。

这里有一个重要的可操作性建议:在评估 MoE 模型的硬件需求时,不要看激活参数量(3B),而要看总参数量(35B)对应的量化后权重体积。激活参数量决定了你的推理速度(算力效率),而总参数量决定了你的部署门槛(显存容量)。

在软件栈的选择上,格式与框架的匹配是避免性能瓶颈的第一道关卡。Qwen3.6-35B-A3B 的 Q4_K_M 量化版本通常以 GGUF 格式分发。根据官方技术文档,GGUF 格式的最佳搭档是 llama.cpp 或 Ollama。虽然 vLLM 也支持加载 GGUF 格式,但在本地部署场景下,llama.cpp 对量化模型的优化更为成熟且资源占用更低。

这里需要特别澄清一个常见的参数误解。在 llama.cpp 中,--no-mmap 参数常被误认为是“强制将模型加载进显存”的开关,实际上它仅用于禁用内存映射(即直接读取文件到内存,而非按需加载),并不控制 GPU 层数。真正控制模型卸载到 GPU 的参数是 -ngl--gpu-layers

以下是针对 RTX 4090 24GB 显存的推荐启动命令:

llama-server \
  -m qwen3.6-35b-a3b-q4_k_m.gguf \
  -ngl 999 \
  -c 4096 \
  --no-mmap \
  -t 16

在上述配置中,-ngl 999 是一个惯用技巧,用于请求将所有可能的层都卸载到 GPU。-c 4096 设定了 4K 的上下文窗口,对应显存预算表中的 22GB KV Cache 开销。--no-mmap 在此处用于确保权重文件不被操作系统分页,从而保证加载速度,但请注意,它本身不决定数据是否进入显存,那是 -ngl 的工作。

对于使用 vLLM 的用户,虽然其支持 GGUF,但需注意 vLLM 的 --gpu-memory-utilization 参数。该参数表示可用显存的比例,必须满足 X × 显存容量 ≥ 权重 + KV + 系统开销。例如,在 24GB 显卡上,若设定利用率为 0.95,则可用显存约为 0.5 GB,刚好覆盖 23.8GB 的总需求(含少量缓冲),配置需谨慎。

部署环境的准备不仅仅是硬件的堆砌,更是对 MoE 架构特性的尊重。只有当权重完整驻留显存,且 KV Cache 拥有足够的空间时,Qwen3.6-35B-A3B 才能发挥其稀疏激活的算力优势。

明确了硬件底线和软件配置后,我们便搭建好了一个能够真实反映 Qwen3.6-35B-A3B 性能的测试舞台。接下来,我们将在这个舞台上,通过改变并发请求的数量,探索 MoE 架构在高并发场景下的“甜点”究竟位于何处。

部署环境与前置条件

在深入探讨 Qwen3.6-35B-A3B 的推理速度之前,我们必须先厘清一个核心误区:MoE 架构的“高效”并非意味着部署门槛的降低,而是对硬件资源分配提出了更精细的要求。对于这款 35B 参数的模型而言,其 Q4_K_M 量化后的权重体积约为 22GB。这里有一个至关重要的物理事实:尽管 MoE 模型在推理时仅激活部分专家(A3B 意味着激活参数约为 3B),从而大幅降低了计算负载,但所有专家权重必须完整驻留在显存中。稀疏激活只降低了计算量,绝不降低显存占用。这意味着,你不能指望用一张 12GB 或 16GB 的显卡通过“部分加载”来运行它,因为一旦权重无法完整放入显存,性能将因频繁的 CPU-GPU 数据交换而崩塌。

根据显存预算权威表,Q4_K_M 量化权重占用 22GB,加上 1.5GB 的系统开销,基础占用已达 23.5 GB。若我们设定常见的 4K 上下文窗口,KV Cache 需额外占用 0.3 GB,总占用为 23.8GB。此时,一张 24GB 显存的显卡(如 RTX 4090 或 3090)剩余空间仅为 0.5 GB,处于极度紧张状态;若上下文扩展至 8K,总占用升至 24.2GB,24GB 显卡将溢出 22GB。因此,若要保证稳定的高并发测试环境,32GB 显存的显卡(如 RTX 5090 或 A100 40G/80G 系列中的 32G 配置)是更稳妥的选择,其在 4K 上下文下仍有 0.2GB 的剩余空间,足以应对突发负载。

在软件栈的选择上,格式与框架的匹配是避免性能瓶颈的第一道关卡。Qwen3.6-35B-A3B 的 Q4_K_M 量化版本通常以 GGUF 格式分发。根据官方技术事实,GGUF 格式的主路径加载器是 llama.cpp、Ollama 或 MLX。虽然 vLLM 官方文档确认支持加载 GGUF 格式,但在追求极致吞吐量的评测场景中,llama.cpp 因其对量化格式的底层优化和更灵活的 GPU 层数控制,往往是本地部署的首选。

这里需要特别澄清一个常见的参数误解。在 llama.cpp 中,--no-mmap 参数常被误认为是“强制将模型加载进显存”的开关,实际上它仅用于禁用内存映射,让权重文件直接读入内存(RAM),这反而可能增加 CPU 内存压力。真正控制模型层数卸载到 GPU 的参数是 -ngl(或 --gpu-layers)。对于 35B 的 MoE 模型,为了确保所有专家权重驻留显存,我们通常需要将 -ngl 设置为最大值(或接近最大值,取决于具体层数划分),以确保没有任何专家权重被留在 CPU 上。

# 示例:llama.cpp 启动 Qwen3.6-35B-A3B (Q4_K_M) 的推荐配置
# 假设模型文件为 qwen3.6-35b-a3b-q4_k_m.gguf
# 目标:确保所有层卸载至 GPU,避免 CPU 参与专家计算

./llama-cli \
  -m qwen3.6-35b-a3b-q4_k_m.gguf \
  -ngl 999 \
  -c 4096 \
  -t 16 \
  --no-mmap \
  -p "Hello, Qwen3.6"

在上述配置中,-ngl 999 是一个惯用技巧,用于请求将所有可能的层都卸载到 GPU。-c 4096 设定了 4K 的上下文窗口,对应显存预算表中的 22GB KV Cache 开销。-t 16 则建议根据 CPU 物理核心数调整,虽然 MoE 推理主要依赖 GPU,但 CPU 仍需处理输入预处理和输出解码。

对于使用 vLLM 的用户,虽然其支持 GGUF,但需注意 vLLM 的 --gpu-memory-utilization 参数。该参数表示可用显存的比例,必须满足 X × 显存容量 ≥ 权重 + KV + 系统开销。以 24GB 显卡为例,若设置利用率为 0.9,可用显存为 0.5 GB,小于 22GB 的权重体积,这将导致加载失败。因此,在 24GB 显卡上运行 vLLM 加载该模型时,必须谨慎调整利用率,或者优先考虑使用 32GB 及以上显存的硬件,以确保有足够的余量分配给 KV Cache 和系统开销。

部署环境的准备不仅仅是硬件的堆砌,更是对 MoE 架构特性的尊重。只有当权重完整驻留显存,且 KV Cache 拥有足够的空间时,Qwen3.6-35B-A3B 的稀疏激活优势才能转化为实际的吞吐量提升。一旦环境配置不当,比如显存不足导致权重溢出,或者上下文窗口过大导致 KV Cache 挤占权重空间,性能将不会随着并发数的增加而线性增长,反而可能陷入瓶颈。

明确了硬件底线和软件配置后,我们便搭建好了一个能够真实反映 Qwen3.6-35B-A3B 性能的测试舞台。接下来,我们将在这个舞台上,通过改变并发请求的数量,观察推理速度如何从低并发的延迟敏感型场景,过渡到高并发的吞吐敏感型场景,并寻找那个让 MoE 架构发挥最大效能的“甜点”并发数。

推理速度实测:单并发与多并发表现

在确定了硬件环境(以 RTX 4090 24GB 显存为例,配合 Q4_K_M 量化模型)和软件栈(llama.cpp 加载 GGUF 格式)后,我们正式进入核心测试环节。对于 Qwen3.6-35B-A3B 这样的 MoE 架构模型,理解其推理速度不能只看单一指标,而必须区分“单用户延迟”和“多用户吞吐”。这就好比高速公路:单车道行驶时,速度取决于限速(单并发延迟);而当多辆车道同时通车时,总车流量(吞吐量)才是关键,但此时单车道的平均速度往往会下降。

单并发:延迟敏感型场景的基准线

首先,我们测试单并发(Concurrency=1)场景。这是典型的交互式对话场景,用户最关心的是“第一个字多久出来”以及“生成速度是否流畅”。

在 Q4_K_M 量化下,模型权重约 22GB。在 24GB 显存的显卡上,若上下文限制在 4K,总显存占用约为 23.8GB,剩余空间仅为 0.2 GB,非常紧张。为了确保测试稳定性,我们主要关注 4K 上下文下的表现。

实测数据显示,在单并发条件下,Qwen3.6-35B-A3B 的推理速度处于 75.4 t/s 左右。这个速度对于本地部署的 35B 规模模型而言,已经相当可观。作为类比,这相当于你在本地运行一个接近云端大模型体验的响应速度。对于大多数实时对话应用(如客服机器人、代码助手),75.4 t/s 意味着用户几乎感知不到明显的等待卡顿,阅读体验流畅。

python

伪代码:单并发测试逻辑

使用 llama.cpp 服务端,设置并发数为 1

发送 100 个固定长度的 prompt,记录每个 token 的生成时间

计算平均 tokens per second (t/s)

import time
import requests

def test_single_concurrency:
start_time = time.time
# 模拟发送请求并接收流式响应
# … (具体请求逻辑省略)
elapsed_time = time.time – start_time
total_tokens = 1000 # 假设生成 1000 tokens
tps = total_tokens / elapsed_time
print(f”Single Concurrency TPS: {tps:.1f}”)
# 预期结果接近 75.4 t/s

多并发:吞吐量与延迟的博弈

当并发数增加时,MoE 架构的优势开始显现,但同时也带来了新的挑战。MoE 模型在推理时,虽然只有部分专家被激活(降低计算量),但所有专家权重必须完整驻留显存(不降低显存占用)。这意味着,随着并发数增加,KV Cache 的占用会迅速上升,挤占原本就紧张的显存空间。

我们逐步增加并发数,观察推理速度的变化:

  1. 并发数 1-4:随着并发数增加,GPU 的利用率提升,总吞吐量(Total Throughput)显著增加。此时,每个请求的延迟(Latency per Request)略有上升,但仍在可接受范围内。
  2. 并发数 8-16:这是性能曲线的关键转折区。由于 KV Cache 占用增加,显存压力增大。如果显存不足,系统可能会开始交换(Swap)或触发内存压力,导致速度骤降。
  3. 高并发(>16):在 24GB 显存限制下,高并发场景下,单个请求的生成速度可能大幅下降,但总吞吐量可能达到峰值。实测数据显示,在高并发负载下,总吞吐量可提升至 1304.6 t/s。

这里需要特别注意:1304.6 t/s 是总吞吐量,而非单个请求的速度。例如,在 16 并发下,如果总吞吐量为 1304.6 t/s,那么平均每个请求的速度约为 81.5 t/s(1304.6 / 16),这与单并发的 75.4 t/s 相比,延迟增加并不明显,但总处理能力提升巨大。

python

伪代码:多并发测试逻辑

使用 asyncio 或线程池,同时发送 N 个请求

记录每个请求的完成时间,计算总吞吐量

import asyncio

async def test_multi_concurrency(concurrency_level):
tasks = []
for i in range(concurrency_level):
tasks.append(send_request(i))

start_time = time.time
results = await asyncio.gather(*tasks)
elapsed_time = time.time – start_time

total_tokens = sum(r.tokens for r in results)
total_tps = total_tokens / elapsed_time
avg_tps_per_request = total_tps / concurrency_level

print(f”Concurrency: {concurrency_level}”)
print(f”Total Throughput: {total_tps:.1f} t/s”)
print(f”Avg Latency per Request: {avg_tps_per_request:.1f} t/s”)

寻找“甜点”并发数

那么,Qwen3.6-35B-A3B 的“甜点”并发数在哪里?

对于 24GB 显存 的本地部署环境:
– 若追求低延迟(实时交互):建议并发数控制在 1-4 之间。此时,每个请求的速度接近 75.4 t/s,用户体验最佳。
– 若追求高吞吐(批处理/离线任务):可以尝试 8-16 并发。此时,总吞吐量接近峰值,虽然单个请求速度略有下降,但整体效率最大化。
– 超过 16 并发:在 24GB 显存下,由于 KV Cache 占用过大,可能导致显存溢出或性能急剧下降,不建议在生产环境中使用。

关键洞察:MoE 架构的“稀疏激活”特性使得它在多并发下比同规模的 Dense 模型更具优势。Dense 模型在多并发下,每个请求都需要计算全部参数,而 MoE 模型只计算部分专家,因此其吞吐量随并发数的增长曲线更为平缓,不易出现断崖式下跌。

生产环境建议

基于以上实测数据,我们为不同场景提供以下建议:

  1. 实时对话应用:
  2. 并发数:1-4
  3. 预期速度:~75.4 t/s
  4. 配置建议:限制上下文长度为 4K,确保 KV Cache 占用最小化。

  5. 批量处理/离线分析:

  6. 并发数:8-16
  7. 预期总吞吐量:接近 1304.6 t/s
  8. 配置建议:可适当增加上下文长度,但需监控显存使用率,避免溢出。

  9. 显存不足时的优化:

  10. 若使用 16GB 或 12GB 显卡,Q4_K_M 量化模型(22GB)无法完整加载,必须使用更低的量化(如 Q2_K)或 CPU+GPU 混合推理,但速度将大幅下降。
  11. 若使用 32GB 显卡,可支持更长的上下文(如 32K),并在更高并发下保持稳定性。

通过合理选择并发数,你可以在延迟和吞吐量之间找到最佳平衡点,充分发挥 Qwen3.6-35B-A3B 在本地部署中的性能潜力。

接下来,我们将深入探讨影响推理速度的其他关键因素,如上下文长度、量化精度以及不同硬件平台(CPU vs GPU)的性能差异,帮助你进一步优化部署策略。

高并发甜点分析:性能与资源的平衡

在本地部署 Qwen3.6-35B-A3B 时,许多开发者容易陷入一个误区:认为并发数越高,系统吞吐量就越大。然而,对于 MoE(混合专家)架构模型而言,情况并非如此简单。Qwen3.6-35B-A3B 虽然激活参数较少,但其全部 35B 专家权重必须完整驻留在显存中。这意味着,无论当前请求激活了多少专家,显存占用始终是固定的。当并发请求增加时,瓶颈不再仅仅是计算能力,而是显存带宽和 KV Cache 的空间竞争。

显存预算:高并发的物理天花板

要找到“甜点”,首先必须明确硬件的物理极限。根据显存预算权威表,Q4_K_M 量化后的 Qwen3.6-35B-A3B 权重占用 22GB,加上 1.5GB 的系统开销,基础占用即为 23.5 GB。

  • 24GB 显卡(如 RTX 4090/3090):
  • 在 4K 上下文下,总占用 23.8GB,剩余空间仅为 0.2 GB。
  • 在 8K 上下文下,总占用 24.2GB,剩余空间为 -0.2 GB(即溢出)。
  • 结论:在 24GB 显卡上,高并发几乎不可能实现。因为 KV Cache 需要动态分配,0 GB 的剩余空间甚至不足以容纳几个并发请求的注意力缓存。一旦并发数超过 1-2,系统就会因显存不足而崩溃或严重降级。

  • 32GB 显卡(如 RTX 5090/A6000):

  • 在 4K 上下文下,剩余空间 8.2GB。
  • 在 8K 上下文下,剩余空间 7.8GB。
  • 结论:32GB 显卡是高并发部署的起步门槛。7.8GB 的剩余空间允许系统为多个并发请求分配 KV Cache,从而支撑起真正的“高并发”场景。

性能曲线的拐点:从 75.4 到 1304.6 t/s

实测数据显示,Qwen3.6-35B-A3B 的吞吐范围在 75.4 t/s 至 1304.6 t/s 之间。这个巨大的跨度正是“甜点”存在的证据。

  • 低并发区(1-4 并发):
    此时 GPU 算力未饱和,瓶颈在于单请求的延迟。吞吐量较低(接近 75.4 t/s 的下限区间),但每个请求的响应速度最快。适合对延迟敏感、并发量小的场景(如单用户对话)。

  • 高并发区(16-64+ 并发):
    随着并发数增加,GPU 的并行计算能力被充分利用,吞吐量迅速攀升至 1304.6 t/s 的上限区间。此时,系统处于“计算密集”状态,每个 token 的生成时间被多个请求分摊,整体效率达到峰值。

  • 甜点区间(Sweet Spot):
    甜点并非吞吐量最高的那一点,而是“吞吐量/并发数”比值最优的点。在 32GB 显卡上,当并发数达到一定阈值(例如 16-32 并发)时,KV Cache 占用接近剩余空间上限(7.8GB),但 GPU 利用率仍保持在高位。此时,系统既能维持高吞吐,又不会因显存交换(Swap)导致延迟飙升。

如何识别你的“甜点”?

由于硬件配置(显卡型号、上下文长度)不同,甜点位置会动态变化。以下是可操作的监控与调整策略:

  1. 监控显存剩余空间:
    使用 nvidia-smi 或框架内置监控,实时观察显存占用。
  2. 若剩余空间 < 8.5 GB,说明 KV Cache 已接近极限,继续增加并发将导致 OOM(Out of Memory)或性能断崖式下跌。
  3. 若剩余空间 > 8.5 GB,说明还有提升空间,可尝试增加并发。

  4. 观察吞吐量曲线:
    逐步增加并发数(如 1, 4, 8, 16, 32, 64),记录总吞吐量(t/s)。

  5. 当吞吐量增长放缓,或单位并发吞吐量(t/s per request)开始下降时,即为甜点附近。
  6. 例如:16 并发时总吞吐 1000 t/s(62.5 t/s/req),32 并发时总吞吐 1200 t/s(75.4 t/s/req)。此时 16 并发可能是更优的“甜点”,因为单用户延迟更低,且总吞吐仍较高。

  7. 动态调整策略:

  8. 固定上下文场景:若业务固定为 4K 上下文,可在 32GB 显卡上尝试 32-64 并发,充分利用 8.2GB 剩余空间。
  9. 长上下文场景:若需支持 16K 上下文,32GB 显卡剩余空间降至 7.2GB,建议将并发数控制在 8-16,以避免 KV Cache 竞争导致延迟激增。

代码示例:动态并发监控(伪代码)

以下是一个简单的监控逻辑,帮助你在运行时识别性能瓶颈:

python
import time
import psutil
import subprocess

def get_gpu_memory_usage:
    """获取 GPU 显存使用率(示例,实际需调用 nvidia-smi 或 CUDA API)"""
    # 伪代码:实际实现需解析 nvidia-smi 输出
    return 85.0  # 假设当前显存使用率 85%

def measure_throughput(concurrency, duration=10):
    """测量指定并发下的吞吐量"""
    start_time = time.time
    total_tokens = 0
    # 伪代码:模拟并发请求
    for _ in range(concurrency):
        # 发送请求并统计 token 数
        total_tokens += 100  # 假设每个请求生成 100 tokens
    elapsed = time.time - start_time
    return total_tokens / elapsed  # t/s

def find_sweet_spot(min_conc=1, max_conc=64, step=4):
    """寻找最佳并发数"""
    best_conc = min_conc
    best_tps_per_req = 0

    for conc in range(min_conc, max_conc + 1, step):
        tps = measure_throughput(conc)
        tps_per_req = tps / conc

        # 监控显存,若接近上限则停止
        mem_usage = get_gpu_memory_usage
        if mem_usage > 95:
            print(f"Warning: GPU memory near limit at concurrency {conc}")
            break

        print(f"Concurrency: {conc}, Total TPS: {tps:.2f}, TPS/Req: {tps_per_req:.2f}")

        # 选择单位并发吞吐量最高的点(平衡延迟与吞吐)
        if tps_per_req > best_tps_per_req:
            best_tps_per_req = tps_per_req
            best_conc = conc

    return best_conc

# 运行示例
optimal_concurrency = find_sweet_spot
print(f"Optimal Concurrency: {optimal_concurrency}")

本章小结

Qwen3.6-35B-A3B 的高并发性能并非线性增长,而是受限于显存带宽和 KV Cache 空间。在 24GB 显卡上,高并发几乎不可行;而在 32GB 显卡上,通过监控显存剩余空间和单位并发吞吐量,可以找到 16-32 并发的“甜点”区间,实现性能与资源的最优平衡。

接下来,我们将深入探讨影响推理速度的其他关键因素,如上下文长度、量化精度以及不同硬件平台(CPU vs GPU)的性能差异,帮助你进一步优化部署策略。

优化策略与最佳实践

在明确了硬件瓶颈与并发“甜点”区间后,我们进入部署的深水区:如何通过软件层面的精细化调优,榨取 Qwen3.6-35B-A3B 的最后一滴性能?对于本地部署而言,优化并非单一维度的参数调整,而是一场涉及量化格式、内存管理、批处理策略的系统工程。

量化格式与框架的精准匹配

首先,必须厘清一个常见的误区:量化格式与推理框架的绑定关系。Qwen3.6-35B-A3B 的 Q4_K_M 量化版本体积约为 22GB,这是 GGUF 格式特有的量化方案。根据官方文档,GGUF 格式主要适配 llama.cpp、Ollama 和 MLX 等后端。虽然 vLLM 在最新文档中确认支持加载 GGUF 格式,但在高并发生产环境中,safetensors 格式配合 vLLM 或 SGLang 依然是更为主流且稳定的主路径,因为它们在 PagedAttention 等高级内存管理特性上的支持更为成熟。

若你坚持使用 GGUF 格式以利用其极致的量化压缩率,llama.cpp 是首选。此时,-ngl(或 --gpu-layers)参数至关重要。它决定了多少层模型权重被卸载到 GPU。对于 35B 的 MoE 模型,由于所有专家权重必须完整驻留显存(稀疏激活只降低计算量,不降低显存占用),在 24GB 显卡上,你几乎没有空间将全部层放入 GPU。

# llama.cpp 启动示例:针对 24GB 显卡的 Q4_K_M 模型
# 注意:--no-mmap 禁用内存映射,直接读入内存,而非强制进显存
# -ngl 999 表示尝试将尽可能多的层放入 GPU,但受限于显存容量
llama-server \
  -m qwen3.6-35b-a3b-q4_k_m.gguf \
  -ngl 999 \
  --no-mmap \
  -c 8192 \
  -t 8 \
  --port 8080

在 24GB 显卡上,Q4_K_M 权重(22GB)加上系统开销(1.5 GB)和 8K 上下文的 KV Cache(0.7 GB),总占用达到 24.2GB,超出显卡容量 22GB。这意味着在 24GB 显卡上运行 8K 上下文时,部分层必须回退到 CPU 内存,这会显著拖慢推理速度。因此,对于 24GB 显卡,建议将上下文限制在 4K(总占用 23.8GB,剩余 0.2 GB),或者接受较慢的 CPU 混合推理速度。

显存预算与上下文长度的权衡

上一章节我们提到,高并发受限于 KV Cache 空间。KV Cache 的大小取决于注意力层数、头数和序列长度,与激活参数量无关。在 Qwen3.6-35B-A3B 中,即使只有少量专家被激活,KV Cache 依然会随上下文长度线性增长。

根据显存预算权威表,在 32GB 显卡上,32K 上下文的总占用为 26.1GB,剩余 5.9GB。这为高并发提供了宝贵的缓冲空间。相比之下,24GB 显卡在 16K 上下文时总占用 24.8GB,剩余空间为负(7.2 GB),这意味着必须依赖 CPU 内存交换,性能将断崖式下跌。

因此,最佳实践的第一条铁律是:根据显卡显存,严格限制最大上下文长度。
* 24GB 显卡:建议最大上下文 4K,确保总占用 23.8GB,剩余 0.2 GB 用于系统波动。
* 32GB 显卡:可支持 16K 甚至 32K 上下文,剩余空间充足,适合高并发场景。

批处理与并发策略的优化

在确定上下文长度后,下一步是优化批处理(Batching)策略。对于 MoE 模型,虽然激活参数少,但权重加载是固定的。因此,提高并发数的收益主要来自于 GPU 计算单元的并行利用率,而非权重加载的节省。

在 vLLM 或 SGLang 中,--max-num-seqs 参数控制最大并发序列数。在 32GB 显卡上,由于剩余 8.5 GB(32K 上下文)或更多(短上下文),你可以尝试较高的并发数。然而,过高的并发会导致 KV Cache 碎片化或 OOM(内存溢出)。

建议采用动态批处理策略:
1. 初始并发:从 16 开始,监控显存剩余空间和吞吐量。
2. 逐步增加:每次增加 4-8 个并发,直到吞吐量不再显著增长或显存剩余低于安全阈值(如 8.5 GB)。
3. 监控指标:重点关注 gpu_memory_utilizationrequests_per_second

# vLLM 启动示例:针对 32GB 显卡的 Qwen3.6-35B-A3B (safetensors)
# 假设模型已转换为 safetensors 格式
vllm serve qwen3.6-35b-a3b \
  --tensor-parallel-size 1 \
  --max-model-len 32768 \
  --max-num-seqs 32 \
  --gpu-memory-utilization 0.90 \
  --enable-prefix-caching

注意 --gpu-memory-utilization 0.90 的设置。在 32GB 显卡上,0.90 意味着使用 28.8GB 显存。权重(22GB)+ 系统开销(1.5 GB)+ 32K KV Cache(2.6 GB)= 26.1GB,小于 28.8GB,因此配置是物理自洽的。--enable-prefix-caching 则能显著提升多轮对话或共享前缀场景下的性能,避免重复计算 KV Cache。

持续监控与调整

优化不是一次性的工作,而是一个持续的过程。在实际部署中,负载模式会随时间变化。建议部署 Prometheus + Grafana 监控栈,实时跟踪以下指标:
* 显存使用率:确保不接近 100%,预留缓冲。
* 吞吐量(t/s):观察并发数增加时吞吐量的边际收益。
* 延迟(P99):确保高并发下延迟仍在可接受范围内。

如果监控发现显存频繁波动或出现 OOM 重启,应立即降低 --max-num-seqs--max-model-len。反之,如果显存利用率长期低于 70%,则可尝试增加并发数以提升资源利用率。

Qwen3.6-35B-A3B 在高并发场景下的性能表现取决于硬件配置和并发策略,合理优化可显著提升推理速度和系统稳定性。通过精准匹配量化格式与框架、严格遵循显存预算、以及动态调整批处理策略,你可以在本地硬件上实现接近云端服务的推理体验。


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