← 返回 AI Radar

FIELD NOTES / LOCAL INFERENCE

Mac mini M4 跑 Qwen:
不只看 token/s。

32GB 统一内存,同机不同轮次的 9B、27B、35B 测试;再看 oMLX 专家卸载和前缀缓存如何改变等待体验。

M4 · 非 M4 Pro32GB 统一内存单并发 · 文本短测逐次数据可下载
先给结论:在这台机器和已记录的短输入下,35B-A3B 4bit 全常驻输出约 43–45 token/s;9B 4bit 约 19.5 token/s,但内存更小。专家卸载能降低 oMLX 的模型加载分配,却明显增加等待。它们都不是回答准确率、全天稳定性或其他 Mac 的性能保证。

测了什么,又没有测什么?

这是一组真实部署过程中的工程记录,目的是为本地助手选择兜底模型,不是先设计好的标准评测。机器是同一台基础款 Mac mini M4、32GB 统一内存;27B 的预热记录来自此前测试,9B、35B 与 oMLX 的追加记录在 11 月 1 日核对。不同轮次、引擎和缓存状态不能假装成严格受控的横评。

已记录的性能测试条件
项目本次记录
机器Mac mini M4/32GB;不是 M4 Pro、Max 或 Ultra
推理后端Rapid-MLX 0.16.10;oMLX 0.7.3。仅对应测试时版本,不表示当前最新版
请求单并发、流式输出、temperature=0、max_tokens=64、关闭 thinking
输入同一对短/中提示,本次服务分别报告约 32/916 输入 tokens
MTP 与缓存27B 使用 MTP;其他主对照不使用。27B 预热样本命中前缀缓存,不能拿它的首字时间做公平排名
磁盘卸载试验使用外接 USB workspace 盘;没有清空整机文件缓存,没有测得独立冷读带宽
未覆盖统一 OS build、长输出、多并发、长上下文、功耗、p95 延迟和长时间稳定性均未完整记录或验证

生成速度不是整段任务速度。本文客户端解码速度按 (输出 token 数 − 1) ÷ (请求总秒数 − 首字秒数) 计算。首字等待包含加载、调度、预填充等成本;不能直接把 916 除以首字时间,当作纯 prefill 性能。后端另报的 generation tokens/s 与客户端公式可能略有差异。

四模型对照:参数更多,不一定输出更慢

下表选取每个模型记录中的同一条 916-token 中提示,均输出 64 tokens。每行是一个实际记录,不是多次均值;完整短提示与其他轮次见文末 JSON。token 不是汉字,不能把 44 token/s 写成“每秒 44 个汉字”。

Rapid-MLX 中提示记录:缓存状态并不完全一致
模型草稿解码客户端生成速度首字等待已缓存输入 tokens
Qwen3.8-27B 4bitMTP9.19 token/s0.84 秒896/916
Qwen3.5-9B 8bit无10.23 token/s4.51 秒原记录未返回该字段
Qwen3.5-9B 4bit无19.54 token/s4.33 秒原记录未返回该字段
Qwen3.6-35B-A3B 4bit无44.57 token/s3.52 秒原记录未返回该字段

此前对话速览把 27B 写作约 9.1 token/s;那对应短提示的 9.10,中提示则是 9.19。这里直接标明所选样本,不把两个数混成平均值,也不把“缓存字段缺失”写成确认未命中。

Qwen 官方模型卡把 35B-A3B 定义为稀疏 MoE:总参数与每个 token 激活的参数不是一回事。这解释了为什么不能只按“9B 比 35B 小”推断速度;但激活约 3B 也不意味着全部模型权重只需 3B 的内存。本机结果更不能证明 35B 在所有任务、精度和上下文上都更快。

先纠正截图里的 GB/GiB

原对话速览中的内存单位需要更正。核对本机 Rapid-MLX health 路由及调度器后,active_memory_gb 来自字节数除以 1e9,是十进制 GB;oMLX 下文使用字节数除以 2**30,是 GiB。1 GiB = 1,073,741,824 字节。两种口径不能直接相减。

9B 独立测试的 MLX 活跃/峰值内存,不是整机内存
模型活跃内存峰值
9B 8bit9.78 GB11.12 GB
9B 4bit5.30 GB6.79 GB

27B/35B 的旧对话内存速记与速度样本没有统一的同步采样,我们不把它们补成一张“精确内存排行榜”。尤其不能用 Rapid-MLX 活跃内存与 oMLX 加载分配的差值,声称换引擎省了多少整机内存。

oMLX 专家卸载:内存下降,速度也下降

复用同一份 35B-A3B 4bit 权重,在 oMLX 0.7.3 中比较专家常驻比例。项目的专家卸载实现按需从检查点读取非驻留专家;75%/50% 是常驻预算,不是永久删除或禁用另一部分专家。对照阶段关闭了前缀缓存,但操作系统文件缓存没有清空。

预热后的 repeat 中提示:916 输入/64 输出,前缀缓存命中为 0
专家常驻比例模型加载分配客户端生成速度首字等待
100%18.48 GiB43.50 token/s1.96 秒
75%14.37 GiB17.01 token/s3.17 秒
50%10.16 GiB13.53 token/s5.94 秒

加载分配由该轮服务状态的 actual_size 字节值换算。截图中的 18.6 GiB 来自后续重载记录;这里采用卸载对照轮次的 18.48 GiB,避免把不同轮次拼成一组。

