一张 2018 年的矿卡,跑赢了 GPT-5
旧卡 + 端侧优化 + 选对壳:我只做对了三件事
- 硬件:2018 年 RTX 2080 Ti,22G 魔改,Turing sm75 —— 没有 FP8、没有 NVFP4
- 结果:HumanEval 98.2%,解码 50~57 tok/s,128K 上下文,占用 21.9 / 22.5 GB
- 第一件事:换掉对话模板 —— 前缀缓存 0% → 97.4%
- 第二件事:选对 harness —— 同一份权重,±40 分
- 第三件事:别信默认值 —— 一个设置 = 6 倍加载时间 + 38% 性能
战绩:这张卡跑出了什么
一台 2018 年发布的显卡:RTX 2080 Ti,22G 魔改版,Turing 架构,sm75。它跑的是 277.8 亿参数的稠密模型,128K 上下文,4-bit 量化。
| 指标 | 实测值 |
|---|---|
| 显存占用 | 21.9 / 22.5 GB(仅剩 600 MB 余量) |
| 热解码速度 | 50 ~ 57 token/秒 |
| 长提示词处理 | 615 ~ 616 token/秒(9624 token 用时 16.7 秒) |
| 多轮对话缓存命中 | 97.4% |
| 启动到可用 | 51 秒 |
| HumanEval(164 题) | Gemma4-26B 98.2% · Qwen3.8-27B 95.7% |
| MBPP(100 题) | Gemma4-26B 87.0% · Qwen3.8-27B 82.0% |
这个 98.2% 不能直接和公开榜比较。公开榜用官方原始补全协议,而那个协议对现在的对话模型不适用 —— 它设了一个 \n 加 def 的停止符,设计前提是模型在函数体内部续写,但对话模型会在第 0 列重新输出整个函数签名,于是输出被当场掐断。我第一次跑的时候,5 道题全部只返回了 9 个字符。改成指令包装协议之后,分数天然更容易拿高。
所以这把尺子本身也已经饱和 —— 它测的是天花板在哪,而不是谁更高。这反而说明了一件事:本地模型已经跑进了第一梯队,分数和榜单前十里的任何一条都在同一量级,不是差一点,是这把尺子分不出来。
真正有区分度的是 MBPP:本地最好成绩 87.0%,而公开榜前沿阵容从 87.8% 起。这才是实打实的差距,本地模型还差一截。
凭什么:22G 显存装下 27B 的两个前提
网上流传的说法是「27B 至少要 32G 显存」。这个说法不算错,但它说的是官方 FP8 与 NVFP4 权重那条路线 —— 那套东西需要 Blackwell 架构的新卡,本质上是要你换显卡。
UD-Q4_K_XL 把权重压到 16.35 GiB。动态量化意味着对质量敏感的层保留更多位数,同体积下优于平铺量化。
这个模型 64 层里 48 层是线性注意力、只有 16 层是全注意力。需要存的 KV 缓存极少,且线性注意力那部分的记忆是固定大小、不随上下文增长。
同样 27B 的纯注意力模型,光 KV 缓存就能把 22G 显存吃干净。128K 上下文能塞进这张卡,靠的是模型设计。
| 量化方案 | 权重体积 | 上下文 | 判定 |
|---|---|---|---|
| UD-Q4_K_XL(本机采用) | 16.35 GiB | 128K,KV 4-bit | 实测占用 21.9 / 22.5 GB |
| Q4_K_M | 约 17.8 GB | 32 ~ 64K | 可用 |
| Q5_K_M | 约 19.5 GB | 16 ~ 32K | 紧张 |
| Q6_K | 约 22.5 GB | — | 全量放不下 |
| Q8_0 | 约 29 GB | — | 不可行 |
另外,投机解码是白捡的速度:这个模型自带 MTP 头,启用后草稿接受率 0.86,平均每次前向产出 4.45 个 token。
第一件事:换掉那个官方对话模板
这是三件事里最不性感、但价值最高的一件。GGUF 模型文件里内嵌了一份对话模板,决定模型怎么读你的多轮对话。这份官方模板有三个毛病,前两个是参数问题,第三个是致命的。
- reasoning_effort 默认值被写成 xhigh,思考 token 消耗极高
- 对 effort 取值设了白名单,OpenAI 风格的 high 会被直接拒绝
- 跨轮重新渲染历史的方式不一致,导致前缀 token 序列变化,prompt 缓存全部失效
缓存失效意味着:每问一句,模型都要把整个对话从头重读一遍。这台机器处理输入的速度是 615 token/秒,社区在同类硬件上实测过 —— 64K 上下文下缓存失效时,每轮要干等 163 秒才吐出第一个字。换掉模板之后,多轮缓存命中率是 97.4%,第 5 轮时只有新增的那一点点内容需要重算。
这一件事的价值,超过后面所有参数调优的总和。而它恰好是所有人都会跳过的一步。
第二件事:选对驱动它的壳
模型本身不会自己读文件、写文件、跑测试。你需要一个 agent 工具去驱动它 —— 这个软件壳,英文叫 harness。这是三件事里变量最大的一件。
我做了组对照实验:完全相同的 40 道题、完全相同的指令,唯一变量是驱动它的壳。
| 组合 | 通过率 | 每题中位耗时 |
|---|---|---|
| Gemma4-26B 单干(对照) | 97.5% | 7.5 秒 |
| Gemma4-26B × Crush | 57.5% | 33.0 秒 |
| Qwen3.8-27B 单干(对照) | 90.0% | 5.2 秒 |
| Qwen3.8-27B × Pi | 95.0% | 23.0 秒 |
同一个模型:套上对的壳,+5 分;套上错的壳,−40 分。模型没变,壳变了。这不是模型能力问题。
那 17 次失败到底发生了什么?我把 40 次运行的原始记录全部翻出来看 —— 40 次里有 17 次,根本没写出任何文件。不是写错了,是什么都没干。模型的完整回复是:
I need the description of the Python function you'd like me to implement. Please provide it.
而题目的完整描述,就在它面前。我逐个排查过:
| 怀疑 | 检验 | 结论 |
|---|---|---|
| 程序崩了 | 退出码 0,错误输出为空,14 ~ 18 秒干脆利落地回答 | 排除 |
| 提示词被截断 | 上下文是 262144,容量充裕 | 排除 |
| 某几道题有问题 | 同一条失败输入原样重放 5 次:1 次成功,4 次一模一样的拒绝 | 排除 |
| 环境偶发 | 成功运行中位 41 秒,失败运行 17 秒 —— 失败者立即作答 | 支持模型未进入工具调用 |
把三套壳的失败记录拆开看,会发现一个比分数更重要的区别:一个壳的失败 100% 是代码写错了,另一个壳的失败 100% 是什么都没写。这两种失败的性质完全不同 —— 写错了你还能改,它压根不动手,你连改的机会都没有。
各挂各的,说明这是壳特有的失效模式,不是题目难度问题。选 harness 不是选界面好不好看,是在选模型的成绩单打几折。
第三件事:别信默认值
第三件事最简单,但也最容易踩。Ollama 把上下文默认值设成了模型的完整长度 262144,结果 KV 缓存溢出到系统内存。改成 32768 之后:
| num_ctx | 内存分布 | 加载耗时 | 解码速度 |
|---|---|---|---|
| 262144(默认) | 22% / 78% CPU/GPU | 194.3 秒 | 59.4 tok/s |
| 32768(改对后) | 100% GPU | 32.0 秒 | 95.5 tok/s |
一个默认值,6 倍加载时间、38% 的性能。而且注意:权重始终是 31/31 层全在 GPU 上的 —— 溢出的是 KV 缓存的内存占用,不是模型层在 CPU 上跑。这两个说法经常被搞混。
同理还有三个参数,设错了会变成「能跑但没法用」:
- KV 缓存量化(-ctk q4_0 -ctv q4_0):不量化,128K 的缓存根本装不下
- Flash Attention(-fa on):量化 KV 的必要前提
- 投机解码(--spec-type draft-mtp --spec-draft-n-max 4):深度 4 是甜点,2 太浅、6 以上启动就爆显存
结论:老卡到底值不值
回头看,这台八年前的机器能达到这个成绩,靠的不是硬件。三件事,没有一件跟硬件有关:
缓存命中率 0% → 97.4%,每轮等待时间差一个数量级。
同一份模型 ±40 分;好的壳还能再 +5 分。
一个参数 = 6 倍加载时间、38% 的性能。
- 新款显卡
- 更大的显存
- 云端 API 预算
- 一份正确的对话模板
- 一个维持前缀缓存的 harness
- 把默认值逐个核对一遍的耐心
端侧模型 + 做对工程细节 + 选对壳,一台八年前的机器就能跑进第一梯队。而这几年里,绝大多数人换显卡的理由,其实是后面这三件事没做对。
最后交代清楚:本机实测用的是指令包装协议,公开分数用官方补全协议,两者不可直接比较;HumanEval 发布于 2021 年,几乎必然已进入所有大模型的训练数据;栈级实验样本量为 40 题,95% 置信区间约 ±13 个百分点,因此好的壳之间的差距不可分辨,而 −40 分的差距远在误差之外。完整研究报告包含 14 节、34 张表,以及我在过程中发现并更正的 9 处错误。
