如何在macOS上设置本地编码代理
摘要
一份关于在macOS上使用Gemma 4与MTP草稿模型及llama.cpp设置本地编码代理的详细教程,通过投机解码实现了约24%的速度提升。
暂无内容
查看缓存全文
缓存时间: 2026/06/12 20:56
# 如何在 macOS 上搭建本地编码代理
来源:https://ikyle.me/blog/2026/how-to-setup-a-local-coding-agent-on-macos
最近几次网络出现问题,让我在没有编码代理的情况下束手无策,所以当我看到关于 Gemma 4 的“MTP 让 Gemma 4 运行速度提升 2 倍” (https://x.com/UnslothAI/status/2065107734916432189) 更新时,我决定尝试让它在本地跑起来。
我希望本地的编码代理设置能满足以下几点:
- 在我的 Mac 上足够快,真正可用
- 通过 OpenAI 兼容的 API 工作(这样我就可以在其他工具中使用它)
- 最好能在需要时处理截图/图像,这样我可以将制作好的截图喂给它。
我做到了!这个视频是实时拍摄的,展示了代理以完全可用的速度响应。
经过一番测试,我最终使用的配置是:
- llama.cpp (https://github.com/ggml-org/llama.cpp) 在 macOS 上使用 Metal 构建
- Gemma 4 26B-A4B GGUF 格式
- 用于推测解码的 Q8 MTP draft 模型
- Gemma 4 多模态投影器
- Pi (https://github.com/earendil-works/pi) 作为终端编码代理
测试环境:Apple M1 Max,64 GB 统一内存,运行 macOS 15.7.7。
## 模型
主模型为:`gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf`。
Huggingface 链接:models/unsloth-gemma-4-26B-A4B-it-GGUF/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf (https://huggingface.co/unsloth/gemma-4-26B-A4B-it-GGUF/blob/main/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf)
该文件约 16 GB。加上 MTP draft 头部和多模态投影器,模型文件夹总共约 17 GB。
基准测试提示词:
```
Write a compact Python function that parses a unified diff and returns the changed file paths. Then explain two edge cases.
```
每次基准测试生成约 128 个 token。
## 基准线:llama.cpp + Metal
首先我直接在 llama.cpp 中通过 Metal 加速运行主模型:
```
repos/llama.cpp/build/bin/llama-cli \
-m models/unsloth-gemma-4-26B-A4B-it-GGUF/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf \
-ngl 999 \
-fa on \
-c 4096 \
-n 128
```
结果:
| 设置 | Prompt tok/s | Generation tok/s |
|------|--------------|------------------|
| Gemma 4 26B-A4B Q4, llama.cpp Metal | 298.0 | 58.2 |
58.2 tokens/秒并不算快,但还算可用。不过对于编码代理的工作来说,尤其是在代理进行多次工具调用时,我们希望速度尽可能快。
## 添加 MTP Draft 模型
Gemma 4 现在提供了 MTP draft 模型 (https://huggingface.co/unsloth/gemma-4-26B-A4B-it-GGUF/blob/main/MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf):
```
MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
```
它可以作为推测 draft 模型加载到 llama.cpp 中:
```
repos/llama.cpp/build/bin/llama-cli \
-m models/unsloth-gemma-4-26B-A4B-it-GGUF/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf \
--model-draft models/unsloth-gemma-4-26B-A4B-it-GGUF/MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf \
--spec-type draft-mtp \
--spec-draft-n-max 3 \
-ngl 999 \
-fa on \
-c 4096 \
-n 128
```
首次运行 MTP 时,使用 4 个 draft token 达到了 69.2 tokens/秒。不过,Unsloth 的《如何运行 MTP 模型》指南 (https://unsloth.ai/docs/models/mtp) 包含以下说明:
> “我们发现 `--spec-draft-n-max 2` 是最佳起点,但不要假定 2 是最优值,因为性能取决于硬件。可以尝试 1 到 6 之间的任何值,选择对您的系统最快的那个。”
经过对 `--spec-draft-n-max` 的扫描,最佳结果是 72.2 tokens/秒(使用 3 个 draft token)。
| 设置 | Prompt tok/s | Generation tok/s | Speedup |
|------|--------------|------------------|---------|
| 仅主模型 | 298.0 | 58.2 | 1.00x |
| 主模型 + Q8 MTP draft | 295.6 | 72.2 | 1.24x |
有用的一点是,提示处理速度基本保持不变,而生成速度提升了约 24%。
## 调整 MTP
我测试了 `--spec-draft-n-max` 从 1 到 6 的值。
| `--spec-draft-n-max` | Prompt tok/s | Generation tok/s |
|----------------------|--------------|------------------|
| 1 | 295.5 | 68.4 |
| 2 | 299.1 | 72.0 |
| 3 | 295.6 | 72.2 |
| 4 | 297.3 | 70.7 |
| 5 | 297.9 | 63.7 |
| 6 | 296.3 | 61.2 |
在我的 M1 Max 机器上,`3` 是最快的,`2` 也非常接近,两者都可以。更高的值会变慢。
## MLX 对比
我还通过 `mlx-lm` 测试了 MLX 模型,以了解在 Mac 上运行该模型更快的方式是 llama.cpp 还是 mlx。
| 运行时 | 模型 | Generation tok/s |
|--------|------|------------------|
| llama.cpp Metal + MTP | Unsloth GGUF Q4 + Q8 MTP | 72.2 |
| llama.cpp Metal | Unsloth GGUF Q4 | 58.2 |
| MLX-LM | Unsloth UD MLX 4-bit | 45.8 |
| MLX-LM | mlx-community 4-bit | 43.9 |
| MLX-LM | mlx-community OptiQ 4-bit | 38.1 |
我原以为 MLX(为 Mac 优化)会最快。但在这个特定设置中,llama.cpp 比 MLX 更快,而带有 MTP 的 llama.cpp 显然是最佳选择。
我想,长期以来对 llama.cpp 进行的所有优化和调整,使得它在 macOS 上得到了相当不错的优化,尽管它是跨平台的。
我还尝试了通过 gemma-4-swift-mlx (https://github.com/VincentGourbin/gemma-4-swift-mlx) 运行 Gemma 4 MTP,但测试的 26B 4-bit MLX 检查点与加载器预期的权重键不匹配,而且我已经有了之前的 MLX 测试结果,所以继续前进,没有再重新下载新模型并尝试调整匹配。
## 添加图像支持
对于 Pi,我还希望能够附加截图。我最初为其设置的本地模型条目声明为纯文本:
这意味着 Pi 没有正确地将图像工具输出发送给模型。
llama.cpp 服务器还需要 Gemma 4 多模态投影器才能让多模态部分工作(只有 12B 版本原生支持多模态 (https://blog.google/innovation-and-ai/technology/developers-tools/introducing-gemma-4-12b/)):
当加载 `--mmproj` 时,llama.cpp 会宣传多模态支持,Pi 就可以发送图像了。
我重新运行了文本基准测试(加载投影器),以检查是否影响速度:
| 设置 | 投影器 | Prompt tok/s | Generation tok/s |
|------|--------|--------------|------------------|
| llama.cpp Metal + MTP | 无 | 120.3 | 71.4 |
| llama.cpp Metal + MTP | `mmproj-BF16.gguf` | 297.4 | 72.2 |
最终运行投影器并没有显示出文本生成速度的下降。
---
现在来看设置说明:
## 安装 llama.cpp
安装依赖:
```
brew install cmake git tmux [email protected]
```
克隆并构建 llama.cpp:
```
mkdir -p ~/Developer/ML-Models/Gemma4/repos
cd ~/Developer/ML-Models/Gemma4
git clone https://github.com/ggml-org/llama.cpp repos/llama.cpp
cd repos/llama.cpp
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_METAL=ON \
-DGGML_ACCELERATE=ON
cmake --build build --config Release -j
```
我测试的构建包含:
```
GGML_METAL=ON
GGML_ACCELERATE=ON
GGML_BLAS=ON
GGML_BLAS_VENDOR=Apple
```
## 下载模型文件
创建 Python 环境:
```
cd ~/Developer/ML-Models/Gemma4
python3.11 -m venv .venv
source .venv/bin/activate
pip install -U huggingface_hub hf_xet
```
下载文件:
```
mkdir -p models/unsloth-gemma-4-26B-A4B-it-GGUF
huggingface-cli download unsloth/gemma-4-26B-A4B-it-GGUF \
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf \
mmproj-BF16.gguf \
MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf \
--local-dir models/unsloth-gemma-4-26B-A4B-it-GGUF
```
最终你会得到:
```
models/unsloth-gemma-4-26B-A4B-it-GGUF/
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf
mmproj-BF16.gguf
MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
```
## 启动本地服务器
最终服务器命令:
```
repos/llama.cpp/build/bin/llama-server \
-m models/unsloth-gemma-4-26B-A4B-it-GGUF/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf \
--model-draft models/unsloth-gemma-4-26B-A4B-it-GGUF/MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf \
--mmproj models/unsloth-gemma-4-26B-A4B-it-GGUF/mmproj-BF16.gguf \
--spec-type draft-mtp \
--spec-draft-n-max 3 \
-ngl 999 \
-fa on \
-c 65536 \
--parallel 1 \
--host 127.0.0.1 \
--port 8080
```
OpenAI 兼容的端点是:
我使用了一个小的 `start_server.sh` 包装脚本,使之在 tmux 中运行:
```
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SESSION_NAME="${SESSION_NAME:-gemma4-server}"
HOST="${HOST:-127.0.0.1}"
PORT="${PORT:-8080}"
CTX_SIZE="${CTX_SIZE:-65536}"
PARALLEL="${PARALLEL:-1}"
LLAMA_SERVER="$ROOT_DIR/repos/llama.cpp/build/bin/llama-server"
MODEL="$ROOT_DIR/models/unsloth-gemma-4-26B-A4B-it-GGUF/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf"
DRAFT_MODEL="$ROOT_DIR/models/unsloth-gemma-4-26B-A4B-it-GGUF/MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf"
MMPROJ="$ROOT_DIR/models/unsloth-gemma-4-26B-A4B-it-GGUF/mmproj-BF16.gguf"
LOG_FILE="$ROOT_DIR/logs/llama-server-mtp.log"
mkdir -p "$ROOT_DIR/logs"
tmux new-session -d -s "$SESSION_NAME" -c "$ROOT_DIR" \
"$LLAMA_SERVER \
-m '$MODEL' \
--model-draft '$DRAFT_MODEL' \
--mmproj '$MMPROJ' \
--spec-type draft-mtp \
--spec-draft-n-max 3 \
-ngl 999 \
-fa on \
-c '$CTX_SIZE' \
--parallel '$PARALLEL' \
--host '$HOST' \
--port '$PORT' \
2>&1 | tee -a '$LOG_FILE'"
```
启动它:
```
chmod +x start_server.sh
./start_server.sh
```
检查服务器是否正在运行:
```
curl http://127.0.0.1:8080/v1/models
```
## 配置 Pi
Pi 从以下位置读取模型提供商:
添加本地提供商:
```
{
"providers": {
"gemma4-local": {
"name": "Gemma 4 Local",
"baseUrl": "http://127.0.0.1:8080/v1",
"api": "openai-completions",
"apiKey": "local",
"authHeader": false,
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf",
"name": "Gemma 4 26B-A4B Q4 + MTP",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 65536,
"maxTokens": 8192,
"cost": {
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0
}
}
]
}
}
}
```
重要部分:
- `baseUrl` 指向 llama.cpp OpenAI 兼容服务器。
- `api` 是 `openai-completions`。
- `authHeader` 为 `false`,因为这是本地服务器。
- `input` 包含 `text` 和 `image`,否则 Pi 会将其视为纯文本。
可选地将其设置为默认值,在:
```
~/.pi/agent/settings.json
```
```
{
"defaultProvider": "gemma4-local",
"defaultModel": "gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf",
"defaultThinkingLevel": "minimal"
}
```
然后检查 Pi 是否能看到它:
```
pi --offline --list-models gemma
```
预期输出:
```
provider model context max-out thinking images
gemma4-local gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf 65.5K 8.2K no yes
```
使用本地模型运行 Pi:
```
pi --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf
```
或使用非交互模式:
```
pi -p --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf \
"Explain what this repository does"
```
对于截图:
```
pi -p @"/path/to/screenshot.png" "Describe this image and point out anything relevant to the UI"
```
## 最终设置
最终的本地编码代理栈:
| 层 | 选择 |
|----|------|
| 推理运行时 | llama.cpp |
| macOS 加速 | Metal + Accelerate |
| 主模型 | `gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf` |
| Draft 模型 | `gemma-4-26B-A4B-it-Q8_0-MTP.gguf` |
| MTP 设置 | `--spec-draft-n-max 3` |
| 多模态投影器 | `mmproj-BF16.gguf` |
| 服务器 | `llama-server` 运行在 `127.0.0.1:8080` |
| API | OpenAI 兼容 `/v1` |
| 编码代理 | Pi |
| Pi 模型输入 | `["text", "image"]` |
主要结论是,MTP draft 模型值得使用。在这台机器上,它将 Gemma 4 从 58.2 tokens/秒提升到 72.2 tokens/秒,同时保持了足够简单的设置,可以作为本地 OpenAI 兼容服务器运行。
---
**附注:**
有建议说可以用 `Qwen3.6 35B-A3B` 代替 `Gemma 4 26B-A4B`。根据我能找到的基准测试,Qwen 作为编码代理**远比** Gemma 4 优秀。但它的速度也更慢。`Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf` + `unsloth-Qwen3.6-35B-A3B-MTP-GGUF` + `mmproj-BF16.gguf` 的结果是 55 tk/s,而不是 72 tk/s。当你坐着等待时,这个差异非常显著。
下载模型:
```
mkdir -p models/unsloth-Qwen3.6-35B-A3B-MTP-GGUF
huggingface-cli download unsloth/Qwen3.6-35B-A3B-MTP-GGUF \
Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf \
mmproj-BF16.gguf \
--local-dir models/unsloth-Qwen3.6-35B-A3B-MTP-GGUF
```
启动服务器:
```
LLAMA_SERVER=/Users/kylehowells/Developer/ML-Models/Gemma4/repos/llama.cpp/build/bin/llama-server
$LLAMA_SERVER \
-m models/unsloth-Qwen3.6-35B-A3B-MTP-GGUF/Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf \
--mmproj models/unsloth-Qwen3.6-35B-A3B-MTP-GGUF/mmproj-BF16.gguf \
--spec-type draft-mtp \
--spec-draft-n-max 3 \
-ngl 999 \
-fa on \
-c 65536 \
--parallel 1 \
--host 127.0.0.1 \
--port 8081
```
Pi 配置:
```
{
"providers": {
"qwen36-local": {
"name": "Qwen3.6 Local",
"baseUrl": "http://127.0.0.1:8081/v1",
"api": "openai-completions",
"apiKey": "local",
"authHeader": false,
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf",
"name": "Qwen3.6 35B-A3B Q4 + MTP",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 65536,
"maxTokens": 8192,
"cost": {
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0
}
}
]
}
}
}
```
## 参考文献
- unsloth.ai/docs/models/qwen3.6 (https://unsloth.ai/docs/models/qwen3.6)
- unsloth.ai/docs/models/gemma-4 (https://unsloth.ai/docs/models/gemma-4)
- unsloth.ai/docs/models/mtp (https://unsloth.ai/docs/models/mtp)
- github.com/ggml-org/llama.cpp (https://github.com/ggml-org/llama.cpp)
- github.com/earendil-works/pi (https://github.com/earendil-works/pi)
- Introducing Gemma 4 12B: a unified, encoder-free multimodal model (https://blog.google/innovation-and-ai/technology/developers-tools/introducing-gemma-4-12b/)
- "MTP enables Google Gemma 4 run ~1.4–2.2× faster with no accuracy loss" (https://x.com/UnslothAI/status/2065107734916432189)
- unsloth/gemma-4-26B-A4B-it-GGUF (https://huggingface.co/unsloth/gemma-4-26B-A4B-it-GGUF)
- unsloth/Qwen3.6-35B-A3B-MTP-GGUF (https://huggingface.co/unsloth/Qwen3.6-35B-A3B-MTP-GGUF)
相似文章
@port_dev: https://x.com/port_dev/status/2054259445732110408
本文提供了一份详细教程,介绍如何通过 Unsloth Studio 和 Pi 编码框架配置基于 Qwen3.6-27B 的本地编码智能体。文章强调了使用 GGUF 量化模型在消费级硬件(如搭载 Apple Silicon 芯片的 Mac 电脑)上实现高效推理的优势。
@Freerunnering: 这实际上使得Gemma 4 26B-4A在我的MacBook Pro M1 Max上以72tk/s的速度可用于编码代理。这个视频是实时的,…
Unsloth AI宣布,Gemma 4在MTP GGUFs上运行速度快了2倍,使得在如MacBook Pro M1 Max这样的硬件上以72 tokens/s的速度运行本地编码代理成为可能。
在单个16GB GPU + 64GB RAM上的本地LLM自动补全与代理式编码
使用 llama.cpp 在单块 16GB GPU 及 64GB+ 内存上设置本地 LLM 自动完成(Qwen2.5-Coder-7B)与代理编码(Qwen3.6-35B-A3B)的技术指南,包含命令与性能基准。
谷歌的 Gemma 4 12B 刚刚发布 —— 下面教你如何在 Mac 上本地运行它
Google 发布了 Gemma 4 12B,这是一款基于 Apache 2.0 开源协议的多模态模型,支持文本、视觉和音频处理,上下文窗口达 256K。本文提供了一份指南,介绍如何在 Mac 上使用 Ollama、LM Studio 或 llama.cpp 本地运行该模型。
本地运行 Qwen3.6-35B-A3B 作为编码 Agent:我的完整部署与可用配置
一份详尽指南,教你如何在 Apple Silicon 上通过 llama.cpp 本地运行 350 亿参数 Qwen3.6 模型,并驱动 pi 编码 Agent,附带优化后的启动参数与采样配置。