本指南将带你在 macOS 上运行一个带有 OpenAI 兼容 API 的本地 LLM 服务器。你可以获得完整隐私、零 API 成本,以及在 Apple Silicon 上出人意料的良好性能。
我们将介绍两个后端:
| 后端 | 安装 | 最擅长 | 格式 |
|---|---|---|---|
| llama.cpp | brew install llama.cpp | 最快的首 token 延迟,用于低内存的量化 KV cache | GGUF |
| omlx | omlx.ai | 最快的 token 生成,原生 Metal 优化 | MLX(safetensors) |
两者都会暴露一个兼容 OpenAI 的 /v1/chat/completions 端点。Hermes 可以与任意一个配合使用 —— 只需要将其指向 http://localhost:8080 或 http://localhost:8000。
对于入门,我们推荐 Qwen3.5-9B —— 它是一个强大的推理模型,在量化后可以轻松适配 8GB+ 统一内存。
| 变体 | 磁盘大小 | 所需 RAM(128K 上下文) | 后端 |
|---|---|---|---|
| Qwen3.5-9B-Q4_K_M(GGUF) | 5.3 GB | 使用量化 KV cache 时约 10 GB | llama.cpp |
| Qwen3.5-9B-mlx-lm-mxfp4(MLX) | 约 5 GB | 约 12 GB | omlx |
内存经验法则:模型大小 + KV cache。一个 9B Q4 模型约为 5 GB。使用 Q4 量化时,128K 上下文的 KV cache 会额外增加约 4–5 GB。使用默认的 f16 KV cache 时,它会膨胀到约 16 GB。llama.cpp 中的量化 KV cache flags 是内存受限系统中的关键技巧。
对于更大的模型(27B、35B),你需要 32 GB+ 的统一内存。9B 是 8–16 GB 机器的最佳平衡点。
选项 A:llama.cpp
Section titled “选项 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 ~/modelsllama-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下面是每个 flag 的作用:
| Flag | 作用 |
|---|---|
-ngl 99 | 将所有层卸载到 GPU(Metal)。使用较大的数字以确保没有层留在 CPU 上。 |
-c 131072 | 上下文窗口大小(128K tokens)。如果内存不足,请降低这个值。 |
-np 1 | 并行 slots 数量。单用户使用时保持为 1 —— 更多 slots 会拆分你的内存预算。 |
-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:8080srv update_slots: all slots are idle受限系统的内存优化
Section titled “受限系统的内存优化”--cache-type-k q4_0 --cache-type-v q4_0 是内存有限系统上最重要的优化。下面是在 128K 上下文下的影响:
| KV cache 类型 | KV cache 内存(128K ctx,9B 模型) |
|---|---|
| f16(默认) | 约 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+ 上,可以运行更大的模型或多个并行 slots。
如果仍然内存不足,请先降低上下文大小(-c),然后尝试更小的量化版本(例如使用 Q3_K_M 而不是 Q4_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获取模型名称
Section titled “获取模型名称”如果忘记了模型名称,可以查询 models 端点:
curl -s http://localhost:8080/v1/models | jq '.data[].id'选项 B:通过 omlx 使用 MLX
Section titled “选项 B:通过 omlx 使用 MLX”omlx 是一个 macOS 原生应用,用于管理和服务 MLX 模型。MLX 是 Apple 自己的机器学习框架,专门针对 Apple Silicon 的统一内存架构进行了优化。
从 omlx.ai 下载并安装。它提供用于模型管理的 GUI 和内置服务器。
使用 omlx 应用浏览并下载模型。搜索 Qwen3.5-9B-mlx-lm-mxfp4 并下载它。模型会存储在本地(通常位于 ~/.omlx/models/)。
默认情况下,omlx 会在 http://127.0.0.1:8000 上提供模型服务。可以从应用 UI 中启动服务,或者在可用时使用 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列出可用模型
Section titled “列出可用模型”omlx 可以同时服务多个模型:
curl -s http://127.0.0.1:8000/v1/models | jq '.data[].id'基准测试:llama.cpp vs MLX
Section titled “基准测试:llama.cpp vs MLX”两个后端都在同一台机器上测试(Apple M5 Max,128 GB 统一内存),运行相同模型(Qwen3.5-9B),并使用可比较的量化级别(GGUF 使用 Q4_K_M,MLX 使用 mxfp4)。测试包含五个不同提示词,每个提示词运行三次,后端按顺序测试,以避免资源争用。
| 指标 | llama.cpp(Q4_K_M) | MLX(mxfp4) | 胜出者 |
|---|---|---|---|
| TTFT(平均) | 67 ms | 289 ms | llama.cpp(快 4.3 倍) |
| TTFT(p50) | 66 ms | 286 ms | llama.cpp(快 4.3 倍) |
| 生成速度(平均) | 70 tok/s | 96 tok/s | MLX(快 37%) |
| 生成速度(p50) | 70 tok/s | 96 tok/s | MLX(快 37%) |
| 总耗时(512 tokens) | 7.3s | 5.5s | MLX(快 25%) |
这意味着什么
Section titled “这意味着什么”- llama.cpp 擅长提示词处理 —— 它的 flash attention + 量化 KV cache 流水线可以让你在约 66ms 内获得第一个 token。如果你正在构建交互式应用,并且感知响应速度很重要(聊天机器人、自动补全),这是一个有意义的优势。
- MLX 一旦开始生成,token 生成速度约快 37%。对于批处理工作负载、长文本生成,或任何总完成时间比初始延迟更重要的任务,MLX 会更快完成。
- 两个后端都非常稳定 —— 多次运行之间的方差可以忽略不计。你可以信赖这些数字。
你应该选择哪个?
Section titled “你应该选择哪个?”| 使用场景 | 推荐 |
|---|---|
| 交互式聊天、低延迟工具 | llama.cpp |
| 长文本生成、批量处理 | MLX(omlx) |
| 内存受限(8–16 GB) | llama.cpp(量化 KV cache 无可匹敌) |
| 同时服务多个模型 | omlx(内置多模型支持) |
| 最大兼容性(也支持 Linux) | llama.cpp |
连接到 Hermes
Section titled “连接到 Hermes”本地服务器运行后:
hermes model选择 Custom endpoint,并按照提示操作。它会要求输入 base URL 和模型名称 —— 使用你上面设置的对应后端的值。
Hermes 会自动检测本地端点(localhost、LAN IP),并放宽其流式输出超时时间。大多数设置无需配置。
如果你仍然遇到超时错误(例如在较慢硬件上使用非常大的上下文),可以覆盖流式读取超时时间:
# 在你的 .env 中 —— 从默认 120s 提高到 30 分钟HERMES_STREAM_READ_TIMEOUT=1800| 超时 | 默认值 | 本地自动调整 | 环境变量覆盖 |
|---|---|---|---|
| 流式读取(socket 级别) | 120s | 提高到 1800s | HERMES_STREAM_READ_TIMEOUT |
| 停滞流检测 | 180s | 完全禁用 | HERMES_STREAM_STALE_TIMEOUT |
| API 调用(非流式) | 1800s | 无需更改 | HERMES_API_TIMEOUT |
流式读取超时是最可能导致问题的那个 —— 它是接收下一块数据的 socket 级截止时间。在大上下文预填充期间,本地模型可能会在处理提示词时连续数分钟不产生输出。自动检测会透明地处理这种情况。