oMLX:为 Apple Silicon 而生的本地 LLM 推理服务器,分层 KV 缓存把上下文复用推到 85%

在 Mac 上跑本地大模型的人大多经历过同一个瓶颈:模型加载得再快,长对话一来一回,上下文一遍遍重新计算,GPU 算力都花在了重复劳动上。oMLX 是一个专为 Apple Silicon 设计的 LLM 推理服务器,它的核心卖点就落在这一点上:分层 KV 缓存把已计算的上下文块持久化到 SSD,换对话、换模型、甚至重启服务器之后,历史上下文仍然可以直接复用,不用从头再算。

oMLX 管理面板的 Serving Stats 页面,显示缓存效率与 token 吞吐

项目 2026 年 2 月创建,Apache 2.0 协议开源,目前 19,285 star、1,656 fork。作者 junkim 用一句话概括动机:市面上的 LLM 服务器让他必须在便利和控制之间二选一,他想要把日常模型钉在内存里、按需自动换载重模型、给上下文设上限,并且全部从菜单栏管理。oMLX 就是这个需求的产物。

分层 KV 缓存:为什么它对 Mac 用户重要

KV 缓存是大模型推理时存放注意力中间状态的数据结构。每多轮对话,缓存就多一截。传统做法是全部放显存(在 Mac 上即统一内存),内存一满,要么驱逐最早的块(下次命中不了就重算),要么直接 OOM。Mac mini M4 这类 16GB 内存的机器,跑一个 8bit 量化模型后留给 KV 缓存的空间非常有限,长上下文基本不可用。

oMLX 借鉴 vLLM 的分页管理思路,把 KV 缓存按块切分,配合前缀共享和写时复制(Copy-on-Write),并分成两层:

  • 热层(RAM):频繁访问的块留在内存,读写延迟最低;
  • 冷层(SSD):热层满了以后,块以 safetensors 格式落盘。下次请求命中相同前缀时直接从磁盘恢复,跳过重新计算,服务器重启后缓存依然有效。

资源管理界面,可调节总内存、模型内存、热缓存与 SSD 冷缓存上限

实际效果可以从管理面板的统计里读出来。官方截图显示的运行数据:累计处理 2,690,587 token,其中 2,288,640 token 来自缓存命中,缓存效率 85.1%;不含缓存的提示词处理速度 901.4 tok/s,生成速度 36.4 tok/s。对一个在本地跑编码 Agent 的开发者来说,这意味着多轮工具调用反复传入的相同系统提示和对话历史,绝大多数不需要重算。

对统一内存紧张的机型,这个设计还改变了容量规划的逻辑。冷缓存上限按 SSD 剩余空间的比例设置(默认界面给出 80%,对应数百 GB),KV 缓存的实际容量不再受物理内存约束,而受磁盘约束。内存只承担热块。

架构:FastAPI 之上叠了一个 EnginePool

oMLX 的服务端结构可以概括为四层:

text
FastAPI Server (OpenAI / Anthropic API)
    │
    ├── EnginePool (multi-model, LRU eviction, TTL, manual load/unload)
    │   ├── BatchedEngine (LLMs, continuous batching)
    │   ├── VLMEngine (vision-language models)
    │   ├── EmbeddingEngine
    │   └── RerankerEngine
    │
    ├── ProcessMemoryEnforcer (total memory limit, TTL checks)
    │
    ├── Scheduler (FCFS, configurable concurrency)
    │   └── mlx-lm BatchGenerator
    │
    └── Cache Stack
        ├── PagedCacheManager (GPU, block-based, CoW, prefix sharing)
        ├── Hot Cache (in-memory tier, write-back)
        └── PagedSSDCacheManager (SSD cold tier, safetensors format)

几个在设计上区别于简单封装的点:

多模型并存与自动驱逐。 EnginePool 允许 LLM、VLM、embedding 模型、reranker 在同一进程内并存,按 LRU 策略自动驱逐最久未用的模型。常用模型可以钉住(pin)常驻,也可以给每个模型单独设 TTL 空闲超时。进程级内存上限默认为「物理内存减 8GB」,防止系统级 OOM。

连续批处理。 并发请求通过 mlx-lm 的 BatchGenerator 处理,最大并发数可配(默认 8)。这与分层缓存是互补关系:批处理解决的是多请求吞吐,缓存解决的是单请求的重复前缀。

API 兼容层做得比较完整。 OpenAI 与 Anthropic 两套 API 均为 drop-in 替换,POST /v1/chat/completionsPOST /v1/messages/v1/embeddings/v1/rerank 都有。对 Claude Code 适配做了专门优化:上下文缩放让小上下文模型在 Claude Code 里以正确的时机触发自动压缩,SSE keep-alive 防止长 prefill 期间读超时。管理面板里 OpenClaw、OpenCode、Codex、Hermes Agent、Copilot 的接入配置可以一键生成。

原生 Metal 内核:GLM-5.2 prefill 提速 30 倍

oMLX 对 GLM-5.2、MiniMax M3、Qwen3.5 三个模型家族提供了原生自定义内核。README 给出的对比数字:M3 Ultra 上 GLM-5.2 的融合 DSA prefill,带内核 845 tok/s,不带内核约 29 tok/s,差距约 30 倍;不带内核的回退路径内存占用也更高。

