Mac 上跑本地大模型:该选哪个版本、免审模型用哪个(附下载地址与实测速度)

Mac 上跑本地大模型:该选哪个版本、免审模型用哪个(附下载地址与实测速度)


同一个模型有 4bit/8bit/免审版,怎么选?一句话:稠密选小、MoE 选大。附下载地址与实测速度;2026-09 补测 oMLX 引擎,修正「换引擎不会变快」的旧结论。

Mac 上跑本地大模型:该选哪个版本、免审模型用哪个(附下载地址与实测速度)

本地跑大模型,同一个模型往往有好几个版本:4bit、8bit、免审版、蒸馏版……选错了要么慢一倍,要么白白牺牲质量。

先记住一句话:

稠密模型要选小体积(4bit),MoE 模型要选大体积(8bit)。很多人两边都选反了。

下面讲清楚为什么、用哪个、怎么装。


一、为什么?先看一个比喻

大模型有两种结构,差别就像两种组织方式:

稠密(Dense)MoE(混合专家)
像什么小团队:做任何一件事,所有人都得上大公司:做一件事只叫几个对口的专家
卡在哪搬数据的量派活的速度
降低精度(4bit)✅ 数据变少,快一倍❌ 快不了,只掉了质量
保持精度(8bit)慢,但质量好✅ 质量好,而且几乎不掉速度

结论:稠密用 4bit,MoE 用 8bit。

为什么 MoE 降精度快不了?因为它的瓶颈是"每次叫谁干活"这个决策开销,不是数据搬运量。数据减半,决策次数一次没少。


二、免审模型用哪个(含地址)

免审(uncensored / abliterated)是社区把模型里"拒绝回答"的倾向去掉后的版本。请自行遵守所在地法律,仅本地自用。

我们实测选出来的是这两个:

用途模型地址体积
MoE · 快 · 能看图froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bithttps://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit37.7 GB
同上,内存不够用这个同仓库 -4bithttps://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit20.4 GB
稠密 · 质量最好 · 当主力orcarouter/Qwen3.8-27B-Uncensored-MLXhttps://huggingface.co/orcarouter/Qwen3.8-27B-Uncensored-MLX16 GB

上面的 HuggingFace 页面就是官方页面,权威说明都在那里 —— 部署方式、必设的 system 提示词、推荐采样参数、思考开关、依赖版本、能力评测都有。第三节把最容易漏的几条摘出来了,但遇到问题应该回去查原页。

那个 8bit 仓库的模型卡自报(第三方数据,仅供参考):拒绝率 83/100 → 10/100,MMLU 83.72% → 83.30%,KL 散度 0.0015。

为什么不是别的?(这几条我们查过,能省你几小时)

  • 4bit 那个下载量是 8bit 的 5 倍多(10169 vs 1811)。这不是质量证据 —— 37.7 GB 装不进 24~32 GB 的机器,多数人是装不下 8bit,不是选出来的。有 256 GB 就用 8bit。
  • 社区有所谓"Claude 蒸馏版",我们逐个查过:官方只出了纯文本 8bit,带视觉的 4bit 全是下载量 100~450 的个人上传仓,没人验证过。不建议用。
  • 免审模型比普通模型更怕低精度:它是靠对权重做细微的方向性修改来去掉拒绝行为的,而 4bit 是分组压缩,容易把这种细微修改一起压掉。表现不是"均匀变差一点",而是偶发胡言乱语。所以内存够就上 8bit。

三、怎么下载、怎么启动

1. 装环境

pip install -U mlx-vlm huggingface_hub hf_transfer

2. 下载模型(自动存到本地缓存)

export HF_HUB_ENABLE_HF_TRANSFER=1
hf download froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit

3. 起服务(对外提供 OpenAI 兼容接口,能看图)

python -m mlx_vlm.server \
  --model froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit \
  --host 0.0.0.0 --port 8081 --max-tokens 32768

4. 试一下

curl http://127.0.0.1:8081/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"x","messages":[{"role":"user","content":"你好"}],"max_tokens":64}'

能返回内容就成了。之后任何支持 OpenAI 接口的客户端(Cherry Studio、ChatBox、DSH 等)都能连它。

另一个起服务的办法:装 LM Studio(或用它的免图形界面版 llmster),把模型放进它的模型目录,然后 lms load <模型> --context-length 262144 && lms server start --port 8081。它比 mlx-vlm 多两个东西:支持前缀缓存(长对话每轮不用重算,见第四节)和视觉/视频。模型目录 ~/.lmstudio/models/<作者>/<模型名>/,可以直接软链接到已有权重,不用复制。

