测了什么,又没有测什么?
这是一组真实部署过程中的工程记录,目的是为本地助手选择兜底模型,不是先设计好的标准评测。机器是同一台基础款 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 个汉字”。
| 模型 | 草稿解码 | 客户端生成速度 | 首字等待 | 已缓存输入 tokens |
|---|---|---|---|---|
| Qwen3.8-27B 4bit | MTP | 9.19 token/s | 0.84 秒 | 896/916 |
| Qwen3.5-9B 8bit | 无 | 10.23 token/s | 4.51 秒 | 原记录未返回该字段 |
| Qwen3.5-9B 4bit | 无 | 19.54 token/s | 4.33 秒 | 原记录未返回该字段 |
| Qwen3.6-35B-A3B 4bit | 无 | 44.57 token/s | 3.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 8bit | 9.78 GB | 11.12 GB |
| 9B 4bit | 5.30 GB | 6.79 GB |
27B/35B 的旧对话内存速记与速度样本没有统一的同步采样,我们不把它们补成一张“精确内存排行榜”。尤其不能用 Rapid-MLX 活跃内存与 oMLX 加载分配的差值,声称换引擎省了多少整机内存。
oMLX 专家卸载:内存下降,速度也下降
复用同一份 35B-A3B 4bit 权重,在 oMLX 0.7.3 中比较专家常驻比例。项目的专家卸载实现按需从检查点读取非驻留专家;75%/50% 是常驻预算,不是永久删除或禁用另一部分专家。对照阶段关闭了前缀缓存,但操作系统文件缓存没有清空。
| 专家常驻比例 | 模型加载分配 | 客户端生成速度 | 首字等待 |
|---|---|---|---|
| 100% | 18.48 GiB | 43.50 token/s | 1.96 秒 |
| 75% | 14.37 GiB | 17.01 token/s | 3.17 秒 |
| 50% | 10.16 GiB | 13.53 token/s | 5.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 服务后来打开了有上限的内存前缀缓存,再做同提示和追问检查。下表不是冷启动对比,也不是统计意义上的平均改善:
| 请求 | 输入/缓存 tokens | 客户端首字等待 | 说明 |
|---|---|---|---|
| 首轮中提示 | 916/0 | 2.084 秒 | 未复用前缀 |
| 重复同一中提示 | 916/909 | 0.119 秒 | 命中大量已有前缀,仍在重新生成答案 |
| 追加追问 | 994/909 | 0.559 秒 | 保留可复用前缀,输出 23 tokens |
| 另一次重复短提示 | 32/25 | 8.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、更多提示与长输出、多轮延迟分布、冷磁盘/系统页缓存的影响、同口径进程峰值、长上下文和真实工具任务正确率。本文没有重新启动、下载或改动正在使用的模型服务,也没有执行新的推理负载;它是对已有本机实测的审计整理。
一手参考与证据边界
- Qwen 官方 35B-A3B 模型卡:解释模型结构,不为本站速度背书。
- Rapid-MLX 官方模型别名目录:核对仓库名称;目录当前版本可能晚于本次 0.16.10 环境。
- oMLX 0.7.3 发布页与专家卸载实现:核对测试时版本与功能机制。
数值来自 iPunk 自有测试文件,而不是复制这些项目的宣传成绩。本文没有商业合作或付费排名;后续修订会保留旧样本和口径变化记录。