这篇能做出什么
读完并照着做,你能在一张可用显存约 13GB 的消费级显卡上,把 27B 级别的 Qwen 模型真正跑起来,并且知道每一层、每一份 AI 词典:KV Cache">KV Cache 分别占了哪块内存。具体产出:
- 一份属于你自己的"显存账本":权重占多少、KV Cache 占多少、计算缓冲留多少
- 一个能落地的量化档位选择(是全量放显存跑 Q3 档,还是 Q4 档配部分层卸载)
- 一条可复制的 llama.cpp / Ollama 启动命令,含上下文长度与 KV 量化参数
- 一套本地推理与云端 API 的分工原则,避免"什么都本地跑"或"什么都调 API"
注意:27B 模型在 13GB 显存里属于"刚好够、但要精打细算"的场景,不存在无脑配置。下面所有数字都是估算方法,实际参数量、层数、KV 头数请以模型的官方卡片为准。
前置条件清单
- 一张 NVIDIA 消费级显卡,扣除显示输出与桌面占用后,实际可用显存约 13GB
- 显卡驱动与 CUDA 运行时可用(
nvidia-smi能正常输出) - 最近的 llama.cpp 构建(自行编译或用官方发布的二进制),版本以官方仓库当前发布为准
- 或使用 Ollama、LM Studio 这类带图形界面的运行时,版本同样以官方页面为准
- 磁盘空间:GGUF 文件本身约 9–17GB,另外预留一份余量用于下载临时文件
- 系统内存建议 32GB 及以上,层卸载到 CPU 时内存会顶上
- 基本的命令行操作能力
第一步:先把 13GB 的账算清楚
显存不是只装权重。真实占用是四项相加:
```
可用显存 ≈ 权重 + KV Cache + 计算缓冲 + 显示输出占用
```
- 权重:由量化档位决定,见下一步
- KV Cache:由上下文长度决定,是新手最容易漏掉的一块,见第三步
- 计算缓冲:批大小、注意力中间结果等,通常留 0.5–1.5GB
- 显示输出:接了显示器且没关桌面合成的话,可能吃掉 0.5–1GB
也就是说,13GB 里真正能给"权重 + KV Cache"用的,往往只有 11–12GB。这个认知决定了后面所有取舍。
第二步:量化档位怎么选
不同量化档位有大致稳定的"每权重比特数"(bpw)经验值。用参数量 × bpw ÷ 8 就能粗估权重体积:
| 量化档位 | 约 bpw | 27B 权重体积估算 | 13GB 内全量卸载 |
|---|---|---|---|
| Q8_0 | 8.5 | 约 28–29GB | 不可行 |
| Q6_K | 6.6 | 约 22GB | 不可行 |
| Q5_K_M | 5.7 | 约 19GB | 不可行 |
| Q4_K_M | 4.8 | 约 16GB | 需卸载部分层 |
| Q3_K_M | 3.9 | 约 13GB | 临界,需压上下文 |
| IQ3_XS / IQ3_XXS | 3.1–3.4 | 约 10–11.5GB | 可行 |
| Q2_K / IQ2_M | 2.6–2.7 | 约 9GB | 可行,质量损失明显 |
结论很直接:
- 想全部层放进显存、还要留出 4K–8K 上下文,目标档位落在 IQ3 系列或 Q3_K_M
- 想用 Q4_K_M 这类质量更好的档位,就必须接受一部分层跑在 CPU 上,速度会掉
- Q2 档虽然塞得下,但在中文长句、代码补全这类任务上可能出现明显的重复、串行、丢指令,能用但别指望它是日常主力
选型顺序建议:先确定"我能不能接受部分层走 CPU"。能接受就上 Q4_K_M,用质量换速度;不能接受就选 IQ3 系列,用一点质量换全速。
第三步:KV Cache 与上下文长度的账
KV Cache 的估算公式:
```
KV 字节数 = 2 × 层数 × KV 头数 × head_dim × 上下文长度 × 每个元素字节数
```
其中 2 是 K 和 V 两份,每个元素 fp16 占 2 字节。
举一个典型配置的例子(层数 48、KV 头数 8、head_dim 128),单 token 的 KV 占用:
```
2 × 48 × 8 × 128 × 2 = 196,608 字节 ≈ 192 KiB
```
乘上上下文长度:
| 上下文长度 | fp16 KV Cache | q8_0 量化 KV |
|---|---|---|
| 4096 | 约 0.75GB | 约 0.4GB |
| 8192 | 约 1.5GB | 约 0.75GB |
| 16384 | 约 3GB | 约 1.5GB |
| 32768 | 约 6GB | 约 3GB |
看到问题了吗?如果权重已经吃掉 11GB,再开 32K 上下文,光是 KV Cache 就爆了。这就是"13GB 跑 27B"的真正瓶颈所在。
三条可用的压缩手段:
1. 降低上下文长度。多数本地对话和代码补全场景,8K 完全够用,先按 8192 起步
2. 启用量化 KV Cache。把 KV 缓存从 fp16 压到 q8_0,显存直接减半,质量损失通常可以接受
3. 多轮对话及时清空。长会话累积的 KV 不会自动释放,重启服务比死撑更省事
以这个例子为准,一套比较稳的组合是:IQ3 系列权重(约 11GB)+ 8192 上下文 + q8_0 KV(约 0.75GB),加起来约 11.75GB,再留 1GB 计算缓冲,刚好落在 13GB 预算内。
第四步:显存拆分(层卸载)实操
层卸载指的是:把一部分 Transformer 层放在 GPU 上算,剩下的放在 CPU 上算。CPU 那部分会慢一个数量级,但至少能跑。
先用 llama.cpp 找到"临界层数"。第一步,全量卸载,看它报不报错:
```bash
llama-cli \
-m /path/to/model-IQ3_XS.gguf \
-ngl 99 \
-c 8192 \
-ctk q8_0 -ctv q8_0 \
-fa \
-p "用三句话解释什么是 KV Cache。"
```
参数说明:
-ngl 99:尽可能把所有层丢到 GPU(99 是习惯写法,表示"全部")-c 8192:上下文长度-ctk q8_0 -ctv q8_0:K/V 缓存量化类型-fa:开启 Flash Attention,能显著降低注意力部分的显存占用
如果这一步直接 OOM,就把 -ngl 往下调。经验做法是二分查找:先试 40,再试 30、35,直到能稳定加载。加载日志里会明确打印类似 offloaded 32/48 layers to GPU 和 KV self size = 768.00 MiB 的信息,这两行就是你的账单。
找到能跑的最大层数后,再往回退 1–2 层。因为推理过程中显存会随着批大小波动,卡在临界值上跑,短会话没事,长会话就容易崩。
如果确认模型是 MoE 结构(总参数大、激活参数小),策略完全不同:所有专家权重都得驻留在内存里,可以用 --n-cpu-moe 这类参数把专家张量留在 CPU、只把注意力层放 GPU。具体参数名以当前 llama.cpp 用法说明为准。
用 Ollama 的话,等价配置写在 Modelfile 里:
```dockerfile
FROM /path/to/model-IQ3_XS.gguf
PARAMETER num_gpu 99
PARAMETER num_ctx 8192
```
注意 Ollama 的默认上下文经常比你想象的短,num_ctx 一定要显式写。
第五步:跑起来并验证
换成 server 模式,拿它当本地 OpenAI 兼容接口用:
```bash
llama-server \
-m /path/to/model-IQ3_XS.gguf \
-ngl 32 \
-c 8192 \
-ctk q8_0 -ctv q8_0 \
-fa \
--host 127.0.0.1 --port 8080
```
开另一个终端监控显存:
```bash
watch -n 1 nvidia-smi
```
发一个请求测速:
```bash
curl http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "写一个 Python 快排"}],
"max_tokens": 256
}'
```
重点看两个数:生成速度(tokens/s)和峰值显存。如果峰值贴着上限,就把 -c 降到 4096 再看一遍。
速度参考思路:全部层在 GPU 上时,消费级卡通常在每秒几十个 token 的量级;一旦有相当比例的层落到 CPU,速度可能掉到个位数,长文生成会明显难受。所以"能跑"和"好用"是两回事,卸载比例最好控制在两成以内。
第六步:本地跑还是调云端 API
这不是二选一,是分工问题。按下面几个维度对照自己的情况:
- 隐私:数据不能出内网、不能上传,本地优先
- 使用强度:每天高频长时间使用,本地跑省下的是持续成本;偶尔用几次,API 更划算
- 质量要求:需要长上下文、复杂推理、稳定结构化输出,云端大参数模型通常更稳
- 延迟与离线:断网环境、需要确定性响应时间,本地优先
- 上下文长度:本地受 13GB 显存限制,32K 以上很吃力;云端往往能直接给到更长
- 维护成本:本地要管模型文件、驱动、显存调参;API 只需要一个 key
比较现实的做法是混合路由:日常的改写、补全、简单问答走本地小模型;遇到长文档分析、复杂代码重构,再切到云端 API。接口都做成 OpenAI 兼容格式,切换只改 base_url 和一个环境变量,几乎零成本。
常见坑与排错
加载成功但一对话就崩
典型是 KV Cache 没算进去。先降 -c,再考虑降量化档位,不要一上来就改其他参数。
nvidia-smi 显示显存没满,速度却很慢
在 Windows 上,显存不够时驱动会偷偷用共享内存(把系统内存当显存),曲线看起来"没爆",实际带宽差很多。解决办法就是老老实实降 -ngl。
改了 -ngl 只加一层就 OOM
说明前面已经贴着上限了,加法是线性的,但计算缓冲不是。回退 2 层。
加载阶段卡很久
大文件 mmap 加载慢是正常的。如果反复卡死,试 --no-mmap,代价是启动时会把整个文件读进内存。
开了 KV 量化后回答变差
q8_0 的 KV 量化在多数任务上影响很小,但如果你已经在用 Q2/Q3 权重,两者叠加误差会放大。可以先把 KV 恢复成 fp16,看是不是这个原因。
Ollama 里上下文只有两千多
默认值的问题,显式设 num_ctx。
只看文件大小判断能不能跑
GGUF 文件大小只是权重,和运行时占用不是一回事。以加载日志里的实际数字为准。
下一步建议
1. 接进编辑器:把 llama-server 起的 8080 端口配到支持 OpenAI 兼容接口的插件里,补全体验会立刻不一样
2. 做一份显存预算表:把权重、KV、缓冲三项写成表格,换模型、换上下文时直接套
3. 试试投机解码:配一个同系列的小模型做 draft,在不增加多少显存的前提下提速度
4. 评估 MoE 模型:如果任务允许,MoE 结构在同样显存下的速度表现往往更有优势
5. 建混合路由:本地服务 + 云端 API 做成可切换的两个 profile,哪边合适用哪边
13GB 显存跑 27B,本质上是一道"分配题"而不是"能不能"的问题。把权重、KV、缓冲三块算清楚,剩下的就是按自己的使用场景调参数了。
