Qwen3.8-27B在Mac上快3倍:mlx-dspark无损加速实测揭秘


Mac本地跑大模型快三倍,还一个字不差!

这可能是2026年Apple Silicon用户最该知道的秘密:Mac跑大模型,不用换硬件也能提速三倍!



一个GitHub项目,把Qwen3.8-27B的推理速度推到了新高度。8-bit目标模型,平均加速2.45倍,数学任务冲到3.00倍,代码任务2.38倍。M4 Pro 48GB机器上,每秒token从8.3飙到20.3。峰值内存约29GB。更反直觉的是,8-bit加投机解码跑出的速度(20-27 tok/s),居然超过了普通4-bit解码(14.6 tok/s)。精度更高,速度更快。项目叫mlx-dspack,开源不到两个月。

这个项目的底子,不是从零写的。它是DeepSeek的DSpark投机解码器在MLX框架上的移植,加上z-lab的DFlash,两条技术路线共用同一个无损验证循环。DeepSeek那个版本叫DeepSpec,本来是跑在数据中心GPU上的。z-lab的DFlash是一个独立研究实验室提出的块扩散解码器——注意,这里的z-lab与智谱AI(Zhipu AI)没有任何关系,只是名字里都有个"Z"。项目作者把这两套代码搬到了Apple Silicon上。v0.10.0加入了一个新东西:Qwen3.8-27B通过RadixArk的草稿模型获得支持。这是mlx-dspack加载的第一个SpecForge/SGLang打包的头部。草稿模型不再需要单独训练,可以直接用社区已经打包好的格式加载。

三倍加速的引擎是DeepSeek的。但把它装进Mac的,是一个个人开发者。这中间隔着一层移植工作——把CUDA生态的代码改成Metal能跑的版本,还要处理量化矩阵乘法在M系列芯片上的特殊斜率问题。

验证每个token都要花钱,这笔账怎么算

投机解码的逻辑不难。轻量级草稿模型快速生成一串候选token,原始目标模型逐字验证。对的留下,错的扔掉重来。输出由目标模型全权把关,所以结果与普通解码一字不差。无损是验证出来的,不是声明出来的。Mac应用里的Race视图会并排跑投机解码和普通解码,逐token对比ID,完全相同才通过。

这个机制本身有一个隐藏成本。验证不是免费的。目标模型每验证一个草稿token,都要做一次前向传播。如果一次提出7个token,验证成本就是7倍。如果提出16个,成本就是16倍。

M系列芯片上,这个成本有一个特别的名字叫斜率。量化方式不同,MLX版本不同,芯片型号不同,这个斜率都在变。mlx 0.31.2上,Gemma-4 12B的验证成本约每token 14毫秒。即使草稿完美,加速上限也只有2.2倍。mlx 0.32把曲线压平了,同样芯片上测出2.11倍。

项目用了--max-draft auto来解决这个问题。每台机器首次运行时实测约5秒,计算出最优的草稿长度,缓存到磁盘。4-bit量化最优cap是2,8-bit是4,bf16是6。同一个模型,换一种量化方式,最优草稿长度完全不同。同一个模型,换一台芯片,数字也变了。硬件瓶颈是客观存在的。但自动调参的方式绕过了部分限制。

8-bit跑得比4-bit快,量化逻辑被翻了过来

普通直觉:量化越低,模型越小,速度越快。mlx-dspack测出的数据把这个直觉推翻了。

Qwen3.8-27B-8bit加投机解码:20.3 tok/s。Qwen3.8-27B-4bit普通解码:14.6 tok/s。8-bit比4-bit快了39%。而且8-bit模型精度更高。

为什么会这样?因为投机解码的加速是加法。在目标模型解码的每一层都叠加草稿验证。4-bit目标模型的验证成本已经很低了,草稿模型的额外开销可能吃掉大部分加速收益。8-bit目标模型验证更贵,草稿模型的相对贡献更大,净收益反而更高。

