[控场AI]
· 23 分钟阅读· 11,516 字

M5 Max 128GB 部署 oMLX 本地推理服务实战指南

M5 Max 128GB 部署 oMLX 本地推理服务实战指南

oMLX 0.6.4 在 M5 Max 128GB 上的多模型共存配置与调优实战指南

本文整合多个来源的实测数据,给出基于 oMLX 0.6.4 在 128 GB M5 Max 上运行本地 LLM 推理服务的完整调优方案。内容覆盖服务器参数配置(内存上限、热/冷缓存比例、并发数)、多模型共存选型(Qwen3.6 35B-A3B 为主力,搭配 14B 助手、VL-32B、嵌入与重排器,舒适占用约 65-70 GB)、Claude Code 通过 Anthropic 兼容 API 的接入方法、跨机 SSH 端口转发技巧,以及 0.6.4 新增的推测解码(Lightning MTP / VLM MTP / DFlash)、TurboQuant KV 压缩等高级调优。实测显示从 0.3.8 到 0.6.4,32k 长上下文解码从 15.2 跃升至 77.9 tok/s,写代码场景提速 1.19x 到 1.88x。

苹果在 2023 年底为 Apple Silicon 推出 MLX 框架后,围绕它的生态一直在快速膨胀。oMLX 就是其中迭代最激进的产品之一:一个建立在 MLX 之上的 LLM 推理服务,补上了连续批处理(continuous batching)、内存 + SSD 两级 KV 缓存,以及兼容 OpenAI 与 Anthropic 的 API。

对一台 128 GB 统一内存的 M5 Max 来说,这套组合的意义在于:你可以同时挂载三到四个大模型,用 TurboQuant 3.5-bit 压缩 KV 缓存,把聊天、Agent、IDE 三路请求并行喂给同一台机器。本文整合了多个来源的实测数据,给出经过验证的配置方案。

oMLX 安装与调优

oMLX 是什么,为什么值得折腾

oMLX 的核心价值不是「又一个本地推理工具」,而是它把苹果生态里长期缺失的服务化能力补齐了。MLX 框架本身只解决在 Apple Silicon 上跑模型的问题,不解决多模型共存、请求排队、KV 缓存跨内存层级搬运这些工程问题。oMLX 补上的是这一层。

当前版本为 0.6.4(Apache 2.0 协议),安装有两条路:从 GitHub Releases 下载 .dmg 拖进 Applications,服务器会以后台进程启动并在菜单栏驻留图标;或者走 Homebrew,brew tap jundot/omlx 之后 brew install jundot/omlx/omlx,再用 omlx start 和 omlx serve --model-dir ~/models 拉起服务。

首次打开 http://localhost:8000/admin 会要求填入 API Key。默认情况下这个字段是空的,只要服务只监听 127.0.0.1 就没有问题。一旦你打算暴露到局域网或分享给其他人,必须去 Settings → Auth & Info 设置一串足够长的随机字符串。这个区块支持同时配置多个 key。

连续批处理(continuous batching) 是现代 LLM 推理服务器区别于朴素逐请求推理的核心机制。传统批处理需要等一批请求全部生成完毕才能接纳下一批,导致短请求被长请求拖住、GPU/ANE 大量空转。连续批处理在每一步解码后立即检查哪些序列已结束,把新到达的请求动态插入空出的槽位,让每个解码步的批次始终填满。它通常与前缀缓存复用、分页 KV 管理(如 PagedAttention)配合使用。oMLX 支持它,意味着 Claude Code、聊天会话、Agent 循环三路并发时,吞吐不是简单地线性排队,而是实测中 8x 并发能带来 3.28 倍加速——远高于单请求时的 72.4 tok/s 基线。

128 GB 机器的服务器参数怎么调

Settings → Global Settings 是全部服务器配置的入口。对 128 GB 机器来说,真正影响体验的决策只有十几项。

网络层保持 Host 为 Localhost only (127.0.0.1),Port 默认 8000。

