MacBook Air M4 编译 llama.cpp 运行 GLM 模型:Metal GPU 加速实战

在上一篇教程中,我们介绍了使用 Ollama 一键部署 GLM-4 模型的方法。本文将带你更深入一层——手动编译 llama.cpp,利用 Apple M4 芯片的 Metal GPU 加速来运行 GLM 模型。这种方式虽然步骤更多,但提供了更精细的控制和更极致的性能调优空间。

llama.cpp 简介

llama.cpp 是由 Georgi Gerganov 开发的开源项目,使用纯 C/C++ 实现,专注于在消费级硬件上高效运行大语言模型。它的核心优势包括:

  • 极致性能:针对 CPU 和 GPU 做了深度优化,支持 AVX2/AVX-512/Metal/CUDA 等多种加速方案
  • 低依赖:纯 C/C++ 实现,无需安装庞大的 Python 环境和 PyTorch
  • GGUF 格式:支持模型量化压缩,大幅减少内存占用
  • API 服务:内置 HTTP 服务器,兼容 OpenAI API 格式
  • 跨平台:支持 macOS、Linux、Windows,甚至树莓派

第一步:环境准备

安装 Xcode Command Line Tools

llama.cpp 的编译需要 C/C++ 编译器,macOS 上通过安装 Xcode Command Line Tools 来获取:

# 检查是否已安装
xcode-select -p

# 如果未安装,执行以下命令安装
xcode-select --install

安装 Homebrew 和依赖工具

# 安装 Homebrew(如果尚未安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 安装编译依赖
brew install cmake git

# 验证安装
cmake --version
git --version

第二步:编译 llama.cpp(Metal GPU 加速)

克隆源码

# 克隆 llama.cpp 仓库
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp

使用 CMake 编译

在 macOS 上,Metal GPU 加速默认启用,无需额外设置任何编译参数。同时 Accelerate 框架(BLAS 加速)也会自动启用。

# 创建构建目录并编译(Metal 默认启用)
cmake -B build
cmake --build build --config Release -j 8

# -j 8 表示使用 8 个线程并行编译,加快编译速度
# M4 芯片有 10 核 CPU,可以根据需要调整线程数

编译完成后,可执行文件位于 build/bin/ 目录下。主要工具包括:

  • llama-cli:命令行交互式对话
  • llama-server:启动 HTTP API 服务
  • llama-quantize:模型量化工具
  • llama-convert:模型格式转换工具

验证 Metal GPU 加速

# 查看编译信息,确认 Metal 支持
./build/bin/llama-cli --help | grep metal

# 运行模型时会自动输出 Metal 信息:
# ggml_metal_init: allocating
# ggml_metal_init: found device: Apple M4
# ggml_metal_init: loading library

第三步:获取 GLM-4 GGUF 模型

方式一:下载预量化 GGUF 文件(推荐)

HuggingFace 上有社区已经转换好的 GLM-4 GGUF 模型,可以直接下载使用。推荐以下仓库:

# 安装 huggingface-cli 工具
pip install huggingface-hub

# 下载 GLM-4-9B-Chat Q4_K_M 量化版(推荐,6.3GB)
huggingface-cli download \
  bartowski/glm-4-9b-chat-GGUF \
  glm-4-9b-chat-Q4_K_M.gguf \
  --local-dir ./models

# 或者下载 Q5_K_M 版本(7.1GB,质量更高)
huggingface-cli download \
  bartowski/glm-4-9b-chat-GGUF \
  glm-4-9b-chat-Q5_K_M.gguf \
  --local-dir ./models

# 下载完成后验证文件
ls -lh models/*.gguf

方式二:从原始模型转换并量化

如果你想从 GLM-4 原始权重文件(safetensors 格式)自行转换,可以按以下步骤操作:

# 安装 Python 依赖
pip install -r requirements.txt

# 下载原始模型(约 19GB)
huggingface-cli download THUDM/glm-4-9b-chat --local-dir ./glm-4-original

# 转换为 GGUF 格式(FP16,约 19GB)
python convert_hf_to_gguf.py ./glm-4-original \
  --outfile ./models/glm-4-9b-chat-fp16.gguf

# 量化为 Q4_K_M(约 6.3GB)
./build/bin/llama-quantize \
  ./models/glm-4-9b-chat-fp16.gguf \
  ./models/glm-4-9b-chat-q4_k_m.gguf \
  Q4_K_M

第四步:运行 GLM-4 模型

命令行交互对话

# 基本运行(自动使用 Metal GPU 加速)
./build/bin/llama-cli \
  -m ./models/glm-4-9b-chat-Q4_K_M.gguf \
  -c 8192 \
  -n -1 \
  -i \
  --color

# 参数说明:
# -m          指定模型文件路径
# -c 8192     上下文窗口大小(tokens)
# -n -1       无限生成(直到模型自行结束)
# -i          交互模式
# --color     彩色输出

带系统提示词的对话

# 使用 GLM-4 的聊天模板
./build/bin/llama-cli \
  -m ./models/glm-4-9b-chat-Q4_K_M.gguf \
  -c 8192 \
  -i \
  --color \
  -sys "你是一个专业的中文编程助手,请用简洁准确的方式回答问题" \
  --chat-template chatglm

单次生成(非交互模式)

# 单次提示生成
./build/bin/llama-cli \
  -m ./models/glm-4-9b-chat-Q4_K_M.gguf \
  -c 2048 \
  -n 512 \
  -p "请用 Python 实现一个二分查找算法,并添加详细注释" \
  --no-display-prompt

第五步:启动 API 服务

启动 OpenAI 兼容 API

# 启动 HTTP 服务(兼容 OpenAI API 格式)
./build/bin/llama-server \
  -m ./models/glm-4-9b-chat-Q4_K_M.gguf \
  -c 8192 \
  --host 0.0.0.0 \
  --port 8080 \
  -np 4

# 参数说明:
# --host 0.0.0.0  监听所有网络接口(局域网可访问)
# --port 8080     服务端口
# -np 4           并行处理 4 个请求

测试 API 调用

# 使用 curl 调用 OpenAI 兼容接口
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-4",
    "messages": [
      {"role": "system", "content": "你是一个专业的AI助手"},
      {"role": "user", "content": "解释一下什么是链表数据结构"}
    ],
    "temperature": 0.7,
    "max_tokens": 1024
  }'

Python SDK 调用

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8080/v1",
    api_key="not-needed"
)

response = client.chat.completions.create(
    model="glm-4",
    messages=[
        {"role": "user", "content": "写一个 Python 装饰器示例"}
    ],
    temperature=0.7
)

print(response.choices[0].message.content)

第六步:性能调优

关键性能参数

参数说明推荐值
-nglGPU 层数(Metal 加速)99(全部放 GPU)
-c上下文窗口大小4096~8192
-b批处理大小512
-ub物理批处理大小512
-tCPU 线程数4~8
--mlock锁定模型在内存中(防止交换)推荐启用
--no-mmap禁用内存映射(加载更慢但运行更稳定)按需

优化运行示例

# 完整优化参数运行
./build/bin/llama-server \
  -m ./models/glm-4-9b-chat-Q4_K_M.gguf \
  -c 8192 \
  -ngl 99 \
  -b 512 \
  -ub 512 \
  -t 6 \
  --mlock \
  --host 0.0.0.0 \
  --port 8080

性能基准测试

# 运行性能基准测试
./build/bin/llama-bench \
  -m ./models/glm-4-9b-chat-Q4_K_M.gguf \
  -ngl 99 \
  -p 512 \
  -n 128

# 输出示例(MacBook Air M4 16GB):
# | model                          |       size |     params | backend    | ngl | test       |   t/s |
# | ------------------------------ | ---------: | ---------: | ---------- | --: | ---------- | ----: |
# | glm-4-9b-chat-Q4_K_M           |   6.30 GiB |     9.00 B | metal      |  99 | pp 512     | 120.5 |
# | glm-4-9b-chat-Q4_K_M           |   6.30 GiB |     9.00 B | metal      |  99 | tg 128     |  42.8 |

其中 pp(prompt processing)表示处理输入的速度,tg(token generation)表示生成输出的速度。42.8 tokens/s 意味着每秒可以生成约 40 个汉字,体验非常流畅。

第七步:后台常驻服务

使用 launchd 创建系统服务

# 创建 launchd 配置文件
cat > ~/Library/LaunchAgents/com.llamacpp.server.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.llamacpp.server</string>
    <key>ProgramArguments</key>
    <array>
        <string>/path/to/llama.cpp/build/bin/llama-server</string>
        <string>-m</string>
        <string>/path/to/models/glm-4-9b-chat-Q4_K_M.gguf</string>
        <string>-c</string>
        <string>8192</string>
        <string>-ngl</string>
        <string>99</string>
        <string>--host</string>
        <string>0.0.0.0</string>
        <string>--port</string>
        <string>8080</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/tmp/llamacpp.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/llamacpp-error.log</string>
</dict>
</plist>
EOF

# 加载服务
launchctl load ~/Library/LaunchAgents/com.llamacpp.server.plist

# 停止服务
launchctl unload ~/Library/LaunchAgents/com.llamacpp.server.plist

常见问题

1. 编译报错:找不到 cmake

# 确保 Homebrew 安装的 cmake 在 PATH 中
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

# 验证
which cmake
cmake --version

2. 运行时提示 Metal 不可用

# 检查 macOS 版本(需要 macOS 13.0+)
sw_vers

# 确认编译时启用了 Metal
cmake -B build -DGGML_METAL=ON
cmake --build build --config Release -j 8

# 如果仍然不行,检查 Metal 框架是否正常
# 系统报告 -> 图形/显示器 -> Metal

3. 内存不足导致系统卡顿

# 减小上下文窗口
./build/bin/llama-server -m model.gguf -c 2048 -ngl 99

# 限制 CPU 线程数(避免抢占系统资源)
./build/bin/llama-server -m model.gguf -c 4096 -ngl 99 -t 4

# 使用更小的量化版本
# Q3_K_M (5.1GB) 或 Q2_K (4.0GB)

性能对比:Ollama vs llama.cpp

对比项Ollamallama.cpp(手动编译)
安装难度⭐ 极简⭐⭐⭐ 需编译
性能优秀极致(可手动调优)
灵活性中等极高
模型管理内置管理手动管理
API 兼容OpenAI 兼容OpenAI 兼容
适合人群普通用户开发者/极客

总结

手动编译 llama.cpp 虽然步骤比 Ollama 多,但换来了更精细的控制能力。你可以自由调整 GPU 层数、批处理大小、线程数等参数,榨干 M4 芯片的每一分性能。同时 llama.cpp 的 HTTP 服务兼容 OpenAI API 格式,可以无缝集成到各种应用中。

在系列下一篇中,我们将探索 Apple 官方的 MLX 框架,这是专为 Apple Silicon 设计的机器学习框架,能为 GLM-4 模型提供最原生的 M4 芯片体验。

发表回复

后才能评论