项目文档里有一句话:接受率不是目标,单位验证宽度的接受率才是。放到量化对比上就是:8-bit的验证成本更高,但草稿模型每次提出的token被接受的比例更高,净收益反而更大。这引出一个操作层面的结论:如果内存够,优先跑8-bit加投机解码,而不是4-bit普通解码。质量更高,速度更快。不是所有模型都适用。Qwen3.8-27B适用。其他模型需要实测。

DSpark和DFlash在M4 Pro上谁赢了,取决于你问什么

DSpark和DFlash的工作方式不一样。DSpark一次提出7个token的块,用并行骨干加一个rank-256的Markov头来注入token间的依赖关系。DFlash是块扩散解码器,一次并行传递生成完整的16-token块。两者都依赖轻量级草稿模型快速生成候选,然后目标模型逐字验证。

Gemma-4 12B(8-bit,M4 Pro)上,DSpark cap-2在聊天任务上接受长度2.45,吞吐28.5 tok/s。DFlash full-16在代码任务上接受长度5.95,吞吐36.6 tok/s。数学任务上DFlash full-16接受6.20,吞吐36.3 tok/s。DFlash在结构化内容上完胜。接受长度约6.0对DSpark的约2.8,吞吐约2.1倍。但聊天任务上DFlash full-16是净亏损。16个草稿位大部分填不满。

换到Qwen3-8B-8bit(验证成本更便宜),DSpark赢在所有领域:聊天2.38/45.7,代码2.55/48.8,数学2.40/46.1。DFlash full-16在代码上只有2.94/27.6。同一个项目里,两种技术路线在不同模型上胜负完全颠倒。胜负手是目标模型的验证成本。验证越贵,DFlash的大块越划算。验证越便宜,DSpark的精准头越占优。

Qwen3.6-35B-A3B-4bit(MoE,M4 Pro)上,DFlash full-16在数学任务上接受9.62个token,项目有史以来测到的最高值。但它输在了吞吐上:DSpark达到1.33倍加速,DFlash full-16只有0.94倍。MoE的验证成本从第一行额外token就开始飙升,因为每个token都会拉入一组全新的路由专家。16-wide的验证是灾难性的,不管接受率多高。那句反复出现的话又回来了:接受率不是目标,单位验证宽度的接受率才是。

内存墙和长上下文,三倍加速还没覆盖的角落

Qwen3.8-27B-8bit峰值约29GB,4bit版本约18GB。加上KV缓存,长上下文会吃掉更多。48GB是项目测试的标准配置。16GB用户可能只能跑4bit版本且上下文受限。

macOS默认只让Metal使用约三分之二RAM。16GB机器上实际可用约10.67GB。调整sysctl iogpu.wired_limit_mb能挤出空间,但超过78%左右系统自身会开始抢占页面。这个限制对所有Mac用户都成立。M4 Pro 48GB的实际可用内存大约32GB。Qwen3.8-27B-8bit峰值29GB,加上KV缓存,剩余空间有限。

长上下文是另一个瓶颈。v0.3.1之前,草稿模型每轮都会冗余平铺GQA/MQA KV缓存,随上下文深度线性增长。在廉价验证目标上,投机解码在几千token之后确实变成了净亏损。这个bug在v0.3.1修复了。修复后的测试数据:Qwen3-4B上投机加速在12k+ token上下保持平坦约1.6倍。Gemma-12B这类昂贵验证目标上,投机解码甚至随深度略微加速。目标模型变慢的速度比草稿模型快,相对加速比反而增加了。

v0.10.1加了部分重用。系统提示词在推理过程中可以复用已计算的KV缓存。实测数据:M4 Pro,Qwen3.8-27B-4bit,约8k token系统提示词,加了前缀缓存之后,首token时间大幅缩短。但"支持前缀缓存"和"支持到20k token不崩"是两回事。项目文档没有提供20k以上的完整测试曲线。