内存管理是重点。Memory Limit (Total) 和 Memory Limit (Models Only) 都设为 Auto,oMLX 会扣掉 macOS 自己保留的部分,在 128 GB 上最终留给推理的大约是 110-114 GB。Hot Cache Limit 设为 10%,这是 RAM 层的中转 KV 缓存;在启用 TurboQuant 的模型上,社区实际跑下来 128 GB 机器普遍落在 10%。Cold Cache Limit (SSD Cache) 同样 10%,大约 80 GB SSD 用于冷 token,不至于把盘写满。

并发与保活方面,Max Concurrent Requests 设 16,对「一个 Agent + 一个聊天会话 + 一个 IDE 同时在敲」的单用户场景足够宽裕,小团队共享可以提到 32。Idle Timeout 设为 None,模型常驻热态,首个 token 能在远低于一秒的时间内返回,而不是几秒。

生成默认值上,Max Context Window 全局设 256000。Qwen3.6 家族在长上下文下表现稳定,配合 TurboQuant 之后实际内存也撑得住。个别模型可以在 Model Settings 里单独压低。Max Tokens 设 64000,Temperature 通用场景 1.0,代码模型 0.2-0.5。

最后一项是 Model Settings → Experimental Features → TurboQuant KV Cache,在大稠密模型上开到 3.5-bit。vLLM 在独立研究中验证的结论是:3.5-bit 在质量上与全精度持平,KV 缓存内存占用约为四分之一。在 M5 Max 上,这决定了 128k 上下文是「内存爆掉」还是「能跑,而且还能再塞下别的模型」。需要注意的是 0.6.4 上它不能与 VLM MTP 叠加,而且实测并不会带来生成加速。

KV 缓存(Key/Value Cache) 是自回归 Transformer 推理时保存的中间状态:每生成一个 token,模型需要回看此前所有 token 的注意力 Key 和 Value,如果不缓存就要重复计算,代价是 O(n²)。KV 缓存的显存/内存占用随上下文长度和层数线性增长,在长上下文场景下往往超过模型权重本身。两级缓存(RAM 热层 + SSD 冷层)的意义在于:热层保留最近高频访问的序列前缀,冷层持久化被换出的 token,用延迟换容量。这正是「10% Hot Cache + 10% SSD Cold Cache」配置背后的工程逻辑——110 GB 内存里,留给权重之外的余量被精细切成这两块。

多模型共存的选型清单

128 GB 的空间足够同时挂载一个大主模型、一个快速助手、一个视觉模型、一个嵌入模型和一个重排器。全部从 Models → Downloader 粘贴 Hugging Face 仓库地址下载。

据实测运行 Claude Code on oMLX 的用户(Diego R. Baquero 的 gist 是这组配置的来源)反馈,Unsloth 的 Qwen 3.6 35B-A3B 系列 MoE(每 token 约 3B 激活参数)是当前最稳的选择。8-bit 版本在 128 GB 上毫无压力:

  • 主力(聊天 + 代码 + 推理):unsloth/Qwen3.6-35B-A3B-MLX-8bit,约 37.7 GB,MoE 35B / 3B 激活的全能选手,和其它模型共存也不会挤压
  • 更压缩的备选:unsloth/Qwen3.6-35B-A3B-UD-MLX-4bit,约 21.6 GB,代价是掉一档质量,但能同时挂两个主力
  • 稠密推理:Mistral-Large-2-123B-Instruct-mlx-4bit(约 70 GB)或 Llama-3.3-70B-Instruct-mlx-4bit(约 40 GB),在需要单次深度推理、小激活 MoE 不够用时顶上
  • 快速助手:Qwen3-14B-Instruct-mlx-4bit,约 8 GB,用于 Agent 里的廉价任务、解析和摘要
  • 视觉:Qwen2.5-VL-32B-Instruct-mlx-4bit,约 18 GB,覆盖 OCR、图像描述和多模态推理
  • 嵌入:BGE-M3-mlx,约 1.2 GB,dense + sparse + multi-vector 三合一
  • 重排:ModernBERT-base-mlx,约 150 MB,用于闭环一个像样的 RAG 管道