可以确认的是:这组记录中,降低常驻比例减少了加载分配,并牺牲了速度。不能确认的是“50% 在任意 SSD 上都能跑 13.5 token/s”,也不能把它等同于整机节省 8 GiB。RSS 会遗漏部分 Metal 内存;文件页、KV 缓存、临时缓冲和其他进程都可能影响实际内存压力。

我们没有测 90% 档位,也没有测更换内置/外接 SSD 后的受控差异。不要根据这三个点插值承诺某个比例一定达到 20–30 token/s,更不要为了追求驻留比例同时启动两套后端抢内存。

为什么生成很快,第一句话仍然等很久?

至少要分开四件事:模型冷加载、输入预填充、前缀缓存复用,以及首字之后的持续生成。Rapid-MLX 的 35B 记录里,恢复服务后的第一条短请求首字等待约 59.93 秒,而随后中提示约 3.52 秒;两条的输出生成都约 44.6 token/s。只看后一个指标,会漏掉真实等待。

日常 oMLX 服务后来打开了有上限的内存前缀缓存,再做同提示和追问检查。下表不是冷启动对比,也不是统计意义上的平均改善:

100% 常驻的缓存专项检查,各行是独立观测
请求输入/缓存 tokens客户端首字等待说明
首轮中提示916/02.084 秒未复用前缀
重复同一中提示916/9090.119 秒命中大量已有前缀,仍在重新生成答案
追加追问994/9090.559 秒保留可复用前缀,输出 23 tokens
另一次重复短提示32/258.944 秒明显慢样本;原因未被单独隔离

0.119 秒不是“开启缓存后每次都这样快”。重复短提示的 8.944 秒说明,字段显示缓存命中仍不能保证低延迟。日志不足以确定那一次慢在调度、运行时还是其他环节,所以保留样本,不擅自解释。重启、空闲卸载、缓存驱逐、提示前缀改变都需要重新测。

“支持 128K 上下文”的配置声明也不等于本机在 128K 下能保持上述速度:主对照只有 32/916-token 输入。给助手接很多工具时,系统提示和工具 schema 会增大输入;不能用短聊天速度预测完整 Agent 工作流。

按自己的任务选,不把速度表当能力榜

  • 内存更紧张:9B 4bit 的活跃内存记录最低,输出约 19.5 token/s;值得用自己的问答、格式和工具样本再验证,不代表它对所有任务“够用”。
  • 这台 32GB Mac 上重视连续输出:35B-A3B 4bit 全常驻是已测的较快方案,但还要为系统和其他应用留空间,观察内存压力与 swap。
  • 模型能加载,但需要腾出常驻预算:75%/50% 卸载是可测的取舍。本机速度下降明显;如果 17 或 13.5 token/s 无法接受,不要只看省内存数字。
  • 首字慢:先记录输入长度、是否冷态、缓存命中和并发,再决定是否换模型。不要把所有等待都归因于 decode。

质量检查也没有给出胜负:9B 的 4bit 与 8bit 在同组 7 项手写小检查中均为 5 项通过,包含两道算术/推理失败;当前 35B 在同两道无 thinking 检查中也出错。这些少量检查不能推导出整体能力,也不意味着三者质量相同。工具调用格式成功同样不等于 Agent 能安全、正确地完成真实操作。

我们最终在这台机器上选择了 35B+oMLX 全常驻,主要依据是这次部署的输出体验与可用内存,不是宣称某个推理引擎“全面胜出”。阅读 OpenClaw 部署边界和 Agent 安全指南,再决定如何暴露接口;本机服务默认只监听 loopback,不把无认证端口直接放到公网。

逐次数据、复现与未解决问题

下载脱敏逐次数据 JSON:包含 13 组记录、客户端时间、输入/输出长度、缓存字段、加载字节数及原记录 SHA-256。只导出白名单指标,没有私有对话、API Key、账号、本机目录或设备标识。哈希用于追溯本次提取来源,不是第三方审计证明。

下载独立流式测速脚本。它不安装模型、不切换服务、不读取助手配置;使用与原测试相同的两条非私密提示、单并发、64-token 输出和客户端计时公式。先自行启动已配置的本机 OpenAI 兼容服务,再替换下面的端口与模型 ID;不必接入任何聊天机器人。

python3 benchmark-qwen-stream.py \
  --base-url http://127.0.0.1:8080/v1 \
  --model YOUR_MODEL_ID

服务需要认证时,通过环境变量 LOCAL_LLM_API_KEY 注入,脚本不会打印它。不要把真实令牌写进文章评论、命令截图或公开仓库。每次测试记录引擎版本、量化来源、MTP、缓存开关、输入长度和机器状态;分别保留首次与重复请求,不把最好的那次改名为“平均值”。

需要继续补测的内容包括:统一 OS build、更多提示与长输出、多轮延迟分布、冷磁盘/系统页缓存的影响、同口径进程峰值、长上下文和真实工具任务正确率。本文没有重新启动、下载或改动正在使用的模型服务,也没有执行新的推理负载;它是对已有本机实测的审计整理。

一手参考与证据边界

数值来自 iPunk 自有测试文件,而不是复制这些项目的宣传成绩。本文没有商业合作或付费排名;后续修订会保留旧样本和口径变化记录。