使用 Apple MLX 框架在 M4 芯片上部署 GLM-4 模型(附三种方案对比)

在前两篇教程中,我们分别介绍了使用 Ollama 和 llama.cpp 在 MacBook Air M4 上部署 GLM-4 模型的方法。本文将介绍第三种方案——使用 Apple 官方的 MLX 框架。MLX 是专为 Apple Silicon 芯片设计的机器学习数组框架,能够充分利用 M4 芯片的统一内存架构和 Metal GPU,为 GLM-4 模型提供最原生的运行体验。

MLX 框架简介

MLX 是 Apple 官方开源的机器学习框架,于 2023 年底发布。与 PyTorch 类似,MLX 提供了张量计算、自动微分等功能,但专门针对 Apple Silicon 进行了深度优化:

  • 统一内存架构:MLX 原生支持 Apple Silicon 的统一内存,CPU 和 GPU 共享同一块内存,无需数据拷贝
  • 惰性计算:采用惰性求值策略,只在需要结果时才执行计算,自动优化计算图
  • 动态图:支持动态计算图,方便调试和灵活建模
  • 多设备支持:无缝在 CPU 和 GPU 之间切换
  • Python 友好:API 设计与 NumPy/PyTorch 高度相似,学习成本低

MLX-LM 是基于 MLX 构建的大语言模型推理库,原生支持 GLM-4、Llama、Qwen 等主流模型,无需额外适配即可直接运行。

第一步:环境搭建

确认系统要求

# 确认 macOS 版本(建议 macOS 14.0+)
sw_vers

# 确认 Python 版本(需要 3.9+)
python3 --version

# 确认芯片型号
sysctl -n machdep.cpu.brand_string

安装 Homebrew 和 Python

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

# 安装 Python 3.12
brew install python@3.12

# 验证安装
python3.12 --version

创建虚拟环境

# 创建项目目录
mkdir -p ~/mlx-glm && cd ~/mlx-glm

# 创建 Python 虚拟环境
python3.12 -m venv venv

# 激活虚拟环境
source venv/bin/activate

# 升级 pip
pip install --upgrade pip

第二步:安装 MLX-LM

# 安装 MLX 和 MLX-LM
pip install mlx-lm

# 验证安装
python -c "import mlx; print(f'MLX version: {mlx.__version__}')"
python -c "import mlx_lm; print('MLX-LM installed successfully')"

MLX-LM 已内置 GLM-4 模型架构支持(包括 glm.pyglm4.pyglm4_moe.py 等模型文件),无需安装任何额外依赖。

第三步:使用预转换的 GLM-4 MLX 模型

命令行快速运行

mlx-community 组织在 HuggingFace 上提供了大量已经转换为 MLX 格式的模型,可以直接下载使用:

# 使用预转换的 GLM-4-9B-Chat 4bit 模型
# 首次运行会自动从 HuggingFace 下载模型(约 5-6GB)
mlx_lm.generate \
  --model mlx-community/GLM-4-9B-Chat-4bit \
  --prompt "你好,请用中文介绍一下你自己" \
  --max-tokens 512

# 进入交互式聊天模式
mlx_lm.chat --model mlx-community/GLM-4-9B-Chat-4bit

指定生成参数

# 自定义生成参数
mlx_lm.generate \
  --model mlx-community/GLM-4-9B-Chat-4bit \
  --prompt "写一个 Python 冒泡排序算法" \
  --max-tokens 1024 \
  --temp 0.7 \
  --top-p 0.9

第四步:自行转换 GLM-4 模型

如果预转换模型不满足需求,你可以从 HuggingFace 上的原始 GLM-4 模型自行转换为 MLX 格式,并选择自定义的量化位数。

# 从原始模型转换为 4bit 量化 MLX 格式
mlx_lm.convert \
  --model THUDM/glm-4-9b-chat \
  --quantize \
  --q-bits 4 \
  --upload-repo mlx-community/my-glm4-4bit

# 参数说明:
# --model          HuggingFace 上的原始模型名称或本地路径
# --quantize       启用量化
# --q-bits 4       4bit 量化(也可选 2, 3, 6, 8)
# --upload-repo    上传到 HuggingFace(可选,不加则保存到本地)

# 转换并保存到本地目录
mlx_lm.convert \
  --model THUDM/glm-4-9b-chat \
  --quantize \
  --q-bits 4 \
  --mlx-path ./my-glm4-4bit

不同量化位数的效果对比:

量化位数模型大小质量损失适合内存
2-bit~2.5 GB较大8GB
3-bit~3.8 GB中等8GB
4-bit~5.2 GB较小8GB/16GB
6-bit~7.5 GB极小16GB
8-bit~9.8 GB几乎无16GB/24GB

第五步:Python API 开发

基础调用

from mlx_lm import load, generate

# 加载模型(首次会自动下载)
model, tokenizer = load("mlx-community/GLM-4-9B-Chat-4bit")

# 应用聊天模板
prompt = tokenizer.apply_chat_template(
    [{"role": "user", "content": "解释一下什么是闭包,并给出 Python 示例"}],
    add_generation_prompt=True
)

# 生成回复
response = generate(
    model,
    tokenizer,
    prompt=prompt,
    max_tokens=1024,
    verbose=True  # 打印生成速度等信息
)

print(response)

多轮对话

from mlx_lm import load, generate

model, tokenizer = load("mlx-community/GLM-4-9B-Chat-4bit")

# 维护对话历史
messages = [
    {"role": "system", "content": "你是一个专业的Python编程助手"}
]

def chat(user_input):
    messages.append({"role": "user", "content": user_input})
    
    prompt = tokenizer.apply_chat_template(
        messages,
        add_generation_prompt=True
    )
    
    response = generate(
        model,
        tokenizer,
        prompt=prompt,
        max_tokens=512,
        verbose=True
    )
    
    messages.append({"role": "assistant", "content": response})
    return response

# 多轮对话
print(chat("什么是装饰器?"))
print(chat("给我一个实际的使用例子"))
print(chat("装饰器和闭包有什么关系?"))

流式输出

from mlx_lm import load, stream_generate

model, tokenizer = load("mlx-community/GLM-4-9B-Chat-4bit")

prompt = tokenizer.apply_chat_template(
    [{"role": "user", "content": "写一首关于秋天的诗"}],
    add_generation_prompt=True
)

# 流式生成,逐 token 输出
for response in stream_generate(
    model,
    tokenizer,
    prompt=prompt,
    max_tokens=512
):
    print(response.text, end="", flush=True)

print()  # 换行

第六步:启动 OpenAI 兼容 API 服务

启动服务

# 启动兼容 OpenAI API 的本地服务
mlx_lm.server \
  --model mlx-community/GLM-4-9B-Chat-4bit \
  --host 0.0.0.0 \
  --port 8080

# 服务启动后,可通过 http://localhost:8080/v1 访问

使用 OpenAI SDK 调用

from openai import OpenAI

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

# 普通对话
response = client.chat.completions.create(
    model="mlx-community/GLM-4-9B-Chat-4bit",
    messages=[
        {"role": "user", "content": "什么是 Apple MLX 框架?"}
    ]
)
print(response.choices[0].message.content)