以 8-bit Qwen3.6 35B-A3B 为主力,加上 14B 助手、VL-32B、嵌入和重排,舒适并发占用约 65-70 GB。再叠一个 Mistral Large 2 123B 做稠密推理,标称会到约 135 GB。LRU 策略会把空闲模型挪到 SSD,所以只要不是所有模型同时被高频调用,这种共存方式是可行的。建议从 Model Manager 把主力模型 pin 住,避免被换出。

把 Claude Code 接到本地端点

oMLX 在 http://127.0.0.1:8000 暴露了 Anthropic 兼容 API,当前版本路由在 /v1 下:POST /v1/messages 和 POST /v1/messages/count_tokens。Claude Code 认 ANTHROPIC_BASE_URL,所以把 CLI 指向本机只是导出环境变量的事。

0.5.0 之后有了一条捷径,一个命令搞定全部:omlx launch claude。它会设置 ANTHROPIC_BASE_URL 指向你的服务器,把配置好的 key 写进 ANTHROPIC_AUTH_TOKEN(没设 key 时填 omlx),清空 ANTHROPIC_API_KEY 强制走 base URL,把 API_TIMEOUT_MS 提到 3,000,000,并关掉非必要流量。它还会按引擎实际能力设置 CLAUDE_CODE_MAX_CONTEXT_TOKENS 和 CLAUDE_CODE_AUTO_COMPACT_WINDOW,并强制一个 48,000 token 的最小窗口,模型达不到就不启动。Codex、OpenCode、OpenClaw广告、Hermes 和 Pi 都有对应的子命令。

手动做法依然有效,适合需要精细控制每个变量的场景。先在 ~/.claude/settings.json 里关掉署名头:{"env": {"CLAUDE_CODE_ATTRIBUTION_HEADER": "0"}}。然后启动脚本里导出这一组变量:ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、三个 ANTHROPIC_DEFAULT_OPUS_MODEL / SONNET / HAIKU_MODEL,以及 ANTHROPIC_DEFAULT_MODEL、API_TIMEOUT_MS=600000、CLAUDE_CODE_USE_BEDROCK=0、DISABLE_NONESSENTIAL_TRAFFIC=1,最后用 claude --bare 启动。

--bare 会跳过 hooks、LSP、插件同步和自动记忆,把 Claude Code 的系统提示词压到约 1,795 token(满载时是数千 token)。对着本地模型离线工作时这是合理默认值:系统提示词里的每个 token 都是你 Mac 白烧的带宽。切回 api.anthropic.com 时再去掉这个 flag。

一个必须说清楚的限制:Claude Code 是针对 Claude 自己的工具调用格式和响应模式调过的。把一个非 Claude 模型放在 ANTHROPIC_BASE_URL 后面,自动补全和推理能用,但 tool-call 可靠性和 Agent 循环会明显下降。它适合离线工作、敏感数据不出本机、或在 api.anthropic.com 限流时兜底,不是 Claude Opus 4.7 的一比一替代品。

跨机使用:从 MacBook 连 Mac Studio

如果 oMLX 跑在 Mac Studio 上,你想从 MacBook 用 Claude Code,SSH 端口转发就是那座桥:ssh -L 8000:localhost:8000 user@mac-studio。连上之后,笔记本上的 127.0.0.1:8000 就指向 Studio 的 oMLX。

把导出变量的部分存成 claude-local.sh,chmod +x 之后在 SSH 会话里运行即可。默认 API key 是空字符串,如果你在 Settings → Auth & Info 里设过,替换成它就行。脚本里可以加 --dangerously-skip-permissions 跳过在自动化管道里没有意义的交互式权限确认。

实测基准:老版本与新版本的差距

先看一组参考数字,M5 Max 40 核 / 128 GB,oMLX 0.3.8,2026 年 5 月测得。Qwen 3.6 35B-A3B 8-bit 短上下文解码 65-80 tok/s,是这台机器上最能改变日常体验的模型。pp1024/tg128 首 token 577 ms、解码 72.4 tok/s、峰值内存 38.5 GB;pp4096/tg128 解码 83.1 tok/s;到 pp32768/tg128 掉到 15.2 tok/s。连续批处理下 1x 基线 72.4 tok/s,8x 并发能到 237.7 tok/s,加速 3.28 倍。

