跳到主要内容

在 Mac 上运行本地 LLM

本指南会带你在 macOS 上运行一个提供 OpenAI 兼容 API 的本地 LLM 服务。这样你可以获得完整隐私、零 API 成本,以及在 Apple Silicon 上相当不错的性能。

这里会介绍两个后端:

BackendInstallBest atFormat
llama.cppbrew install llama.cpp首 token 延迟最低,量化 KV cache 带来更低内存占用GGUF
omlxomlx.aitoken 生成速度最快,原生 Metal 优化MLX (safetensors)

两者都会暴露兼容 OpenAI 的 /v1/chat/completions 接口。Hermes 可以直接接入任意一种,只需要把地址指向 http://localhost:8080http://localhost:8000

Apple Silicon only

本指南面向 Apple Silicon Mac(M1 及更新机型)。Intel Mac 也能运行 llama.cpp,但无法获得 GPU 加速,性能会明显慢很多。


选择模型

如果你想快速上手,我们推荐 Qwen3.5-9B。这是一个推理能力很强的模型,在量化后可以比较轻松地放进 8GB 以上统一内存的机器里。

VariantSize on diskRAM needed (128K context)Backend
Qwen3.5-9B-Q4_K_M (GGUF)5.3 GB使用量化 KV cache 时约 10 GBllama.cpp
Qwen3.5-9B-mlx-lm-mxfp4 (MLX)~5 GB~12 GBomlx

内存经验法则: 模型体积 + KV cache。9B 的 Q4 模型大约是 5 GB。上下文设为 128K 时,若使用 Q4 量化,KV cache 大约再增加 4 到 5 GB;如果用默认的 f16 KV cache,则会膨胀到大约 16 GB。对于内存吃紧的系统来说,llama.cpp 的量化 KV cache 参数是关键技巧。

如果你想用更大的模型(27B、35B),通常需要 32 GB 以上统一内存。对于 8 到 16 GB 的机器,9B 往往是最合适的甜点位。


方案 A:llama.cpp

llama.cpp 是最通用的本地 LLM 运行时之一。在 macOS 上它会默认使用 Metal 做 GPU 加速。

安装

brew install llama.cpp

安装完成后,你就能全局使用 llama-server 命令。

下载模型

你需要一个 GGUF 格式的模型。最简单的来源是通过 huggingface-cli 从 Hugging Face 下载:

brew install huggingface-cli

然后执行:

huggingface-cli download unsloth/Qwen3.5-9B-GGUF Qwen3.5-9B-Q4_K_M.gguf --local-dir ~/models
Gated models

有些 Hugging Face 模型需要认证。如果你遇到 401 或 404,请先执行 huggingface-cli login

启动服务

llama-server -m ~/models/Qwen3.5-9B-Q4_K_M.gguf \
-ngl 99 \
-c 131072 \
-np 1 \
-fa on \
--cache-type-k q4_0 \
--cache-type-v q4_0 \
--host 0.0.0.0

各个参数的含义如下:

FlagPurpose
-ngl 99把所有层都尽量卸载到 GPU(Metal)。设置成较大的数,确保不会留在 CPU 上
-c 131072上下文窗口大小(128K tokens)。如果内存紧张,可以调小
-np 1并行槽位数。单用户场景建议保持 1,更多槽位会分摊你的内存预算
-fa on开启 Flash Attention,可减少内存使用并加快长上下文推理
--cache-type-k q4_0把 key cache 量化到 4-bit,这是最大的省内存手段之一
--cache-type-v q4_0把 value cache 量化到 4-bit。和上面一起使用时,相比 f16 可把 KV cache 内存削减约 75%
--host 0.0.0.0监听所有网卡。如果你不需要网络访问,可以改成 127.0.0.1

当你看到下面输出时,说明服务已经启动:

main: server is listening on http://0.0.0.0:8080
srv update_slots: all slots are idle

面向受限机器的内存优化

对内存有限的系统来说,--cache-type-k q4_0 --cache-type-v q4_0 是最重要的优化参数。在 128K 上下文下,影响如下:

KV cache typeKV cache memory (128K ctx, 9B model)
f16 (default)~16 GB
q8_0~8 GB
q4_0~4 GB

如果你是 8 GB Mac,建议使用 q4_0 KV cache,并把上下文缩减到 -c 32768(32K)。16 GB 机器通常可以较舒适地跑 128K;32 GB 及以上则可以考虑更大模型或多个并行槽位。