项目还明确警告了一个flag:mlx.Metal.set_wire_limit(1)不要开。它会锁定页面,在16GB Mac上可能让系统硬挂到需要强制重启。它还曾在gemma-4/mlx-vlm路径上破坏验证logits。垃圾logits可能提交错误token,不只是崩溃。测试中没有可测量的速度提升。一个号称加速三倍的项目,文档里却写了一条这个flag别开。因为它在某些情况下会输出错误结果。无损的前提是用户不使用某些特定配置。

硬件变了数字就变,三倍不是一个常数

项目在README里说得很清楚:跑mlx-dspack benchmark,用你自己机器测出来的数字才是你的数字。表格里的3倍是M4 Pro的3倍。换到M3或M2会变。

成本模型是这样的:tok/s ≈ A / (drafter + overhead + slope·C)。A是接受长度,C是草稿容量。那个slope是量化方式、MLX版本和芯片型号共同决定的。这就是为什么--max-draft auto要在每台机器上实测一次,而不是写死一个常数。

实测数据印证了这个模型的预测。Qwen3.8-27B-8bit在M4 Pro上数学3.00倍,但同样的模型在4bit量化下只有1.74倍。同一个模型,8bit和4bit的加速比差了将近一倍。目标模型的精度选择直接改变了斜率,进而改变了最优草稿长度和最终加速比。

MLX版本升级也能改变数字。mlx 0.31.2上Gemma-4 12B的验证成本约+14ms/token,加速上限2.2倍。mlx 0.32的内核把曲线压平了,同样芯片上测出2.11倍。版本升级带来的加速,比换模型还明显。

这些数字加在一起指向一个结论:三倍加速是在特定硬件、特定量化、特定MLX版本、特定提示词集合上测出来的。任何一项变了,数字就变了。

Qwen3.8-27B的128k上下文还没测完

项目有一条未被验证的声明:Qwen3.8-27B的投机解码在长上下文测试中还没跑过。Qwen3.8-27B的context window是128k。投机解码的KV缓存会随上下文线性增长。8-bit目标加4-bit草稿,两条模型的KV缓存同时膨胀。48GB内存能撑到多少上下文?项目没有给出具体数字。

其他模型有长上下文数据。Gemma-4 12B在长上下文中投机加速甚至随深度略微增加——目标模型变慢的速度比草稿模型快,相对加速比反而更大了。但这个规律在Qwen3.8-27B上是否成立,没人知道。

Agent场景下还有一个额外问题。Claude Code每次请求发送约18-26k token的系统提示词和工具schema。预填充主导了墙钟时间。能复用前缀的模型赢了。Qwen3-8B接受长度只有3.01,但因为复用了约26k token,比接受长度5.07的Ornith还快了近一倍。项目文档的结论是:Agent选择对时钟的影响大于模型选择。三倍推理加速被18k token的系统提示词吃掉了大半。前缀缓存能解决一部分问题。但缓存的命中率取决于提示词的重复程度。agent场景下,每次调用的工具schema可能变化,缓存不一定能全量复用。

还有一件事没解决。mlx-dspack支持用户指定自己的草稿模型。但兼容性分三种:DeepSpec-native独立草稿可跑,z-lab DFlash适配器可跑,RedHatAI的speculators格式不兼容,DeepSeek-V4-Pro-DSpark(893GB,MLA+MoE)架构不兼容。项目在文档里说:如果你跑了一对我们没测过的组合,mlx-dspack benchmark --json会生成一个带设备戳的结果。

这意味着当前的性能表格——Gemma-4 12B数学3.09倍、Qwen3.6-27B数学2.67倍、Ornith-1.0-9B代码2.53倍——只是已知组合的子集。未经测试的组合可能更快,也可能完全不工作。

有人在M5 Max上跑过对比测试,数据贴在了另一个讨论串里。llama.cpp加MTP的加速比和mlx-dspack在同一个模型上各有高低。但M5 Max的数据不能代表M4 Pro,更不能代表M3或M2。每颗芯片的斜率都不同。

如果有人在自己的M4 Pro上跑完128k上下文的完整测试,数字会是多少?没人知道。项目仓库的issue列表里还没有这个问题的完整答案。