很多新手开发者想在自己电脑上跑大模型,却觉得门槛高。其实用苹果 M2 Pro + MLX 框架,32GB 内存就能跑 32B 参数的 Qwen2.5-Coder 模型,速度 12-20 tokens/s,完全本地、无需网络。
下面是完整从零到实战的路径,附带机制拆解。
1. 硬件与模型选择
配置:Apple M2 Pro(19 核 GPU)、32GB 统一内存。
推荐模型:mlx-community/Qwen2.5-Coder-32B-Instruct-4bit
- 4bit 量化后只占 18-22GB 内存
- 专为代码和 Agent 优化,Tool Calling 能力强
- MLX 原生支持 Metal 4,速度和功耗最优
2. 环境搭建(5 分钟)
用 pip3 即可:
bash
python3 -m venv ~/mlx-env
source ~/mlx-env/bin/activate
pip3 install --upgrade pip
pip3 install mlx-lm
以后每次新开终端,先执行 source ~/mlx-env/bin/activate 进入环境。
3. 首次下载模型(必看,自动触发)
首次运行任何 mlx_lm 命令时,会自动下载模型权重:
bash
# 推荐用这个命令安全触发下载(只下载不聊天)
mlx_lm.generate --model mlx-community/Qwen2.5-Coder-32B-Instruct-4bit --prompt "hello" --max-tokens 10
- 下载大小:18.4 GB(.safetensors 权重文件)
- 下载时间:普通家用宽带 3-8 分钟,慢速网络或高峰期可能 10-20 分钟
- 存储位置:
~/.cache/huggingface/hub/models--mlx-community--Qwen2.5-Coder-32B-Instruct-4bit - 磁盘要求:确保至少 25GB 空闲空间
- 后续运行无需重复下载(下次秒开)
下载完成后模型就永久保存在本地。
4. 命令行直接运行模型
下载完成后,进入环境执行:
bash
# 交互聊天(推荐)
mlx_lm.chat --model mlx-community/Qwen2.5-Coder-32B-Instruct-4bit --temp 0.7 --context-length 32768
输入问题即可实时对话。退出输入 /exit。
单次生成用 mlx_lm.generate 加 --prompt。

图1:Decoder-only Transformer 结构(Qwen 正是这种架构,每层做 Masked Self-Attention + FFN)
5. LLM 运行机制:Transformer 执行器 + 权重
LLM 本质只有两部分:
- 架构 :Transformer 代码(mlx-lm 里
models/qwen2.py已实现) - 权重:320 亿个数字(18.4GB 文件,训练好的参数)
mlx-lm 就是执行器:加载权重到 GPU,按 Transformer 规则一步步计算输出。它不是编译源代码,只是把预训练好的权重加载运行。
6. KV Cache:生成加速的核心
生成文字是"每次只出一个词,再把新词加回去继续生成"。
没有 KV Cache 时,每次都要重新算前面所有词的 Key/Value,速度极慢。
KV Cache 把历史 Key 和 Value 存起来,下次只算新词,速度提升 3-10 倍。
你的 32k 上下文全靠它实现。

图2:有/无 KV Cache 的对比(紫色部分直接从缓存拿,省去重复计算)
7. mlx-lm 内部具体做了什么
每次运行,mlx-lm 按顺序执行 7 步:
- 加载权重到 GPU
- 把提示词转成 token ID
- Prefill:一次性算完整个提示词,建好 KV Cache
- Decode 循环:每次只输入上一个词,用 KV Cache 计算新词
- 采样下一个词
- 转回文字输出
- KV Cache 自动追加

图3:Prefill(黄色)+ Decode(红色)完整流程(TTFT 是首字延迟,后续飞快)
想看真实过程,运行下面测试脚本:
bash
cat > test_flow.py << 'EOF'
from mlx_lm import load, stream_generate
model, tokenizer = load("mlx-community/Qwen2.5-Coder-32B-Instruct-4bit")
prompt = tokenizer.apply_chat_template([{"role":"user","content":"写个 Python 函数"}], add_generation_prompt=True)
for resp in stream_generate(model, tokenizer, prompt, verbose=True):
print(resp.text, end="", flush=True)
EOF
python test_flow.py
8. 实战:5 分钟做一个能控制浏览器和 Shell 的 Agent
安装浏览器依赖:
bash
pip3 install playwright
playwright install chromium
创建 Agent(48 行)并运行:
bash
cat > ~/mini_openclaw_agent.py << 'EOF'
from mlx_lm import load, generate
import subprocess
from playwright.sync_api import sync_playwright
import re
model, tokenizer = load("mlx-community/Qwen2.5-Coder-32B-Instruct-4bit")
SYSTEM = """你是简易 OpenClaw Agent。需要工具时严格输出:
<tool>shell_exec</tool><arg>命令</arg>
或
<tool>browser_open</tool><arg>URL</arg>"""
history = [{"role": "system", "content": SYSTEM}]
def execute_tool(tool, arg):
if tool == "shell_exec":
return subprocess.check_output(arg, shell=True, text=True, timeout=15).strip()
elif tool == "browser_open":
with sync_playwright() as p:
page = p.chromium.launch().new_page()
page.goto(arg)
return page.title()
while True:
user = input("\n你: ")
if user in ["exit", "quit"]: break
history.append({"role": "user", "content": user})
prompt = tokenizer.apply_chat_template(history, add_generation_prompt=True)
response = generate(model, tokenizer, prompt=prompt, max_tokens=512, temp=0.7)
match = re.search(r'<tool>(.*?)</tool>\s*<arg>(.*?)</arg>', response, re.DOTALL)
if match:
tool, arg = match.group(1).strip(), match.group(2).strip()
print(f"\n执行工具 {tool}({arg})")
result = execute_tool(tool, arg)
print(result)
history.append({"role": "tool", "content": result})
else:
print(response)
history.append({"role": "assistant", "content": response})
EOF
python ~/mini_openclaw_agent.py
输入"打开 https://x.ai 并告诉我标题"或"列出当前目录文件",Agent 就会自动执行。
总结
现在你已经:
- 完成首次下载并跑起 32B 模型
- 看懂了 Transformer + KV Cache + Prefill/Decode 机制
- 拥有一个能控制电脑的简易 Agent
本地 LLM 没有想象中难,动手跑起来就是最好的入门。后续想加工具或开机自启,直接扩展这套框架即可。