这里有一个部署时容易踩的坑:pip install -e . 默认不编译这些内核,受影响的模型会静默回退到慢速通用路径。编译需要 Metal 工具链,而 Command Line Tools 单独不提供 metal 工具(报错 xcrun: error: unable to find utility "metal"),需要完整 Xcode。不想装 Xcode 的用户直接用官方 DMG,内核预编译在里面。Homebrew 用户可以 brew install jundot/omlx/omlx --HEAD --with-custom-kernel。装完可以用一行命令验证内核状态:

bash
python -c "from omlx.custom_kernels import native_kernel_status; print(native_kernel_status())"

近 40 万条社区 Benchmark 能看出什么

oMLX 在应用内内置了一键 benchmark,测量 prefill(PP)和生成(TG)的 tok/s,并带部分前缀缓存命中的测试。用户可以从 App 提交结果(v0.2.6+),官方汇总在 omlx.ai/benchmarks,目前累计 398,915 条。

以 M4 系列芯片过滤(127,968 条结果),第一页的近期数据:

芯片内存模型量化上下文PP tok/sTG tok/s
M4 Max (40c)64 GBQwen3.8-27B-oQ8e-mtp8bit1k244.839.2
M4 Max (40c)64 GBQwen3.8-27B-oQ8e-mtp8bit4k249.345.4
M4 Max (40c)128 GBQwen38-27B-oQ4e-mtp4bit16k298.347.9
M4 Max (40c)128 GBQwen38-27B-oQ4e-mtp4bit8k299.943.2
M4 Max (40c)64 GBNVIDIA-Nemotron-3-Nano-30B-A3B4bit4k1,578143.7
M4 Max (40c)128 GBQwen2.5-Coder-14B-Instructbf168k477.915.5

几个可以从数据里直接读出的结论:

MoE 架构在生成速度上优势明显。 NVIDIA-Nemotron-3-Nano-30B-A3B 是 A3B 结构(激活参数约 3B),TG 达到 143.7-147.1 tok/s,是同表 dense 模型的三倍以上。密集的 Qwen3.8-27B 在 8bit 下 TG 只有 39-45 tok/s。

bf16 全精度在 Apple Silicon 上依然可行,但代价是生成速度。 Qwen2.5-Coder-14B 的 bf16 版本 TG 只有 15.5 tok/s,对比 4bit 量化的 27B 模型反而更慢。在统一内存架构上,精度带来的内存带宽压力直接反映在生成速度上。

MTP 标记的含义。 表格中带 ✓ 的条目使用了 MTP(multi-token prediction)/TQ 提交,这是 oMLX 内置的投机解码路径,官方排行榜可以按需隐藏这些结果做对比。

菜单栏应用与多 Mac 分布式

oMLX 同时提供一个原生 Swift/SwiftUI 菜单栏应用(非 Electron),负责服务器的启停、监控、崩溃自动重启和应用内自动更新,统计信息跨重启持久保存。从 Homebrew 安装时,omlx start 委托给 brew services,崩溃自动拉起。

macOS 菜单栏弹出窗口显示服务器状态与统计

更激进的功能是实验性的多 Mac 推理:源码构建版本可以把一个下载好的语言模型拆分到内存不等的两台 Mac 上,基于 MLX pipeline ranks,走 Ring 或 Thunderbolt RDMA/JACCL 互联。集群面板处理对等发现、SSH/runtime 校验、按字节感知的不等分片规划、实测算力/链路再平衡。对拥有多台 Mac mini 的开发者,这是一条把零散机器拼成一台大内存推理节点的路径,目前仍在实验阶段。

部署的最短路径

三种安装方式按省事程度排序:

bash
# 方式一:DMG(推荐,内核预编译,应用内自动更新)
# 从 GitHub Releases 下载 .dmg 拖进 Applications

# 方式二:Homebrew
brew tap jundot/omlx https://github.com/jundot/omlx
brew install jundot/omlx/omlx
omlx start

# 方式三:源码
git clone https://github.com/jundot/omlx.git
cd omlx && pip install -e .
omlx serve --model-dir ~/models

服务器默认监听 http://localhost:8000/v1,自动发现模型目录下的 LLM、VLM、OCR、embedding 和 reranker。OCR 模型(DeepSeek-OCR、DOTS-OCR、GLM-OCR)自动检测并套用优化提示词。管理面板支持八种语言,CDN 依赖全部本地化,可完全离线运行。受限地区下载模型可以切 --hf-endpoint https://hf-mirror.com

对 16GB 内存的 Mac mini M4,实际可用的模型档位大致是 4bit 量化的 7B-14B dense 模型,或 Qwen3 系列 A3B 类 MoE。默认内存上限(RAM - 8GB)留给系统和 Agent 工具链的空间已经不多,跑大模型时建议把 Hermes、浏览器这类常驻内存的大户先关掉。27B 级别模型在 16GB 机器上只能靠 2bit/3bit 极限量化,生成质量会明显掉档,这类机型更合适的定位是 embedding 服务器加轻量 LLM,重度推理交给云端 API。

oMLX 起源于 vllm-mlx v0.1.0,在其之上长出了多模型服务、分层 KV 缓存、完整 paged cache 支持的 VLM、管理面板和菜单栏应用。它对「Mac 作为本地推理节点」这个场景的完成度,目前看是同类项目里比较靠前的:缓存层解决了长上下文的重复计算,EnginePool 解决了多模型的内存调度,Metal 内核解决了特定模型家族的 prefill 瓶颈。对已经在 Mac 上跑 Ollama 或 LM Studio 的用户,如果痛点集中在长对话延迟和多模型切换,值得把它加入对比清单。

来源: