Betelgeuse:RTX 3060 12GB + 16GB 内存跑 Qwen 3.8 Flash Next,22 tok/s 不丢专家

2026-11-02来源:Betelgeuse GitHub 仓库 + Alpha-Orionis-XS 模型卡 + Reddit r/LocalLLaMA 原帖本地部署 MoE llama.cpp NVMe offload RTX 3060

开发者 zyxciss 10 月 31 日在 r/LocalLLaMA 发布 Betelgeuse:一个 llama.cpp 定制分支(bel-cli / bel-server,MIT 协议),在 RTX 3060 12GB + 16GB DDR4 单通道内存 + 消费级 NVMe 的机器上跑通 Qwen3.8-Flash-Next(125B 主模型,每 token 激活 6B)的 IQ2_XS 量化(68GB 运行包),重复负载下持续 22 tok/s。全部 24,576 个路由专家参与计算,输出与未修改的 stock 引擎逐字节一致。GitHub 仓库 10 月 31 日创建,当日挂出 v0.6.0 Alpha-Orionis 版本,并向 llama.cpp 上游提了 PR(#31469,open 未合并)。

前作因丢专家被作者废弃

作者两个月前发过 Qwen 3.6 35B 的 MoE 专家预测帖,当时靠 gate pruning(路由权重低时丢冷专家)把速度做上去,但低比特量化下输出质量退化。作者在原帖开头承认那版是「cheating」,已废弃。这次的目标就是把 68GB 的 IQ2_XS 权重在 12GB 显存 + 16GB 内存上跑出可用速度,且不丢一个专家。作者特意拔掉多余的内存条来模拟普通 16GB 机器,测试全程在 MemoryMax=12G 的 cgroup 限制内完成。

测试机配置:RTX 3060 12GB(CUDA sm_86)、16GB DDR4 单通道(约 19 GB/s)、消费级 PCIe NVMe(约 2.1 GB/s)、CachyOS/Arch Linux。

机制:显存专家槽位池、in-stream 门铃与 victim cache

Qwen3.8-Flash-Next 官方架构为 48 层、每层 512 个路由专家、每 token 取 10 个路由专家加 1 个共享专家,另有 51B 参数的 n-gram 嵌入表(官方写明比 MoE 更适合卸载)。Betelgeuse 把 24,576 个路由专家的量化字节原样保留,速度来自三层调度改造:

层 做法
显存 约 3.2GB 装下全部 dense 权重(attention 混合器、DeltaNet 状态、路由、共享专家、LM head);其余显存做约 5,000 个专家槽位,按层不均匀分配——前几层计算空隙为 0 毫秒,每层给 240 槽,中层 92、尾部 60
调度 stock 引擎每 token 把计算图切 48 次去 CPU 侧问「哪些专家未命中」,约 360ms/token 开销;Betelgeuse 用一个 in-stream CUDA kernel 在 GPU 上约 2µs 完成命中判定,只在未命中时触发主机门铃;per_layer_token_embd 也预置到显存,整个 decode 是单次 CUDA Graph replay
内存/盘 显存淘汰的专家先进 8GB 的 RAM victim cache(牺牲缓存),显存与内存 100% 互斥不重复缓存;再未命中经 buffered io_uring 读 experts.bin,物理盘读从 208–312 MiB/token 降到 12.43 MiB/token

磁盘布局也重排了:单文件 GGUF 里专家与 dense 权重混排、相邻专家间隔 100-250MB,Betelgeuse 把专家字节剥离重排成 4KB 对齐的单读 blob。运行包四个文件:Dense GGUF 3.77GB(元数据+dense 权重+专家描述符)、experts.bin 35.48GB、PLE GGUF 28.8GB(n-gram 表,原 shard 原样保留)、热专家画像 6.9KB,合计约 68GB。

bit-exact 的确切含义:与 stock 引擎输出逐字节一致

「100% bit-exact」指同一 IQ2_XS 权重下,输出与未修改的 stock llama.cpp 逐字节一致——不是与全精度模型一致,IQ2_XS 量化损失照旧存在。验证口径:两个 warmup 臂各匹配 576 个 golden 输出 token 与全部 28,080 条路由记录(0.000e+00 diff),全 24,576 个专家字节对比过原 GGUF,stripped bundle 的 1,079 个 dense 张量逐字节对比。专家读取/DMA 失败直接报错退出,而不是静默用零权重继续。

这个口径在社区有混淆,评论区有人以为「bit-exact」是质量承诺。作者文档明确:速度来自调度与 I/O 层,路由选择 top-10 从未被改动。

实测:22 是重复负载速度,48 是突发峰值

作者文档(测量记录 2026-10-30,受控协议:清页缓存 → 64-token 预热 → 两个 256-token greedy 补全):

配置 生成 Run 1 / Run 2 预填充 Run 1 / Run 2 盘读 MiB/生成 token
stock llama.cpp(修正基线,用户自报) 0.9 — —
Strata(用户自报) 8.0 — —
Betelgeuse,victim cache 8GB 16.29 / 22.03 13.85 / 19.35 35.37 / 12.43
Betelgeuse,auto-warm 开 16.80 / 21.85 16.18 / 18.29 30.54 / 12.88

20+ tok/s 是重复负载第二次运行(victim cache 已热)的速度,不是冷启动保证;Reddit 帖标题里的 48 tok/s 是作者报的「10 个路由专家全部驻留显存/缓存时的突发峰值」,仅出现在 Reddit 帖中,作者自己的 README 与模型卡数字表均未收录。README 原话:profile 文件不保证 22 tok/s。CUPTI 剖析显示第二次运行专家解析/搬运耗时从 34.89ms/token 降到 18.97ms/token。

同一块 3060 上作者还报了 Q8_K_XL(约 190GB 总量)档:8 tok/s 冷、12 tok/s 暖(burst 21),预填充 8-34 tok/s;stock 引擎直接 OOM 或低于 0.1 tok/s。预填充是当前短板,社区指出 Q8 档 34 tok/s 的预填充难以使用,作者回应新版本预填充会提升 10 倍。预填充在受控测量中两次运行差异大(13.85 对 19.35),作者文档承认「Prefill has not improved consistently across both runs」。

后续帖:IQ4_XS 档双通道 24 tok/s

11 月 1 日至 2 日作者又发一帖报 IQ4_XS 档:2×8GB DDR4 双通道 24 tok/s,单条 16GB(单通道)14 tok/s,仍标注 0 dropped experts / 100% byte-exact(此帖数字来自帖子标题,单源待证)。双通道比单通道快约 71%——内存带宽翻倍、速度接近按比例涨,说明数据量更大的 IQ4_XS 档内存带宽成为主要瓶颈。

限制与许可

  • 实测包络:单 context 单并发、上下文 512、-ub 64、Linux x86-64 + CUDA sm_86(RTX 30 系);其他 GPU/系统/后端未认证。更大的上下文与并发需要自行验证内存与正确性。
  • MTP 未启用:官方 1 层 MTP sidecar 冒烟测试接受率 75%(6/8)但输出在第 8 个 token 与 golden 分叉,发布版禁用。
  • 运行包不兼容 stock llama.cpp / Ollama / LM Studio,必须用 Betelgeuse 分支的 stripped-expert loader。
  • 自动缓存预热约 42 秒启动开销,且换话题仍会 miss;profile 只做热专家播种。
  • 许可提醒:引擎 MIT;权重不是无限制 Apache——底层模型是 Qwen Community License 1.0(含商用 MaaS / AI Work Assistant 限制),量化仓库声明的 Apache-2.0 与之有差异,模型卡原文提醒「不要假定无限制 Apache 权利」。商用前核原许可。

作者下一步是把同一套流式读取 + victim cache 架构移植到 DeepSeek V4.1 Flash (1017),同硬件档早期测试约 25 tok/s。

此前社区还有把专家权重留 NVMe 的 ExLlama 系方案(如 10 月 25 日的 Lean-QwenFlash,4090 限 16GB 显存 + 8GB 内存、EXL3 3.05bpw、262K 满窗 20 tok/s),与 Betelgeuse 是 llama.cpp 与 ExLlama 两条独立引擎路线,互相印证「专家留盘流式」这条低配路线可行。

参考链接