# 流式输出
stream = client.chat.completions.create(
    model="mlx-community/GLM-4-9B-Chat-4bit",
    messages=[
        {"role": "user", "content": "写一个 Python 异步爬虫示例"}
    ],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

第七步:高级优化

调整 Wired Memory 限制

对于大模型推理,macOS 默认的 Wired Memory 限制可能不够。可以通过以下命令临时调整(重启后失效):

# 查看当前 wired memory 限制
sysctl iogpu.wired_limit_mb

# 对于 16GB Mac,设置为 12GB(留 4GB 给系统)
sudo sysctl iogpu.wired_limit_mb=12288

# 对于 24GB Mac,设置为 18GB
sudo sysctl iogpu.wired_limit_mb=18432

# 恢复默认值
sudo sysctl iogpu.wired_limit_mb=0

使用 KV Cache 量化

from mlx_lm import load, generate

# 加载模型时启用 KV Cache 量化,减少内存占用
model, tokenizer = load(
    "mlx-community/GLM-4-9B-Chat-4bit",
    # MLX-LM 会自动管理 KV Cache
)

# 减小上下文窗口以节省内存
prompt = tokenizer.apply_chat_template(
    [{"role": "user", "content": "你好"}],
    add_generation_prompt=True
)

response = generate(
    model,
    tokenizer,
    prompt=prompt,
    max_tokens=256,
    verbose=True
)

指定使用 GPU 或 CPU

import mlx.core as mx
from mlx_lm import load, generate

# 默认使用 GPU
# 可以手动切换到 CPU(不推荐,性能会大幅下降)
# mx.set_default_device(mx.Device(mx.DeviceType.CPU))

# 加载模型并生成
model, tokenizer = load("mlx-community/GLM-4-9B-Chat-4bit")

# 检查当前使用的设备
print(f"Default device: {mx.default_device()}")

prompt = tokenizer.apply_chat_template(
    [{"role": "user", "content": "1+1等于几?"}],
    add_generation_prompt=True
)

response = generate(model, tokenizer, prompt=prompt, max_tokens=64, verbose=True)
print(response)

三种部署方案全面对比

对比项Ollamallama.cppMLX-LM
安装难度⭐ 极简⭐⭐⭐ 需编译⭐⭐ pip 安装
性能表现优秀极致优秀
GPU 加速MetalMetalMetal(原生)
内存效率最佳(统一内存)
Python API通过 HTTP通过 HTTP原生 Python
模型量化预定义灵活(Q2~Q8)灵活(2~8bit)
自定义训练不支持不支持支持(LoRA 微调)
社区生态庞大庞大快速增长
适合人群普通用户开发者/极客Python 开发者
OpenAI 兼容

性能基准对比

以下是在 MacBook Air M4(16GB)上运行 GLM-4-9B-Chat Q4 量化版本的参考性能数据:

方案加载时间Prompt 处理 (t/s)生成速度 (t/s)内存占用
Ollama~3s~110~40~7GB
llama.cpp~2s~120~43~6.5GB
MLX-LM~4s~100~45~6GB

注:以上数据为参考值,实际性能受 macOS 版本、后台进程、环境温度等因素影响。

方案选择建议

  • 新手用户:选择 Ollama,两条命令搞定,开箱即用
  • 追求极致性能:选择 llama.cpp,可精细调优每个参数
  • Python 开发者:选择 MLX-LM,原生 Python API,方便集成到项目中
  • 需要模型微调:选择 MLX-LM,支持 LoRA 等微调技术
  • 需要 API 服务:三种方案都支持 OpenAI 兼容 API,按需选择

系列总结

本系列三篇文章完整介绍了在 MacBook Air M4 上部署 GLM-4 模型的三种方案:

  1. Ollama 方案(入门篇):最简单的一键部署方案,适合新手
  2. llama.cpp 方案(进阶篇):手动编译 Metal 加速,追求极致性能
  3. MLX 方案(高级篇):Apple 官方框架,原生 Python 开发体验

MacBook Air M4 凭借其强大的 M4 芯片、Metal GPU 加速和统一内存架构,已经完全具备在本地流畅运行 9B 参数大语言模型的能力。无论你是想保护隐私数据、节省 API 费用,还是进行 AI 应用开发,MacBook Air M4 都是一个出色的本地 AI 推理平台。

希望这个系列教程能帮助你顺利在 MacBook Air M4 上部署 GLM-4 模型。如果你在操作过程中遇到任何问题,欢迎在评论区留言交流!

发表回复

后才能评论