1. 先把参数拆开看:35B 和 A3B 各自意味着什么
Qwen 3.6-35B-A3B 这个型号我第一次看到时,注意力没在 35B 上,而是先盯住了那个 A3B——A 是 Activated,意思是每个 token 实际参与计算的参数只有 3B 左右,剩下那三十多个 B 躺在专家池里,按路由结果被挑选调用。这个设计直接决定了本地部署的全部策略:显存是按 35B 的体量吃,速度却是按 3B 的体量跑。市面上讲大模型本地部署的文章大多只写“装个 Ollama 拉一下”,放到这种混合专家架构上基本抓瞎,因为常规的“整模型塞进显存”这条路上,24GB 消费卡根本走不通。这篇内容适合三类人:手里有单卡 24GB 或双卡、想在家用机器上跑一个真正能写代码能长文推理的模型的;在做内部知识库、需要离线推理服务的;以及已经被各种量化版本和推理框架参数绕晕、想弄清楚每一步为什么这么设的。我不打算写成参数手册,而是把我自己从“能加载”到“能日常干活”这段路完整拆开,包括每一步的取舍逻辑、算账过程和踩过的坑。
1.1 混合专家架构到底省了什么、没省什么
先说清楚省的和没省的,后面所有决策都从这里推。省下来的是算力:稠密模型每生成一个 token 都要把全部 35B 权重过一遍,而混合专家模型只走被路由选中的那几个专家,FLOPs 大约只有稠密的十分之一不到,所以在同样的硬件上,它的 token 生成速度大致相当于一个 3B 到 5B 的稠密模型,而不是 35B。这一点非常反直觉——很多人第一次跑起来发现输出比 14B 稠密模型还快,会以为是量化掉了精度,其实是架构本身省了计算。
没省的是显存:所有专家都得在内存里待着,随时可能被调用。路由是按 token 动态决定的,这个 token 走专家 A 和 B,下个 token 可能走专家 F 和 G,你没法提前知道哪几个专家会被用到,所以不能只加载一部分权重就完事——除非你接受把没加载的专家放到内存或者固态硬盘上,用的时候临时搬。这就是后面要重点讲的“专家卸载”,也是 24GB 卡能不能跑起来的关键。
还有一个容易被忽略的点:带宽压力。稠密模型的计算是算力瓶颈,混合专家的瓶颈更偏向显存带宽——虽然参数量少了,但专家权重的分布是离散的,缓存命中率不如稠密模型那么友好。所以你会看到一个有意思的现象:同样的量化档位,算力翻倍的卡不一定快翻倍,但显存带宽翻倍的卡提升明显。这也是为什么在选卡的时候,我不太建议为了省钱去挑位宽被砍过的型号。
1.2 先明确你的目标:聊天、批处理还是长文档
部署方案没有通用最优解,得先看你要拿它干什么,因为这三类任务的调优方向完全相反。
日常聊天和单人问答,核心指标是首 token 延迟(TTFT),也就是你说完话到它蹦出第一个字的这段时间。这时候最优配置是大 batch 关闭或者压到很小、上下文别开太长、专家尽量全塞显存。我自己的体感是 TTFT 控制在 1 秒以内,人就不会觉得卡;超过 2 秒手就会不自觉地去点别的窗口。
批处理场景,比如批量打标、批量摘要、批量代码审查,核心指标变成总吞吐,也就是每秒能出多少 token。这时候要做的是提高并发序列数、开连续批处理、接受单请求变慢。同一个模型同一张卡,这两套配置的吞吐能差三到五倍,所以别拿聊天场景的体感去评价批处理配置的好坏。
长文档场景最麻烦,核心指标是上下文长度和显存的平衡。上下文一长,KV 缓存线性膨胀,长到一定程度就把权重挤出去了,然后你就 OOM。这一块我在第 4.2 节会给出具体的算账方法,因为我见过太多人把上下文参数设成 128K,然后发现显存爆掉却不知道是哪里吃的。
注意:先写清楚自己的场景再动手调参,比盲目抄别人的启动命令有效十倍。我见过有人拿一份面向吞吐优化的配置去跑单轮对话,抱怨说“这模型怎么这么慢”,实际上是配置和场景错配。
2. 显存怎么算:把账算明白再买卡
这一节是全文最实用的部分,因为大部分人卡在第一步——不知道自己手上的机器到底能不能跑、能跑到什么程度。我不想给一个“至少需要 XX GB”的模糊结论,而是给一套你自己就能算的公式,因为上下文长度、量化档位、并发数这三个变量一变,答案就完全不同。
2.1 权重显存的估算公式与实测对照
权重占用可以用一个很粗但够用的式子估:显存 ≈ 参数量 × 每权重比特数 ÷ 8。35B 参数代入,各档位的结果如下表。表格里的数值是按公式算出来的理论值,实测会因为嵌入层、输出层、归一化参数不参与量化而略高一点,我把自己机器上的实测值也放进去做对照。
| 量化档位 | 平均每权重比特 | 理论权重显存 | 实测文件大小 | 24GB 卡能否全量加载 |
|---|---|---|---|---|
| Q8_0 | 约 8.5 bit | 约 37 GB | 37.2 GB | 不能 |
| Q6_K | 约 6.6 bit | 约 29 GB | 29.1 GB | 不能 |
| Q5_K_M | 约 5.7 bit | 约 25 GB | 25.3 GB | 不能 |
| Q4_K_M | 约 4.8 bit | 约 21 GB | 21.4 GB | 勉强,上下文只剩很小空间 |
| Q3_K_M | 约 3.9 bit | 约 17 GB | 17.6 GB | 能,可留 4K 到 8K 上下文 |
| IQ3_XXS | 约 3.1 bit | 约 13.5 GB | 14.0 GB | 能,可留 16K 上下文 |
| IQ2_M | 约 2.7 bit | 约 12 GB | 12.4 GB | 能,但质量下降明显 |
看这张表得出一个不太舒服的结论:24GB 的卡上跑 Q4_K_M,权重就吃掉 21GB,剩下的 3GB 左右要分给 KV 缓存、计算缓冲和框架本身,实际能开的上下文大概只有 4K 到 8K。这个长度用来跑单轮问答够,拿来读一份长报告就完全不够了。所以要么降量化,要么走“部分专家放内存”的路子,没有第三条捷径。
2.2 KV 缓存的算法:长上下文真正的吞金兽
很多人对 KV 缓存的体量没有概念,以为开了 32K 上下文只是多占一点。实际算一下:每 token 的 KV 占用 = 2 × 层数 × KV 头数 × 头维度 × 每元素字节数。以一套常见的配置举例,层数按 48 层、KV 头数按分组查询注意力常见的 4 组、头维度 128、半精度每元素 2 字节来算,每个 token 就是 2 × 48 × 4 × 128 × 2 ≈ 96 KB。听起来很小,但乘以 32768 个 token 就是 3 GB 出头,乘以 128K 就是 12 GB 以上。
注意:上面这些层数、头数是按同类架构的常见取值举例,你手上的模型具体是多少,一定要去读发布包里 config.json 的 num_hidden_layers、num_key_value_heads、head_dim 三个字段,套同一个公式算,别拿我的数字直接用。
这也解释了一个高频困惑:为什么把上下文从 8K 调到 32K,模型就启动失败。因为同时还要给计算中间结果留缓冲,batch 越大缓冲越大,长上下文加高并发是双重叠加,很容易瞬间打满。
压 KV 缓存的手段有三个,按性价比排序:第一是开 KV 缓存量化,把它存成 8 位或者 8 位浮点,直接砍一半,质量损失在绝大多数任务上测不出来;第二是减少并发序列数,把同时处理的请求数从 32 降到 8,缓存占用直接除以四;第三才是降上下文长度。顺序别搞反,我见过太多人一上来就砍上下文,其实把并发调下来问题就解决了。
2.3 三种典型硬件路线的真实取舍
路线一:单卡 24GB 消费卡。这是最普遍的起点。可行配置基本锁定在 Q4_K_M 加 8K 上下文,或者 IQ3 系列加 16K 上下文,再把一部分专家层卸载到系统内存。速度方面,短上下文下每秒能出二十多个 token,长上下文会掉到十几个,属于“能用但不爽”的档位。适合个人日常问答和轻量代码补全。
路线二:统一内存架构的工作站或笔记本。这类机器显存和内存共享一个池子,可以做到 64GB 甚至 128GB 可用,代价是带宽比独立显卡低一截。好处是能直接把 Q6_K 甚至 Q8_0 全量塞进去,不用折腾卸载,配置极其简单,长上下文也敢开。坏处是吞吐上不去,做批处理会很难受。我个人觉得这类机器最适合“一个人安安静静写东西”的场景,不适合当服务端。
路线三:双卡或四卡。这里有个反直觉的地方:双卡的收益不是线性的。如果两张卡之间没有高速互联,只靠主板通道通信,张量并行会引入大量跨卡同步开销,实测有时候单卡跑 25 token/s,双卡张量并行只跑到 30 出头,而流水线并行又会让每张卡只处理一半层、总延迟反而上升。真正明显受益的是“把专家分片到不同卡上”的专家并行模式,这也是混合专家架构在服务端部署时的标准做法。
3. 推理框架怎么选:三条路线的适用边界
框架选型这事,网上的信息噪音特别大,各家都有自己的拥趸。我的看法是别争谁更好,先看清自己的约束:你是要最快跑通,还是要最高吞吐,还是要最细的控制粒度。这三个目标对应的工具其实不太一样。
3.1 GGUF 路线:控制粒度最细,也是单卡首选
基于 GGUF 格式配合 llama.cpp 系列工具,是我在单卡和混合内存场景下的默认选择。原因有三:第一,它对混合专家模型的专家卸载支持做得最细,可以精确到“前 N 层专家留在显存、其余放内存”;第二,量化档位特别全,从 2 位到 8 位都有,能在显存和质量之间找到那个刚好卡住的点;第三,纯 C++ 实现,依赖少,部署到没有网络的环境里最省事。
下面是我在单卡 24GB 上跑 Q4_K_M 的一份启动配置,每一项后面我都标了为什么这么设。
llama-server \ -m ./models/qwen3.6-35b-a3b-Q4_K_M.gguf \ -c 8192 \ -ngl 99 \ --n-cpu-moe 14 \ --cache-type-k q8_0 \ --cache-type-v q8_0 \ -fa on \ -t 12 \ -b 2048 \ -ub 512 \ --jinja \ --host 0.0.0.0 \ --port 8080逐项解释一下。-ngl 99的意思是“能放显存的层全放”,99 是个足够大的数,不用精确数层数。--n-cpu-moe 14是混合专家专属参数,表示把 14 层的专家权重挪到系统内存,只留注意力部分在显存——这个数字要试,从 8 开始往上加,每次加 2,直到显存占用落到 21GB 左右留出余量为止。--cache-type-k/v q8_0是 KV 缓存量化,前面算过它能省一半缓存。-fa on打开闪光注意力,长上下文下的显存和速度双收益。-t 12是 CPU 线程数,一般设成物理核心数,别设成逻辑核心数,超线程在这里是负收益。-b 2048 -ub 512是逻辑批和物理批,物理批设小一点能降低峰值显存。--jinja打开模板解析,聊天模板才会按模型自带的格式走,不开的话多轮对话会串味。
提示:
--n-cpu-moe这个参数在不同版本里名字可能略有差异,老版本要靠-ot配合正则表达式来指定卸载哪些张量。升级前先跑一次--help确认参数名,别直接复制旧命令。
3.2 服务端路线:吞吐优先时的配置思路
如果要对外提供服务、要扛并发,那 GGUF 这条路就不太合适了,得换到更偏工程化的推理引擎。这类引擎的核心优势是连续批处理——多个请求的 token 生成可以交错进行,GPU 利用率能拉得很高,单卡吞吐能比单请求模式高出好几倍。代价是显存管理更激进,配置不当会直接 OOM。
以常见的服务端引擎为例,一份 32K 上下文、面向中等并发的启动配置大致长这样:
vllm serve ./models/Qwen3.6-35B-A3B \ --served-model-name local-moe \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.90 \ --max-model-len 32768 \ --kv-cache-dtype fp8 \ --max-num-seqs 12 \ --enable-expert-parallel \ --swap-space 16--gpu-memory-utilization 0.90是让引擎自己去规划显存,留 10% 给框架和碎片,这个值别设到 0.98,我试过,跑着跑着就来一次显存不足。--max-num-seqs 12是同时处理的请求上限,这是吞吐和延迟之间最直接的旋钮,调到 32 吞吐上去了但每个请求都变慢。--kv-cache-dtype fp8压缩缓存。--enable-expert-parallel在多卡时把专家分散到各卡,单卡时无效果但也不影响。--swap-space是 CPU 侧的交换空间,单位 GB,卸载部分缓存用的。
如果你的机器显存实在不够全量加载,服务端引擎一般也提供把权重卸载到 CPU 内存的开关,但要清楚这会把速度拉到一个很低的水平,只适合夜间批处理,不适合交互。
3.3 快速验证路线:先用五分钟确认模型质量
正式调优之前,我强烈建议先用最简单的工具跑一次,确认这个模型的输出质量、模板格式、中文表现是不是符合预期。因为量化和调优都是“降质换资源”的操作,如果原始模型本身就不满足你的需求,后面所有功夫都白费。
最快的验证方式是写一个极简的配置描述文件,把模型路径、上下文、显卡层数、采样参数写进去,然后一条命令拉起来。关键参数其实就四个:num_ctx控制上下文,num_gpu控制卸载层数,num_thread控制 CPU 线程,temperature和top_p控制采样。这套配置跑通之后,你对这个模型的“原始手感”就有了基准,后面换框架换量化,都是拿这个基准去比。
FROM ./qwen3.6-35b-a3b-q4_k_m.gguf PARAMETER num_ctx 8192 PARAMETER num_gpu 99 PARAMETER num_thread 12 PARAMETER temperature 0.6 PARAMETER top_p 0.95 PARAMETER repeat_penalty 1.05采样参数这块多提一句:混合专家模型的输出分布和稠密模型不太一样,温度设太高容易出现“每句都对但整体跑题”的情况,我的经验是温度控制在 0.5 到 0.7 之间,重复惩罚别超过 1.1,超了会开始胡言乱语。这个和常见教程里“温度 0.8 更有创意”的建议是相反的,原因在于专家路由本身带随机性,采样再放开就是双重随机。
4. 调优实操:从“能跑”到“跑得舒服”
到这一步模型已经能出字了,接下来是真正耗时间的地方。我发现大部分人卡在两个误区:一是把所有参数往最大值调,觉得这样性能最好;二是看到一个参数不懂就照抄,结果配置之间互相打架。调优的本质是找平衡点,而平衡点是被你的场景和目标硬件共同决定的。
4.1 专家卸载的甜点区在哪
混合专家模型最有价值的调优手段就是这个。逻辑很简单:注意力层和路由层留在显存,专家权重按层分批挪到内存。挪多少层,直接决定显存占用和速度的比值。
我做过一组对照,同一张 24GB 卡、同一个 Q4_K_M 文件、8K 上下文,只改卸载层数,结果如下表。这张表是我自己实测的,你机器上的绝对值会不一样,但趋势是一致的。
| 卸载专家层数 | 显存占用 | 生成速度 | 体感 |
|---|---|---|---|
| 0(全量显存) | 超出显存,启动失败 | — | 不可用 |
| 8 | 约 23.5 GB | 约 9 token/s | 频繁触发内存搬运,很卡 |
| 14 | 约 21.2 GB | 约 22 token/s | 日常问答无感 |
| 20 | 约 19.8 GB | 约 17 token/s | 可接受,能开更长上下文 |
| 28 | 约 17.5 GB | 约 11 token/s | 只适合批处理 |
这张表里最关键的一行是“卸载 8 层”——显存快满了,速度反而最差。这个现象很有意思,原因是显存余量太小,系统开始频繁做内存页换入换出,每次换页都是一次几十毫秒的停顿,累积起来就是断崖式掉速。所以“显存别占满”这句话不是玄学,是有具体机制的:留出至少 2GB 余量,让系统有腾挪空间,速度反而更好。
提示:卸载层数不是越多越好,也不是越少越好,找到那个“显存占用 85% 左右、速度还能接受”的点就停。我个人习惯是留 2.5GB 到 3GB 余量,这个余量在长上下文时会自动被 KV 缓存吃掉,正好不浪费。
4.2 上下文长度的动态调整策略
前面算过 KV 缓存的账,这里讲实操层面的策略。我不建议把上下文一次性设成最大值然后不管,因为那等于永久占用一块显存。更合理的做法是分场景配置多套启动参数,或者在支持的框架里用按需分配的缓存模式。
具体怎么定,我的经验值是:单轮问答和短对话,8K 够用,绝大多数提问都在 2K 以内;代码审查和文档摘要,32K 是门槛,低于这个长度经常要截断,反而影响效果;整本书级别的分析,那得上 128K,但这时候就不该在单卡上硬扛了。
还有一个容易被忽略的细节:上下文长度和实际使用长度是两回事。设了 32K,但只用前 4K,KV 缓存并不会立刻占满 32K 的空间——现代推理框架大多按实际长度分配。所以设大一点不一定立刻爆显存,但并发数一上来,每个请求都往 20K 走,总占用就上去了,这个叠加效应要心里有数。
4.3 采样参数与模板:质量问题的常见源头
很多时候“模型回答质量差”根本不是模型的问题,是模板或者采样参数错了。混合专家模型对聊天模板尤其敏感,模板不匹配会直接导致多轮对话中角色混乱、系统提示词被忽略、输出格式错乱。
排查顺序我一般是这样的:先看模型发布包里有没有提供模板字符串,直接用它;然后检查系统提示词的位置对不对,有些模型的模板要求系统提示必须放在第一个用户消息之前,位置错了就会被当成普通内容;最后才动采样参数。温度、top_p、top_k 这三个参数,我通常只在确定模板没问题之后才调,而且一次只改一个,改完跑同一组固定问题对比,别凭感觉。
至于重复惩罚,我在混合专家模型上踩过一次坑:为了压住偶尔的复读,把惩罚设到 1.3,结果模型开始刻意回避高频词,写出来的句子特别别扭,像翻译腔。后来降到 1.05,复读问题改从提示词层面解决,效果好得多。采样参数是治标不治本的,能用提示词和上下文解决的问题,别用参数硬压。
4.4 服务化时的并发与队列设计
如果你打算把它挂成一个本地服务给团队用,那还要考虑并发模型。这里有个简单事实:单卡上并发数和单请求速度是反比关系。12 个并发跑着,每个请求可能只有 5 token/s;缩到 2 个并发,每个请求能到 20 token/s。
我的做法是分层:交互类请求走小并发池,限制在 2 到 4 个槽位,保证响应手感;批处理任务走单独的队列,串行执行,不跟交互抢资源。很多新手会把所有请求丢进同一个池子,结果就是白天大家用着都卡,晚上跑批又跑不完。
还有一个经验:请求排队时间要显式记录。我见过一个案例,用户抱怨“服务很慢”,最后发现模型生成速度没问题,是请求在队列里排了十几秒。这类问题不去量排队时间,永远查不出来。
5. 怎么验证调优有效:三个必须量的指标
调参不量化等于闭眼开车。这一节讲我固定使用的三个指标和一套简单的压测脚本,都是能直接抄去用的。有了这套基准,你换一个量化档位、改一个卸载层数,都能立刻知道是变好还是变坏。
5.1 首 token 延迟、生成速度、并发吞吐
这三个指标覆盖了绝大多数实际使用场景,缺一不可。
首 token 延迟反映预处理和排队时间,直接决定交互手感。生成速度是稳态输出速率,决定你等一段长回复要多久。并发吞吐是系统级指标,是所有请求加起来每秒出的 token 数。这三个数经常是互相矛盾的,所以必须一起看:只看生成速度,可能选出配置过于激进的方案;只看吞吐,可能选出单请求慢到无法忍受的方案。
下面这段脚本是我常用的最小压测工具,测的是首 token 延迟和总时长,跑三遍取中位数,避免抖动干扰。
import time import statistics import requests BASE = "http://127.0.0.1:8080/v1/chat/completions" PROMPT = "用三百字解释一下稀疏激活模型为什么在同样硬件上比稠密模型快。" def one_run(): payload = { "model": "local-moe", "messages": [{"role": "user", "content": PROMPT}], "max_tokens": 300, "temperature": 0.6, "stream": True, } t0 = time.perf_counter() first = None chars = 0 with requests.post(BASE, json=payload, stream=True, timeout=300) as r: for line in r.iter_lines(): if not line: continue if line.startswith(b"data: ") and line != b"data: [DONE]": if first is None: first = time.perf_counter() - t0 chars += 1 total = time.perf_counter() - t0 return first, total results = [one_run() for _ in range(3)] ttft = statistics.median([r[0] for r in results]) total = statistics.median([r[1] for r in results]) print(f"首 token 延迟: {ttft*1000:.0f} ms") print(f"总时长: {total:.2f} s, 约 {300/total:.1f} token/s")注意这里的 token 速度是用固定 max_tokens 反推的粗略值,精确值要用分词器数输出长度,不过做配置对比时这个粗值完全够用。
5.2 质量回归:别让调优把效果调没了
性能指标好看,但答案变差,这是量化调优里最常见的翻车方式。所以我每次改量化档位或者改卸载策略之后,都会跑一组固定题做回归。题库不用大,十道题就够,但要覆盖你实际会用的场景。
我的题库结构是这样:两道代码题(一道要写函数,一道要解释报错)、两道长文摘要(一篇技术文一篇新闻)、两道逻辑推理、两道中文写作(一篇正式一篇口语)、两道事实性问答(要求给出不确定就说不确定,考察它会不会编)。每次调优前后各跑一遍,人工扫一眼,重点看有没有出现这三种退化:句子开始重复、逻辑链条断裂、开始编造细节。这三种情况一出现,基本可以判定量化档位降过头了。
注意:质量回归别只看单次输出,同一道题跑三次看一致性。有些配置下模型第一次答对,后面两次开始漂,这种“质量抖动”比稳定答错更麻烦,因为它让你以为配置没问题。
我自己的经验是,从 Q4_K_M 往下降到 Q3_K_M,日常问答几乎感觉不到差别,但代码题的正确率会明显掉一档。所以如果主要用途是写代码,宁可牺牲速度和上下文,也要保住 Q4 以上的档位。
6. 常见问题与排查实录
这一节是我这两年里攒下来的问题清单,按照“启动期”和“运行期”分开,因为这两类问题的排查路径完全不一样。启动期的问题通常是配置写错了,看日志就能定位;运行期的问题往往跟负载有关,得靠观测。
6.1 启动阶段:加载失败与显存不足
一加载就报显存不足,但算下来明明够。这是最常见的问题,原因通常是没算计算缓冲。推理引擎在加载时会预留一块用于中间激活值的空间,batch 越大、上下文越长,这块越大。排查方法很直接:把上下文先砍到 2048、batch 砍到 256,如果能起来,说明是缓冲不够,再一点点往上加,找到临界点。
加载特别慢,磁盘灯一直亮。模型文件大,从机械硬盘读进来要几分钟很正常。换成固态能快十倍以上,这是投入产出比最高的一次升级。另外,如果系统内存不够,加载过程会走交换分区,那个速度会让你以为程序卡死了。
起来了但一开始生成就崩。大概率是模板不匹配或者特殊字符处理有问题。检查模型发布包里有没有推荐的模板配置,把模板参数显式传进去,别依赖框架的自动识别。
6.2 运行阶段:速度波动、输出异常、长上下文变慢
速度忽快忽慢。先看是不是专家卸载层数设得太满,导致显存和内存之间频繁搬运数据。把卸载层数往上加两层试试,速度往往会变得更均匀。另一个可能是有别的程序在占显存,跑之前清一下。
输出到一半开始重复同一句话。三个原因按可能性排序:重复惩罚设太低、上下文里确实有大量重复内容被它学了去、量化档位过低导致输出分布畸变。先调惩罚到 1.05 到 1.1 之间,不行就换高一档量化验证。
上下文一长就变慢得厉害。这是注意力计算的平方复杂度在起作用,属于架构层面的固有代价,不是配置问题。缓解办法是开闪光注意力,或者把长文档任务改成“分段摘要再汇总”的两阶段流程,比硬扛长上下文划算得多。
双卡比单卡还慢。前面提过,张量并行的跨卡同步开销可能吃掉全部收益。判断方法很简单:把张量并行度设为 1,只用一张卡跑,如果速度反而上升,就说明卡间通道是瓶颈。这时候改用专家并行或者干脆退回单卡更明智。
6.3 一张速查表收尾
| 现象 | 最可能的原因 | 优先尝试的动作 |
|---|---|---|
| 启动即报显存不足 | 计算缓冲未预留 | 上下文降到 2048,batch 降到 256 |
| 加载耗时数分钟 | 存储介质太慢 | 模型文件迁到固态 |
| 首 token 延迟超过 3 秒 | 排队或预处理重 | 降并发,检查是否有其他任务占卡 |
| 生成速度低于 10 token/s | 专家卸载过多 | 卸载层数减 2 到 4 层 |
| 速度忽快忽慢 | 显存余量太小触发搬运 | 卸载层数加 2 层,留足余量 |
| 输出重复或跑题 | 采样参数或量化档位 | 惩罚调到 1.05,换高一档量化复核 |
| 长上下文明显变慢 | 注意力复杂度 | 开闪光注意力,改用分段处理 |
| 多卡慢于单卡 | 卡间同步开销 | 张量并行度设为 1 做对照 |
| 多轮对话角色混乱 | 聊天模板未生效 | 显式传入模板配置 |
我个人在实际操作中的体会是,混合专家模型的调优跟稠密模型最大的区别在于“不要追求全量加载”。稠密模型的思路是能塞进显存就塞,塞不进就降量化;而混合专家模型的正确姿势从一开始就是混合部署——权重的主体躺在内存里,热的部分留在显存,靠卸载层数这一个旋钮去平衡。把这个思路扭过来之后,24GB 的卡跑 35B 总参数的模型,从“想都不敢想”变成了“日常真能用”。
最后分享一个小习惯:我每次调整配置都会在文件名里带上关键参数,比如带 q4km、ctx8k、moe14 这样的标记,跑出来的一组数据单独记一行。攒上十几组之后你会发现,真正影响体感的就那么两三个参数,其余的改动都是噪声。这个记录本比任何调参指南都值钱,因为它是针对你这台机器的。