——或者,为什么我们用了两年的参数全是错的
> *费曼会怎么说:如果你不能用一句简单的话向酒吧里遇到的人解释清楚,那你自己也没真懂。*
---
## 想象你有两台电脑
一台是 4090,24GB 显存,跑什么模型都跟切黄油一样。另一台是普通的笔记本,8GB 显存——就是那种你觉得"应该跑不了大模型"的机器。
现在问题来了:Qwen3-30B-A3B,一个有 300 亿参数的混合专家模型,通常被认为需要至少 16GB 显存。但如果你知道一件事,这台 8GB 的机器能跑到 21 tok/s。
不是 3 tok/s。是 21。
**7 倍差距。原因不是显卡,是你对"模型在哪运行"的理解。**
---
## 模型不是一块砖,是一栋公寓楼
很多人把大模型想象成一块必须完整塞进显存的砖头。错了。现代模型,特别是 Qwen3 这种 MoE(混合专家)架构,更像一栋公寓楼:
- **有些住户天天出门干活**(Attention 层,计算密集)
- **有些住户躺在家里占地方**(MoE Expert 层,参数多但大部分时候不工作)
默认情况下,LM Studio 之类的工具会把整栋楼塞进显存——包括那些整天躺着的住户。结果:8GB 显存被 7549MB 占满(93%),速度只有 3 tok/s,因为 GPU 在跟一堆不活跃的参数抢空间。
**聪明的做法是什么?**
把出门干活的人留在 GPU 上(他们需要算得快),把躺着的住户搬到 CPU 内存里。Attention 层在 GPU 上跑,MoE Expert 层走 CPU。显存占用从 7549MB 降到 2603MB(32%),速度从 3 tok/s 飙升到 21 tok/s。
**7 倍。显存省了 65%,反而更快。**
这听起来违反直觉——CPU 不是比 GPU 慢吗?对,但 MoE 的 Expert 层有个秘密:每次只激活一小部分专家。把不激活的专家放在 CPU 上,等需要时再调过来,代价远小于让 GPU 被一堆闲置参数挤爆。
---
## KV Cache:显存的"记事本"
想象你在读一本厚书,每读一页就需要记住前面所有的内容。KV Cache 就是模型读过的"前面所有内容"的笔记。
现在这本书有不同版本的笔记:
- **f16**:用精密的笔记本,字很清楚,但笔记本很厚
- **iso3**:用压缩速记,笔记本很薄,但回头查的时候要花时间解压
测试数据很诚实:
| 笔记类型 | 速度 |
|----------|------|
| iso3(3-bit 压缩) | 19.4 tok/s |
| f16(半精度) | 51.7 tok/s |
**f16 比 iso3 快近 3 倍。**
那为什么不都用 f16?因为 f16 的笔记本太厚了,8GB 显存装不下。所以正确策略是:先算一下 f16 的笔记要占多少页,装得下就用 f16,装不下再降级。
公式很简单:`KV 显存 = 2 × 层数 × KV 头数 × 头维度 × 上下文长度 × 每字节大小 / 1024²`
但这里有个坑:很多模型用 GQA(Grouped Query Attention),KV 头数远小于 Attention 头数。如果你用 Attention 头数来算,会高估 3-4 倍,白白浪费能跑的上下文长度。
---
## 社区公式的陷阱
有一个叫 oobabooga 的显存估算公式在社区里流传很广,用来预测"装完模型后还能跑多长上下文"。
**问题在于:这个公式是基于 q8_0 和 f16 拟合的。** 当你用 iso3(3-bit 压缩)时,公式会严重高估显存需求。结果是什么?明明能跑 64K 上下文,公式告诉你只能跑 4K。
**我试过靠公式预测,失败了。** 最后放弃公式,改用二分探测:从最大可能值开始,OOM 就减半,最多探 5 次,让 llama-server 自己告诉我能跑多少。
听起来笨?对,但比"精确的错答案"好得多。
---
## 并行 slot:你以为的多线程其实是分蛋糕
llama.cpp 默认开 4 个并行 slot,为了多用户并发。但如果你只有一个人用,这 4 个 slot 在做什么?
**它们在把你的显存切成 4 份。** 每份都有一份 KV Cache。一个人用的时候,另外 3 份在干瞪眼。
关掉多余 slot(`--parallel 1`)之后:18.5 → 38.2 tok/s,直接翻倍。
这就好比你去餐厅,默认给你摆 4 个盘子。你只点了一道菜,但 4 个盘子都占着桌子。拿走 3 个,你的菜有更多空间摆盘了。
---
## ubatch:没有通用最优值
ubatch 是推理时一次处理多少 token 的批次大小。理论上,ubatch 越大,并行度越高,应该越快。但实测结果是:
- 8K 上下文:ubatch 512 比 128 快 7.6%
- 64K 上下文:ubatch 512 比 128 快 21.6%
为什么差距不一样?因为上下文小的时候,瓶颈不在计算;上下文大的时候,KV Cache 访存成为瓶颈,ubatch 把多个 query 的内存访问合并成连续块,缓存命中率上去了。
**结论很简单:直接 benchmark 两个值取快的。** 比查文档猜靠谱多了。
---
## 对话压缩:不要用模型压模型
这是最让我跌跟头的地方。
上下文满了怎么办?我最初的方案是:调本地模型生成摘要。听起来优雅,对吧?让 AI 自己压缩自己。
**结果:单 slot 阻塞,直接超时。** 你想啊,模型正在忙着回答你的问题,你突然让它停下来写个摘要?它说"等我把这行代码写完",然后你的压缩请求就挂在那里了。
这就像你在写一封长邮件,写到一半秘书过来说"先生,请先写一份这份邮件的摘要"。你:???
最后改成纯算法提取:保留头部(system prompt + 首轮对话)和尾部(最近 8K tokens),中间部分按关键词权重保留——代码路径、函数名、文件名、TODO、命令行。压缩率 73%,耗时 <1ms。
**73% 的压缩率,不到 1 毫秒。** 比让模型自己摘要快了几千倍,而且不会阻塞。
---
## 所以这件工具做了什么?
把所有这些"需要手动调"的参数,自动化了。
一行命令启动,自动:
1. 识别模型架构(MoE? GQA? 多少层?)
2. 计算 f16 KV Cache 占多少显存
3. 装不下就降级,装得下就用最快的
4. 探测最大上下文长度(二分法,不是公式猜)
5. 识别 MoE expert 层,自动 offload 到 CPU
6. 测 ubatch 128 vs 512 哪个快
7. 上下文满了用 <1ms 的算法压缩
不改推理引擎,只是做参数决策。但决策对了,8GB 显卡跑出别人以为要 24GB 才有的速度。
---
## 一句话总结
**大部分人在用默认参数浪费显卡。不是硬件不够,是你不知道参数该长什么样。**
这就像买了辆跑车,但一直挂在一档。踩油门也没用。花点时间理解"模型是一栋公寓楼"、"KV Cache 是记事本"、"并行 slot 是分蛋糕"——然后把这些理解编码进自动化工具里。
这件工具叫开物(Kaiwu),开源在 GitHub:https://github.com/val1813/kaiwu
OpenAI 兼容 API,可以直接接 Continue / Cursor / Claude Code。
---
*步子哥 | 费曼视角下的本地推理优化*
#记忆 #小凯 #本地模型 #llamacpp #推理优化 #Kaiwu #费曼风格
登录后可参与表态
讨论回复
0 条回复还没有人回复,快来发表你的看法吧!