Llama 3.3 70B 4-bit 解码 14-18 tok/s。Mistral Large 2 123B 4-bit 配合 TurboQuant 3.5-bit KV 缓存,解码 8-11 tok/s,真正关键的是 128k 上下文下峰值内存约 74 GB —— FP16 KV 会直接冲破 128 GB。dasroot.net 对 104B 稠密模型的长上下文实验记录了相同的峰值。

vLLM 在 2026 年 5 月测出的 TurboQuant KV 压比是 4.41x。这个数字决定了你是「有 128k 上下文但装不下」还是「装得下还能再挂两个模型」。4-bit 和 3.5-bit 下质量接近全精度,3-bit 开始在代码和长文本推理上能感觉出来。

0.6.4 的高级调优:推测解码

0.6.4 上最大的速度杠杆是推测解码,而且选哪种方法取决于模型。通过 API 在 temperature 0.6 下实测:Qwen3.8-27B oQ4e 开 Lightning MTP 从 21.1 提到 39.7 tok/s,Qwen3.6-35B-A3B 8-bit 开 VLM MTP 从 79.7 提到 117.5 tok/s。整体上写代码场景提速 1.19x 到 1.88x,15,000 token 上下文下是 1.07x 到 1.47x。

oMLX 0.6.4 提供三种方法,每个模型只能选一种:

Lightning MTP 使用权重里自带的 multi-token prediction 头,只有转换时保留了 mtp.* 张量才能用。VLM MTP 使用小于 2 GB 的外部 drafter,只在该模型没有任何其它请求在跑时生效。DFlash 使用 z-lab 的 block-diffusion drafter,一次最多提 16 个 token,串行服务请求并维护自己的前缀缓存。三种方法里大模型都会验证每个被提议的 token,所以输出来自大模型而非 drafter。

各模型的组合实测结果:Qwen3.6-35B-A3B 8-bit 配 mlx-community/Qwen3.6-35B-A3B-MTP-bf16(1.7 GB)走 VLM MTP,写代码 79.7 → 117.5 tok/s,15k 上下文 84.0 → 90.7 tok/s;Qwen3.8-27B oQ4e 配 Jundot/Qwen3.8-27B-oQ4e-mtp(17.0 GB)走 Lightning MTP,21.1 → 39.7 和 21.4 → 27.2;Gemma 4 12B 8-bit 配 mlx-community/gemma-4-12B-it-assistant-bf16(0.88 GB)走 VLM MTP,27.4 → 50.5 和 26.6 → 39.2。

如果 Qwen 模型的设置页出现 Config declares MTP layers but the weight files contain neither mtp. tensors nor native nextn layers* 警告,说明转换时把 MTP 头剥掉了。mlx-lm 的默认转换器就是这么干的,mlx-community 的 Qwen3.6-35B-A3B 和 lmstudio-community 的 Qwen3.8-27B 都中招。两条出路:下载保留 MTP 头的构建(比如 oMLX 作者发布的 oQ4e-mtp 系列),或者改用外部 drafter 的 VLM MTP。

DFlash 只在短提示下划算。内置基准里 Qwen3.6-35B-A3B 8-bit 在 1k 提示下从 92 提到 112 tok/s,但 32k 提示下从 78 掉到 17 tok/s。Qwen3.8-27B 4-bit 在 32k 下从 23.5 掉到 6.3。如果你用 Claude Code(每轮都发几万 token 上下文),关掉它。

Qwen ANE Prompt Processing(把部分 prefill 分给 Apple 神经引擎)实测收益不稳定。在 Qwen3.8-27B oQ4e 上,8,193 token 提示的 prefill 从 452 提到 510 tok/s,涨 12.8%。但配合 Lightning MTP 后这个收益消失:4k 提示 prefill 505 对 499,32k 时 422 对 471(反而更慢)。代价是加载模型从 16.0 GB 涨到 20.7 GB,加载时间从 2 秒变 20 秒。这台机器上建议关掉。

