12GB 显存跑 35B,听起来像标题党。我第一眼看到这套数字,先把权重、上下文和内存三笔账分开算了一遍。
算完发现确实不是魔法:26 层 MoE 被丢给 CPU,权重用 Q4_K_M,KV cache 压到 Q8,剩下的靠 llama.cpp 在显卡和内存之间来回搬。能跑,50 tok/s 也是真的;但这套数字只回答「跑得动吗」,不回答「能不能当编码 Agent 用」。
这套配置到底把什么放进了 12GB
先看清单:
- 显卡:RTX 3060,12GB 显存
- 系统内存:16GB
- 权重:Q4_K_M,35B 总参,按 4bit 出头算,光权重就接近 20GB
- 注意力:Flash Attention 打开,KV cache 用 Q8
- 分工:26 层 MoE 交给 CPU,其余层留在 GPU
- 运行时:llama.cpp 的 llama-server
20GB 权重塞进 12GB 显存,唯一的路是拆开。26 层去 CPU,等于把一部分专家权重放进系统内存,GPU 只留放得下的部分。这不是「模型变小了」,是「模型被分成了两半」。
A3B 省的是算力,不是显存
35B 总参、3B 激活,意思是每个 token 只走 3B 左右的计算路径。decode 本来就是逐 token、吃显存带宽,活跃参数少,单步就轻,50 tok/s 不奇怪。
但「只激活 3B」不等于「只需要 3B 的显存」。全部专家还得存着,路由到哪个专家,哪个专家的权重就得在。把 A3B 理解成 3B 模型,是这类配置最容易踩的坑。省下来的是每一步的乘加,不是权重占的地方。
26 层下放 CPU,代价是每步都要过一趟 PCIe
GPU 算完自己的层,激活值要经 PCIe 交给 CPU;CPU 算完 26 层,再交回来。每生成一个 token 都要走一遍。层数越多、来回越频繁,瓶颈就从算力变成传输和内存带宽。
16GB 系统内存也不宽裕:一部分装下放的专家,一部分留给 KV cache 和运行时,剩下给系统的就不多了。浏览器、IDE、Docker 一开,数字会变。
- 1路由选专家每层只激活少数专家,整轮约 3B 激活
- 2GPU 层计算显存放得下的层先在卡上算完
- 3激活值过 PCIe交给系统内存里的 26 层
- 4CPU 层计算用内存带宽换显存空间
- 5汇总采样各层算完后汇总 logits,采样出下一个 token
262K 是配置值,不是可用值
配置里写 262K,只说明 n_ctx 能开到这么大,不代表这个长度下还能保持 50 tok/s,也不代表内存装得下。
KV cache 随 token 数线性增长。35B 级别的模型,层数和 KV 头数摆在那,Q8 已经压过一轮,26 万 token 粗算也是十几 GB 起步。12GB 显存加 16GB 内存,不可能全放显存,只能继续往 CPU 内存里挤。
实际能用的上下文,要一点点往上加:8K、16K、32K,每档看显存占用、系统内存、decode 速度,以及有没有开始 swap。掉到 swap 那一刻,速度不是打折,是换了一个数量级。
长上下文还有质量问题。能塞进去,不等于模型还能用住中间的信息。拿一段长文档做定位测试,比看参数表有用。
550 tok/s 的 prompt 和 50 tok/s 的 decode,不是一回事
prompt processing 是 prefill:整段提示一起进,矩阵乘能并行,550 tok/s 说的是这个阶段。decode 是一个 token 一个 token 往外蹦,每步都要读权重、走一遍 GPU 和 CPU 之间的往返,50 tok/s 说的是这个阶段。两个数字差十倍,不是测错了,是两种负载。
做编码 Agent 时,这个差别很要命。工具调用会把上下文越滚越长,每次追加结果都要重新 prefill 新增的部分;缓存命中做得好,只算增量,做不好就整段重算。聊天的体感是 decode,Agent 的体感往往是 prefill 加排队。只看 50 tok/s 去买机器,很容易失望。
真正该测的是活能不能干完
这套配置下一步该对比的,不是又一个 tok/s 数字,而是四件事:能不能写出可运行的代码、工具调用参数对不对、报错后能不能自己定位、多步任务会不会中途跑偏。
对本地编码 Agent 来说,一次任务重试三次,省下来的 token 成本全吐回去,人还得盯着。建议用同一组任务做 A/B:固定提示、固定工具集、固定上下文预算,记录完成率、平均重试次数、人工接管次数和总耗时。速度只作为其中一列。
50 tok/s 在交互式补全里很舒服,在长任务里可能被一次失败的 prefill 抵消。
想复现,先按这个顺序调
- 先确认显存余量。12GB 卡别一上来就开大上下文,先把 n_ctx 设到 8K,看模型加载后还剩多少。
- 用 Q4_K_M 起步,别急着上更低的档位。量化越低,权重越省,质量掉得也越明显;编码任务对量化很敏感。
- 用 `-ngl` 控制上卡层数,用 `-ot` 把专家张量单独指到 CPU。先让模型能起来,再谈速度。
- KV cache 先用 Q8,观察内存曲线;不够再降,别一开始就压到 Q4。
- 上下文逐档加,记录每一档的 decode 速度和内存占用,找到开始 swap 的那一档,往前退一档用。
- 最后再测任务完成率。跑分好看和能干活,是两件事。
12GB 显存跑 35B,成立的前提是把一半模型放进内存,再用 MoE 的稀疏激活把单步计算量压下来。这套思路值得学,但别把它读成「小显卡也能随便跑大模型」。最后决定能不能天天用的,是上下文开到多大、内存够不够,以及 Agent 任务能不能一次跑完。
50 tok/s 只是入场券。