如果还是爆内存,优先先减小上下文窗口(-c),再考虑更激进的模型量化,例如把 Q4_K_M 改成 Q3_K_M。

测试它

curl -s http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3.5-9B-Q4_K_M.gguf",
"messages": [{"role": "user", "content": "Hello!"}],
"max_tokens": 50
}' | jq .choices[0].message.content

获取模型名

如果你忘了模型名,可以查询 models 接口:

curl -s http://localhost:8080/v1/models | jq '.data[].id'

方案 B:通过 omlx 使用 MLX

omlx 是一个 macOS 原生应用,用来管理和提供 MLX 模型服务。MLX 是 Apple 自家的机器学习框架,专门针对 Apple Silicon 的统一内存架构做了优化。

安装

omlx.ai 下载并安装即可。它提供图形界面做模型管理,并内置了服务能力。

下载模型

使用 omlx 应用浏览并下载模型。搜索 Qwen3.5-9B-mlx-lm-mxfp4 并下载。模型会存储在本地(通常位于 ~/.omlx/models/)。

启动服务

omlx 默认会在 http://127.0.0.1:8000 提供模型服务。你可以直接在应用 UI 中开启服务,如果 CLI 可用,也可以用 CLI。

测试它

curl -s http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3.5-9B-mlx-lm-mxfp4",
"messages": [{"role": "user", "content": "Hello!"}],
"max_tokens": 50
}' | jq .choices[0].message.content

列出可用模型

omlx 可以同时提供多个模型:

curl -s http://127.0.0.1:8000/v1/models | jq '.data[].id'

基准测试:llama.cpp vs MLX

两个后端都在同一台机器上测试(Apple M5 Max,128 GB 统一内存),使用同一个模型(Qwen3.5-9B),量化等级也尽量对齐(GGUF 使用 Q4_K_M,MLX 使用 mxfp4)。一共用了 5 个不同提示,每个提示跑 3 次,两个后端串行测试以避免资源争抢。

结果

Metricllama.cpp (Q4_K_M)MLX (mxfp4)Winner
TTFT (avg)67 ms289 msllama.cpp(快 4.3 倍)
TTFT (p50)66 ms286 msllama.cpp(快 4.3 倍)
Generation (avg)70 tok/s96 tok/sMLX(快 37%)
Generation (p50)70 tok/s96 tok/sMLX(快 37%)
Total time (512 tokens)7.3s5.5sMLX(快 25%)

这意味着什么

  • llama.cpp 在 prompt 处理阶段表现更强。它依靠 flash attention + 量化 KV cache,可以在约 66ms 内给出首个 token。如果你在做聊天机器人、自动补全这类对“体感响应”非常敏感的交互应用,这是一个很有价值的优势。

  • MLX 一旦开始生成,速度会快约 37%。对于批处理、长文本生成,或者任何更看重总完成时间而不是起始延迟的任务,MLX 往往更早结束。

  • 两者的表现都非常稳定,不同轮次之间的波动几乎可以忽略。这些数据是可以参考的。

该选哪一个?

Use caseRecommendation
交互式聊天、低延迟工具调用llama.cpp
长文本生成、批量处理MLX (omlx)
内存紧张(8-16 GB)llama.cpp(量化 KV cache 几乎无可替代)
需要同时提供多个模型omlx(内建多模型支持)
追求最大兼容性(包括 Linux)llama.cpp

连接到 Hermes

当你的本地服务跑起来后:

hermes model

选择 Custom endpoint,然后按提示输入 base URL 和 model name。直接使用你上面设置好的后端对应值即可。


超时

Hermes 会自动识别本地 endpoint(localhost、局域网 IP),并自动放宽流式请求超时。大多数场景下不需要额外配置。

如果你仍然遇到超时错误(例如在慢硬件上跑超大上下文),可以手动覆盖流式读取超时:

# In your .env — raise from the 120s default to 30 minutes
HERMES_STREAM_READ_TIMEOUT=1800
TimeoutDefaultLocal auto-adjustmentEnv var override
Stream read (socket-level)120s自动提升到 1800sHERMES_STREAM_READ_TIMEOUT
Stale stream detection180s完全禁用HERMES_STREAM_STALE_TIMEOUT
API call (non-streaming)1800s无需调整HERMES_API_TIMEOUT

最常引发问题的是 stream read timeout,它控制的是“等待下一块数据到达 socket”的截止时间。在大上下文预填充阶段,本地模型可能要花好几分钟处理 prompt,却还没有任何输出。自动检测机制会透明地帮你处理这一点。