TurboQuant KV 并不会加速生成。在 Qwen3.8-27B oQ4e 上开 Lightning MTP 再加 4-bit TurboQuant,32k 提示峰值内存不变(24.4 GiB),解码反而从 35.4 掉到 30.3 tok/s。这类混合模型里只有全注意力层保留 KV 缓存,本来就没多少可压。它省内存,不加速。

推测解码(speculative decoding) 的原理是:用一个廉价的小型 drafter 模型预先「猜」出接下来若干 token,再让大模型一次性并行验证这批候选。被接受的 token 就等于大模型直接生成的,被拒绝的位置从该处回退重来。因为大模型验证 k 个 token 的耗时远低于串行生成 k 个,只要接受率足够高就能提速。MTP(Multi-Token Prediction)头是训练阶段内建在权重里的预测模块,drafter 就是模型自己的一部分;而 DFlash 这类外部 drafter 则是独立小模型,需要额外加载。关键约束是所有候选 token 最终都经过大模型验证,所以输出质量不受 drafter 影响,只会影响速度。

0.6.4 上的实测数字

配合上面的配置,这台 M5 Max 在写代码场景每秒生成的 token 数是未调优时的 1.19 到 1.88 倍。带 15,000 token 上下文时是 1.07 到 1.47 倍。完全不开加速,Qwen3.6-35B-A3B 8-bit 在 32k 提示下能保持 77.9 tok/s,而 0.3.8 上只有 15.2 tok/s。

这个差距大到不可能是测量口径造成的。同一台机器、同一个模型系列,仅版本从 0.3.8 升到 0.6.4,32k 长上下文解码从 15.2 提到 77.9 tok/s,1k 提示从 72.4 提到 92.1,首个 token 从 577 ms 降到 298 ms。

测试方法分两套。通过 API 跑流式请求到 /v1/chat/completions,temperature 0.6、关闭 reasoning。短测试里每个配置回答三个编码任务(Python、TypeScript、Go)各两次,768 token 答案;长测试里回答两个关于约 15,100 token 源码的问题,512 token 答案。计时在客户端做。内置基准从 POST /admin/api/bench/start 启动,每个配置重复三次取中位数,提示长度 1,025 / 4,097 / 16,385 / 32,769,生成 256 token,语料用 code_python,始终贪心采样。

每个请求都带唯一前缀,所以没有一个是靠前缀缓存取巧的。测试连续跑了大约三小时,期间其它应用照常开着。内置基准记录了 macOS 热压力等级,242 次测量里有 194 次处于五级中的第三级 Heavy。只有第一批 gpt-oss 是冷机跑的,它的 16k prefill 从冷机 3,140 tok/s 掉到热机 1,755 tok/s。所以绝对数字要当成「热 Mac」的数字读,调优前后的相对增益比绝对值更可靠。

从 0.3.8 到 0.6.4 都变了什么

0.5.0(2026 年 7 月 10 日)加入了 Qwen3.6-27B、Qwen3.6-35B-A3B、DeepSeek广告-V4-Flash 和 GLM-5.2 的原生 depth-k 推测解码。项目方在 M3 Ultra 上测得 Qwen3.6-35B-A3B 从 89.6 提到 140.4 tok/s(1.57x),Qwen3.6-27B 从 35.0 提到 55.1 tok/s。

同一版本还加入了 DeepSeek V4、Qwen3.5/3.6 和 GLM-5.2 的自定义计算内核,prefill 提升在 M3 Ultra 上测得 45%(DeepSeek-V4-Flash 64k 上下文 313.3 → 455.8 tok/s)、33%(Qwen3.6-27B)和 99%(GLM-5.2 32k)。对 M5 系列而言,重要的是调度是 NAX-aware 的,专门为了避免 M5 上的回退,所以值得实测确认而不是想当然。

oMLX 也不再只依赖你下载的权重:它带来了自己的量化方案。0.5.0 加入 oQe,一套带激活重要性校准和 MoE 专家覆盖追踪的流程。按项目方的测量,oQ4e 在同盘体积档位下比 oQ4 平均准确率更高 —— Qwen3.6-35B-A3B 上是 83.88% 对 82.83%,Qwen3.5-9B 上是 73.09% 对 70.01%。

0.6.3 分支优化了神经引擎上的 prefill 路径。bank 编译内存在这块从 35.8 GB 降到 4.7 GB,可选的持久编译缓存把新进程启动时间砍掉 53% 到 66%。0.6.4 继续推进,把 Qwen3.8-Flash-Next 的提示处理提升 33.5%,32k 下总请求时间减少 24.2%(同样是 M3 Ultra 数据)。

API 端新增了 /v1/rerank、/v1/responses 和 /v1/mcp/tools,同时挂一个嵌入模型和一个重排器,整条检索管道就能跑在同一台服务器上。鉴权也从「一堆等价 key」变成三种权限:主 key 能调 API 和进面板;子 key 只能调 API,进不了面板也改不了设置;面板会话 token 存在签名 cookie 里。要把访问权分给多个应用时,发子 key。

还有 Profiles(围绕单个模型保存命名设置包,以 model:profile 形式暴露,不额外占内存)、Aliases(在 API 层面重命名模型),以及实验性的分布式推理(按各机内存把模型层分到多台 Mac 上,走 SSH,会考虑链路是 Thunderbolt 还是 10GbE)。

几个常见的坑

配置文件里的 hot_cache_max_size 默认是 "0",这实际上是关掉 RAM 热缓存。内存上限现在的键名是 memory_guard_tier(四档 safe / balanced / aggressive / custom),自定义值放 memory_guard_custom_ceiling_gb,默认上限是系统内存减 8 GB。

Kernel memory limit 需要手动调。macOS 默认限制 GPU 可锁定的内存,低于 oMLX 可用量时面板会亮红警告。跑 sudo sysctl iogpu.wired_limit_mb=124518(128 GB 机器上是内存减 5%),重启 oMLX 时应用。这个值在 Mac 重启后会丢。

点「Save Settings」会卸载所有已加载的模型,即使你根本没碰缓存相关的字段,因为面板会把每个字段都重发一遍。

Prefill Priority 设成 Speed。内存紧张时 Max Context 会把 prefill 压到每步 32 token 以塞下提示,Speed 保持全速并拒绝塞不下的。Hide Helper Models 打开,避免 drafter 出现在 /v1/models 里被客户端误选。Max Concurrent Requests 保持在 8 到 16 之间,不要降到 1 —— 调度器在挂起的缓存写入数达到这个上限时不会接纳新请求。

Burst Decode 保持 Balanced。Aggressive 会在发送前把 token 攒最多 200 ms(对 100 ms),客户端看到首个 token 的时间会更晚。

iogpu.wired_limit_mb 是 macOS 用来限制 GPU/ANE 可锁定物理内存上限的内核参数。默认值保守,是为了防止某个进程独占内存导致系统不稳,但对本地大模型推理这类确实需要大量常驻显存的场景反而是瓶颈。调高它就等于告诉 macOS「我愿意承担这个风险」。sysctl 设置是运行时参数,不写进持久配置,所以每次重启 Mac 都要重新执行,或封装进启动脚本。128 GB 机器上设为内存减 5%(约 124518 MB)是社区经验值:既给系统留足余量,又让 oMLX 有足够空间把所有权重和 KV 缓存锁定在 resident 内存中,避免被换出到 SSD 拖慢解码。

参考来源

  • Diego R. Baquero 的 gist「Running Claude Code with a local LLM」:本文设置的基础配方来源(TurboQuant 3.5-bit、64k 上下文、关闭署名头、Qwen 3.6 35B-A3B 系列)
  • vLLM 博客的 TurboQuant 综合分析:独立验证 3.5-bit 与全精度质量持平的结论
  • omlx.ai/benchmarks:公开排行榜,含 M5 Max 的真实提交
  • dasroot.net 的 M5 Max 长上下文与内存碎片化实验:另一个关于 M5 Max + TurboQuant 长上下文的详细实验

原文首发于 jacar.es,基准数字随每个 oMLX 版本更新。

#oMLX#M5 Max 本地推理#Apple Silicon LLM#MLX 框架#TurboQuant#推测解码#Claude Code 本地模型#本地大模型部署
分享:

相关推荐