官方模型卡里的必做项(最容易漏,但都实际影响效果)

1. system 提示词的第一行必须固定是这句

You are Qwen, created by Alibaba Cloud. You are a helpful assistant.

模型卡原话是不加这句模型会表现下降。这一行之后可以继续追加你自己的要求。

注意:这是客户端传的,服务端启动参数里没有这一项 —— 所以每个连上来的客户端都要自己带上。

2. 按官方推荐采样参数

场景temptop_ptop_k
思考模式(写代码)0.60.9520
思考模式(通用)1.00.9520
非思考模式0.70.820

repeat_penalty 保持 1.0(等于关闭)。GGUF 类引擎用 presence_penalty,MLX 用 repeat_penalty。

3. 思考开关:一个标签就能切

在任意一条消息里写 <|think_off|> 或 <|think_on|>,模板会截获这个标签、从上下文里删掉、并切换模式:

System: 你是一个编程助手。<|think_off|>
User:   巴黎天气怎么样?
        → 不推理,直接回答

System: 你是一个编程助手。<|think_on|>
User:   用 Rust 实现一个红黑树。
        → 先深度推理再作答

4. 硬件与依赖

  • 最低内存 约 40 GB(35 GB 权重 + 运行开销)
  • 需要 mlx-lm >= 0.31.2、mlx-vlm >= 0.4.4

四、第三个选择:两个都要(能看图 + 记得住对话)

前两个引擎各缺一样:mlx-vlm 能看图但不记对话历史,rapid-mlx 记得住但不能看图。

现在有第三个:LM Studio 的 mlx-engine —— 就是它桌面版跑 MLX 用的那个引擎,MIT 开源,也有免图形界面的 llmster。它两个都能给。

差距有多大?同一个 27B 模型:

对话长度不记(mlx-vlm 一直这样)记得住(rapid-mlx)
6000 字等 25.2 秒等 7.05 秒
27000 字等 83.7 秒等 4.07 秒

用 mlx-vlm 聊长对话,每说一句都要把前面从头重算一遍。 短聊天感觉不出来,一旦长就是灾难。

三个引擎横向对比:

mlx-vlmrapid-mlxmlx-engineoMLX
读图✅❌✅✅
看视频✅❌✅❌
记住对话(前缀缓存)❌✅✅✅ 还能跨重启
连续批处理❌✅✅✅

怎么选:

你的情况选
既要看图、又要长对话mlx-engine 或 oMLX
只跑文本oMLX
只看图、聊得很短mlx-vlm

两个反直觉但重要的点:

1. "能不能看图"是引擎的问题,不是模型的问题。 同一个模型(Qwen3.8-27B,混合注意力架构),rapid-mlx 会明确拒绝图片,报 vision_hybrid_runtime_unsupported;而 mlx-engine 和 mlx-vlm 都能正常识别。所以遇到"这个模型不支持图片"时,先换引擎试试,别急着换模型。

2. "换引擎不会让稠密模型变快" —— 我们一开始这么写,后来被打脸了。

同一个 27B 模型,三家引擎不开任何加速时几乎一样快:mlx-engine 37、rapid-mlx 37、oMLX 36.8 t/s。所以我们当时写下上面那句结论。

但后来给 oMLX 挂上投机解码,同一个模型跑到 53~57 t/s;而 rapid-mlx 挂同样的投机解码只有 44.5 t/s —— 同权重、同一个加速包、同一台机器,差 20%。

差别不在"引擎裸速度",而在加速功能实现得好不好。所以准确的结论是:

引擎的裸速度决定不了什么(都一样);但"加速功能"的实现质量,在稠密模型上能差出 20%。

MoE 模型则两家差不多(见下),因为 MoE 瓶颈在调度、不在字节数。

3. 但并发能力差得很远。 如果你有多个客户端同时用,这个比单请求速度更重要。开 4 个并发请求,聚合吞吐:

配置单请求4 并发合计说明
mlx-engine(35B-A3B)72.5203(2.8×)默认并行度 4
oMLX 开着 MTP(27B)5778(1.4×)MTP 和批处理能共存
rapid-mlx 关了 MTP(27B)38.989.9(2.3×)真批处理
rapid-mlx 开着 MTP(27B)44.542.3(1.0×)只是排队

最后一行是最容易踩的:在 rapid-mlx 上开了 MTP 就没批处理,加并发不会提高总吞吐,只会让每个人变慢(8 并发时最慢的那个人只有 5 t/s)。

但这是 rapid-mlx 这家引擎的毛病,不是 MTP 本身的限制 —— 换到 oMLX,MTP 和批处理可以共存(单请求 57 + 4 并发 78),不用二选一。细节见第五节。


五、三个"看着很美、实际别开"的加速功能

1. DFlash 加速 —— 短问题快,长文本反而变慢

速度变化
短问题+13%
6000 字上下文−14%

2. KV 量化(号称省显存提速)—— 短上下文猛,长上下文直接崩

速度变化
6000 字+26%
27000 字−64%(从 74 掉到 26.4)

3. MTP 加速 —— 有两个反噬条件

MTP(小模型猜、大模型验)本身是好东西,稠密模型上能 +24%。但它有两个隐藏前提:

前提一:drafter 必须和当前权重配套。 我们换成同架构的免审版(8bit → 8bit,参数量一模一样)后忘了这点,速度从 70 掉到 39 t/s —— drafter 是在原版权重上训练的,换权重后命中率崩了,投机解码从加速变成净拖累。摘掉后立刻回到 80 t/s。

前提二:有些引擎会把并发批处理关掉。 这个更隐蔽,但要看引擎。

rapid-mlx 上有这个问题:同一个 27B 模型实测:

配置单请求4 个并发合计
开 MTP44.5 t/s42.3 t/s(等于单请求,加并发只是排队)
关 MTP38.9 t/s89.9 t/s

开了 MTP 之后,引擎调度器日志里的 running 永远是 1 —— 即使 7 个请求在排队也只跑一个。而且光加并发参数没用,必须真的关掉 MTP 才会启用批处理。

oMLX 上没有这个问题:同样的模型同样挂 MTP,单请求 57 t/s、4 并发 78 t/s —— 加速和批处理同时拿到。

所以结论是:先看你在用哪个引擎。 rapid-mlx 上必须二选一(一个人用开 MTP / 多人关掉);oMLX 上不用选。

共通教训:加速功能不能只看"开没开",要拿你实际的模型、上下文长度、以及"几个人同时用"去测。


六、给技术人员的部分:实测数据与踩坑

(下面这段偏技术,普通读者可以跳到最后一节)

测试环境

M3 Ultra / 256 GB / 819 GB/s / macOS 26.6.2 / mlx-vlm 0.6.17 / rapid-mlx 0.14.3 / LM Studio mlx-engine(llmster 0.0.25-1)/ oMLX 0.6.4(2026-09-22 补测)

量化与速度对照

模型量化权重decode
稠密 27B4bit16.05 GB54.3 t/s(实测)
稠密 27B8bit31.19 GB约 28 t/s(按带宽推算)
MoE 35B-A3B8bit37 GB85.8 t/s
MoE 35B-A3B4bit20.4 GB与 8bit 基本无差

MoE 给 8bit 版挂 MTP 投机解码只拿到 +5%(82.2 → 85.8)。投机解码本质是让一次权重读取摊到多个 token —— 有效即说明瓶颈在调度而非字节数。

坑 1:rapid-mlx 不配 tool-call parser,工具调用变裸 XML

客户端收到 <tool_call><function=bash>... 这样的文本。不是模型坏了,是服务端没解析:

--enable-auto-tool-choice --tool-call-parser qwen3_coder_xml

坑 2:--speculative-config 的 JSON 必须带 model 字段

# ❌ 拒绝启动
--speculative-config '{"method":"mtp","num_speculative_tokens":3}'
# ✅
--speculative-config '{"method":"mtp","model":"<MTP sidecar 路径>","num_speculative_tokens":3}'

坑 3:上下文窗口不能硬拉

上限由模型 max_position_embeddings 决定,硬拉参数没用。这个 35B-A3B 是 262K 原生,官方模型卡写明开 YaRN 后可到 1M+(RoPE theta 10M、partial_rotary_factor 0.25)—— 所以想要 1M 是在引擎侧开 YaRN,不是换模型。但要注意:本案例用过的 mlx-vlm 0.6.17 与 rapid-mlx 0.14.3 的命令行参数里都没看到 YaRN/rope 缩放开关,LM Studio 的 lms load 参数里也没有,用之前先确认你的引擎支持。

坑 4:HF 匿名下载慢/断连的排查

netstat 统计不可靠,直接采样目录增长:

D=~/.cache/hf/<repo>
S1=$(du -sk "$D"|cut -f1); sleep 10; S2=$(du -sk "$D"|cut -f1)
echo "$(( (S2-S1)/10/1024 )) MB/s"

日志里 peer closed connection ... Trying to resume download... 是正常抖动,会自动续传。装了 hf_transfer 速度没变 → 瓶颈是链路带宽,别折腾工具。

坑 5:改了 plist 用 kickstart 重载,模型根本不会换

launchctl kickstart -k 是用 launchd 缓存里的任务定义重启,不会重读 plist 文件。所以改完 --model 再 kickstart,进程确实起来了、PID 也变了,但跑的还是旧模型 —— 静默失败,最难查。

必须 bootout + bootstrap 强制重新加载:

PLIST=~/Library/LaunchAgents/com.xxx.plist
LABEL=com.xxx
cp "$PLIST" "$PLIST.bak"                    # 先备份
/usr/libexec/PlistBuddy -c "Set :ProgramArguments:4 <新模型ID>" "$PLIST"

launchctl bootout "gui/$(id -u)/$LABEL" 2>/dev/null || true
launchctl bootstrap "gui/$(id -u)" "$PLIST"

而且不能拿"命令没报错"当成功 —— 要校验进程命令行里是不是新模型:

ps -o command= -p "$(launchctl list | awk '$3=="com.xxx"{print $1}')" \
  | grep -q "<新模型ID>" && echo OK || echo "还是旧模型"

坑 6:mlx_vlm 会按请求里的 model 名热切换模型,传错名字会静默拿到另一个模型

/v1/models 列出的是缓存里所有模型,不是当前加载的那一个。而且服务端会按请求 body 里的 model 字段现场切换:你写哪个名字,它就把那个加载进来。日志能看到 Loading model: ...,一次切换约 3 秒,进程内存始终只有单个模型大小。

两个后果:

  1. "新模型出现在列表里"不能当作切换成功的判据 —— 权重一下完它就会列出来。
  2. 客户端传的 model 名不对,你会静默地拿到另一个模型的结果,而且没有任何报错。

我们真踩了这个坑:脚本用 /v1/models 的第 0 项当模型名,结果测了半天一直是旧模型,一整轮数据全废。所以务必显式传你要的模型全名,并用日志确认:

curl http://127.0.0.1:8081/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"<你的模型全名>","messages":[{"role":"user","content":"hi"}],"max_tokens":8}'

grep "Loading model" ~/logs/<你的服务>.log | tail -3

坑 7:并发压测里的"连接被服务端关闭",多半是你客户端的问题

用 Python 的 urllib 做并发压测时,会偶发 RemoteDisconnected: Remote end closed connection without response。这个现象我们在两个不同引擎上都遇到过,一开始怀疑是"并发超过上限被拒"或"服务端崩了"。

实际排查:服务端三项全正常(进程存活、/v1/models 返回 200、日志无错误),内存也没涨。真凶是客户端的 HTTP keep-alive 连接复用。

请求头加上 Connection: close 之后,同样的并发测试跑 12 轮(2 并发和 4 并发各 3 轮 × 2 个端点)零丢包。

排查顺序:先怀疑自己。 客户端报"连接被关闭"时,先确认服务端三项(进程存活 / 健康检查 200 / 日志无错误)—— 本地环回网络几乎不可能丢包。


七、速查表

你的情况选择
稠密模型,内存紧张4bit,明确换速度
稠密模型,内存充足4bit 仍是甜点
MoE 模型8bit
免审 / abliterated尽量 8bit
要读图mlx-vlm(但要接受"不记对话")或 mlx-engine
长对话 / AgentoMLX 或 mlx-engine
既要读图又要长对话mlx-engine(唯一同时支持两者)
想开投机解码(MTP / DFlash)换过模型权重就必须重测,否则可能是负收益
想开 KV 量化先跑到真实最长上下文再决定
一个人用开 MTP,单请求最快(oMLX 上无副作用)
多人 / 多客户端同时用oMLX 直接开 MTP 即可;rapid-mlx 上才需要关掉 MTP 换批处理
想确认批处理有没有生效看引擎日志里的 running= —— 恒为 1 就是没批处理(rapid-mlx 开 MTP 时的典型症状)

选型的核心不是"哪个量化好",而是先问清楚:你的模型卡在搬数据上,还是卡在派活上。

15300举报0子龙•7天前
点击获取 ^_^

暂无评论