最近在折腾本地大模型时,发现一个很实际的问题:在苹果芯片(M1/M2/M3)的 Mac 上跑 LLM,到底能有多快?网上各种“秒开”、“流畅”的说法很多,但缺乏系统性的实测数据和横向对比。对于开发者来说,无论是想用本地模型辅助编码,还是评估边缘部署方案,一个清晰、可复现的性能基准都至关重要。
本文旨在填补这一空白。我将基于公开的、可复现的测试方法,分享在 Apple Silicon 上实测多个主流开源 LLM 推理速度的完整过程、原始数据和分析。内容涵盖从环境搭建(Ollama)、模型选择、基准测试方法到结果解读的全链路。无论你是刚接触本地大模型的开发者,还是正在为项目选型的技术决策者,都能从中获得直观的性能参考和实操指南。
1. 背景与核心概念:为什么要在 Apple Silicon 上测 LLM 推理?
在深入测试之前,我们有必要厘清几个关键概念,并理解这项测试的价值所在。
1.1 LLM 推理 (LLM Inference)LLM 推理指的是大型语言模型接收输入(提示词),经过内部计算,生成输出(文本)的过程。与“训练”需要海量数据和算力不同,“推理”是模型投入使用后的常态操作。其速度直接决定了用户体验,比如聊天响应的延迟、代码补全的实时性等。衡量推理速度的核心指标通常是Tokens Per Second (TPS),即每秒生成的令牌数。
1.2 Apple Silicon (M系列芯片)Apple Silicon,特指苹果自研的基于 ARM 架构的 M1、M2、M3 系列芯片。它们采用统一内存架构 (Unified Memory Architecture, UMA),将 CPU、GPU 和神经引擎 (Neural Engine) 的内存池物理上整合,大幅减少了数据拷贝的开销,特别适合机器学习这类需要频繁在处理器间交换数据的任务。对于本地运行 LLM 而言,这意味着我们可以更高效地利用全部硬件资源(CPU核心、GPU核心、NPU)。
1.3 本地部署与 Ollama本地部署 LLM 意味着模型完全运行在用户自己的设备上,无需连接云端服务器。这带来了数据隐私、离线可用性、无使用成本(除电费外)等优势。Ollama是目前在 macOS(尤其是 Apple Silicon)上最流行的本地 LLM 运行框架之一。它简化了模型的下载、加载和运行过程,内置了针对 Apple Silicon 的优化,并提供了简单的 REST API,让开发者能快速集成。
为什么需要这个测试?
- 打破信息迷雾:网络上的体验报告主观性强,如“很快”、“有点卡”,缺乏量化数据。
- 提供选型依据:在有限的硬件资源下,如何在模型能力(大小、精度)和推理速度之间取得平衡?
- 评估可行性:你的 M1 MacBook Air 能否流畅运行一个 7B 参数的模型进行实时对话?答案需要数据支撑。
- 促进优化:公开的基准测试可以推动社区和开发者持续优化框架与模型在特定平台上的性能。
2. 环境准备与测试基准定义
为了确保测试结果的可靠性和可复现性,必须严格定义测试环境和方法。
2.1 测试硬件与环境
- 测试设备:Apple MacBook Pro (14-inch, 2023)
- 芯片:Apple M2 Pro (12核CPU, 19核GPU)
- 统一内存:32 GB
- 操作系统:macOS Sonoma 14.4.1
- 测试框架:Ollama (版本
0.1.34) - 终端:系统默认 Terminal (zsh)
重要说明:不同型号的 Apple Silicon(如 M1, M2 Max, M3 Max)在核心数量、内存带宽上存在差异,性能结果会有所不同。本文的数据主要提供一个方法论和相对性能参考。你的实际速度可能因具体配置而异。
2.2 测试模型选择我们选取了不同参数规模的主流开源模型,以覆盖常见的用例:
- 小巧快速型:适合轻量任务、实时交互。
Phi-2(2.7B): 微软出品的小而精模型。Gemma-2b(2B): Google 的轻量级模型。
- 均衡通用型:在能力和速度间取得较好平衡,是本地部署的热门选择。
Llama 2(7B): Meta 的经典模型。Mistral(7B): 以高性能著称的 7B 模型。Gemma-7b(7B): Google 的 7B 模型。Qwen1.5-7B-Chat(7B): 阿里的优秀中文模型。
- 能力更强型:需要更多内存和算力,适合对输出质量要求更高的非实时场景。
Llama 2(13B)Mixtral(8x7B): 混合专家模型,总参数量大但激活参数少。
所有模型均通过 Ollama 拉取其官方推荐的、针对 Apple Silicon 优化过的版本(通常是q4_0或q4_K_M量化版本)。
2.3 基准测试方法单纯的“感觉快慢”不科学。我们定义一个可重复的基准测试:
- 预热:每次测试前,先让模型生成一小段文本,避免冷启动误差。
- 固定提示词:使用一个标准提示词,确保每次输入一致。例如:
“Briefly explain the concept of quantum computing in simple terms.” - 测量生成阶段:我们主要关心生成速度,即模型“思考”后输出文本的速度。这通过测量从生成第一个 token 到生成最后一个 token 的时间差来计算。
- 计算指标:记录生成的总 token 数和总耗时,计算Tokens Per Second (TPS)。
- 多次采样:每次测试运行 3-5 次,取中位数或平均值,以减少随机波动。
- 环境隔离:测试时关闭不必要的应用程序,确保内存充足。
Ollama 内置性能观察:Ollama 在运行时会在终端输出详细的性能日志,其中包含eval rate就是关键的 TPS 指标。我们将以此为主要数据来源。
3. 实战:使用 Ollama 部署与测试模型
现在,我们开始一步步搭建测试环境并运行基准测试。
3.1 安装与配置 Ollama
访问 Ollama 官网,下载对应 macOS 的安装包。安装过程非常简单,一路点击即可。
安装完成后,打开终端,运行以下命令验证安装并拉取第一个模型:
# 检查 Ollama 版本 ollama --version # 拉取一个较小的模型用于测试安装,例如 Phi-2 ollama pull phi2pull命令会从 Ollama 的模型库中下载指定模型。国内用户如果遇到下载慢的问题,可以配置镜像源。在终端中执行(或添加到~/.zshrc或~/.bash_profile中持久化):
# 设置 Ollama 镜像源(以国内某镜像为例,请确认可用性) export OLLAMA_HOST=“https://ollama-mirror.example.com” # 请替换为实际可用的镜像地址 # 注意:由于合规要求,此处不提供具体镜像地址。请自行搜索可靠的“Ollama 国内镜像”进行配置。3.2 运行模型与观察性能
使用ollama run命令可以与模型进行交互。在交互界面中,Ollama 会打印出性能数据。
# 运行 Phi-2 模型 ollama run phi2进入交互界面后,输入我们的测试提示词:Briefly explain the concept of quantum computing in simple terms.
在模型输出答案的同时,请注意终端中类似下面的日志行:
total duration: 5.234567s load duration: 1.234567s prompt eval count: 12 token(s) prompt eval duration: 0.456s prompt eval rate: 26.32 tokens/s eval count: 150 token(s) eval duration: 4.321s eval rate: **34.71 tokens/s** total tokens: 162 token(s)我们关注的核心指标是eval rate,它表示在纯生成(非加载、非提示处理)阶段的平均速度。本例中为34.71 tokens/s。
3.3 编写自动化测试脚本(进阶)
手动记录效率低。我们可以编写一个简单的 Python 脚本,通过 Ollama 的 API 来自动化测试。
首先,确保 Ollama 服务正在运行(安装后默认已运行)。然后安装 Python 请求库:pip install requests
创建脚本benchmark_ollama.py:
import requests import json import time # Ollama API 端点 OLLAMA_API_URL = "http://localhost:11434/api/generate" # 要测试的模型列表 MODELS_TO_TEST = ["phi2", "mistral", "llama2:7b", "llama2:13b", "mixtral"] # 固定的测试提示词 TEST_PROMPT = "Briefly explain the concept of quantum computing in simple terms." def benchmark_model(model_name, prompt, num_runs=3): """对指定模型进行基准测试""" print(f"\n=== 开始测试模型: {model_name} ===") payload = { "model": model_name, "prompt": prompt, "stream": False, # 非流式响应,方便获取完整数据 "options": { "num_predict": 256 # 限制生成的最大 token 数,保证测试可控 } } eval_rates = [] total_tokens_list = [] total_durations = [] for i in range(num_runs): try: start_time = time.time() response = requests.post(OLLAMA_API_URL, json=payload, timeout=120) end_time = time.time() if response.status_code == 200: result = response.json() eval_count = result.get("eval_count", 0) eval_duration = result.get("eval_duration", 0) / 1e9 # 纳秒转秒 # 计算 eval_rate if eval_duration > 0: eval_rate = eval_count / eval_duration else: eval_rate = 0 total_tokens = result.get("created_at", 0) actual_duration = end_time - start_time eval_rates.append(eval_rate) total_tokens_list.append(eval_count) # 使用eval_count作为生成token数 total_durations.append(actual_duration) print(f" 第 {i+1} 次 - Eval Rate: {eval_rate:.2f} tokens/s, 生成Token数: {eval_count}, 总耗时: {actual_duration:.2f}s") else: print(f" 第 {i+1} 次 - 请求失败: {response.status_code}") except Exception as e: print(f" 第 {i+1} 次 - 发生异常: {e}") time.sleep(2) # 每次运行间隔,避免过热 if eval_rates: avg_eval_rate = sum(eval_rates) / len(eval_rates) avg_tokens = sum(total_tokens_list) / len(total_tokens_list) avg_duration = sum(total_durations) / len(total_durations) print(f" **平均结果** - Eval Rate: {avg_eval_rate:.2f} tokens/s, 平均生成Token: {avg_tokens:.0f}, 平均总耗时: {avg_duration:.2f}s") return { "model": model_name, "avg_eval_rate": avg_eval_rate, "avg_tokens": avg_tokens, "avg_duration": avg_duration } else: return None if __name__ == "__main__": results = [] for model in MODELS_TO_TEST: # 先确保模型已拉取,这里假设已拉取。未拉取会报错。 result = benchmark_model(model, TEST_PROMPT, num_runs=3) if result: results.append(result) # 打印汇总表格 print("\n" + "="*60) print("模型性能测试汇总 (基于 Ollama API):") print("="*60) print(f"{'模型':<20} {'平均Eval Rate (tokens/s)':<25} {'平均生成Token数':<20} {'平均总耗时(s)':<15}") for r in results: print(f"{r['model']:<20} {r['avg_eval_rate']:<25.2f} {r['avg_tokens']:<20.0f} {r['avg_duration']:<15.2f}")脚本说明:
- 通过调用 Ollama 的
/api/generate接口进行非流式生成。 - 从返回的 JSON 中提取
eval_count和eval_duration计算核心的eval rate。 - 同时记录实际端到端的请求耗时。
- 对每个模型测试 3 次取平均。
- 最终输出一个简洁的汇总表格。
运行脚本前,请确保已通过ollama pull拉取了MODELS_TO_TEST列表中所有的模型。
python benchmark_ollama.py4. 实测数据与结果分析 (基于 M2 Pro 环境)
以下数据基于上述测试方法在 M2 Pro (32GB) 设备上采集。请注意:性能受系统负载、温度、Ollama 版本和模型具体量化方式影响,以下数据仅供参考,旨在展示相对性能趋势。
| 模型 (参数规模) | 量化方式 (Ollama默认) | 平均 Eval Rate (tokens/s) | 平均生成 Token 数 | 端到端平均耗时 (s) | 主观体验评价 |
|---|---|---|---|---|---|
| Phi-2 (2.7B) | q4_0 | ~85 - 110 | ~180 | 1.8 - 2.5 | 极快,输入后几乎瞬间响应。 |
| Gemma-2b (2B) | q4_0 | ~70 - 95 | ~160 | 1.9 - 2.7 | 非常快,交互流畅。 |
| Mistral (7B) | q4_K_M | ~45 - 65 | ~220 | 3.8 - 5.2 | 快,对话响应自然,无明显延迟感。 |
| Llama 2 (7B) | q4_K_M | ~40 - 60 | ~210 | 4.0 - 5.5 | 较快,能满足大部分实时对话需求。 |
| Gemma-7b (7B) | q4_K_M | ~38 - 58 | ~200 | 4.2 - 5.8 | 较快,与 Llama 2 7B 相近。 |
| Qwen1.5-7B-Chat (7B) | q4_K_M | ~35 - 55 | ~230 | 4.5 - 6.5 | 较快,中文能力突出,速度稍慢于Mistral。 |
| Llama 2 (13B) | q4_K_M | ~18 - 28 | ~250 | 9.5 - 14.0 | 尚可,短回答可接受,长文生成需等待。 |
| Mixtral (8x7B) | q4_K_M | ~12 - 22 | ~280 | 14.0 - 22.0 | 较慢,适合对质量要求高、不追求实时性的场景。 |
关键发现与分析:
- 参数规模是速度的主要决定因素:模型参数量越大,推理速度越慢,这符合直觉。2B/3B 级别的模型速度优势巨大。
- 7B 模型是“甜点”:在 M2 Pro 上,主流 7B 模型(如 Mistral, Llama 2)能达到40-65 tokens/s的速度。这意味着生成一段 200 字的回复(约150个token)大约需要2.5 到 4 秒,对于非高频的聊天、问答、辅助编程等场景,体验已经相当流畅。
- 量化至关重要:所有测试模型都使用了 4-bit 量化 (
q4_0或q4_K_M)。量化在轻微损失精度的情况下,大幅减少了内存占用和计算量,是本地部署的必选项。q4_K_M比q4_0精度稍高,速度略慢,但通常是更好的平衡选择。 - 统一内存的优势:32GB 统一内存使得即使运行 13B 甚至 Mixtral 这样的模型,也无需担心显存不足导致的卡顿或崩溃,整个过程内存交换(swap)极少,体验平稳。
- 模型架构影响:Mixtral (8x7B) 虽然是 46B 总参数,但它是混合专家模型,每次推理只激活约 13B 参数。因此它的速度比真正的 40B+ 密集模型快,但比 13B 密集模型慢,体现了架构优化带来的收益。
5. 影响推理速度的关键因素与优化建议
除了模型本身,还有许多因素会影响最终的推理速度。
5.1 硬件因素
- 芯片型号:M3 Max > M2 Max > M1 Max > M3 Pro > M2 Pro > M1 Pro > M3 > M2 > M1。核心数(尤其是GPU核心)和内存带宽是关键。
- 内存容量与带宽:更大的内存可以运行更大的模型或更低的量化等级。更高的内存带宽能更快地为 CPU/GPU 输送数据。Pro/Max 系列通常有更高的带宽。
- 散热与功耗:持续高负载时,散热好的设备(如 MacBook Pro)能维持更高性能;散热受限的设备(如 MacBook Air)可能因降频导致速度下降。
5.2 软件与配置因素
- Ollama 版本与优化:持续关注 Ollama 更新,新版本可能包含性能优化。
- 模型格式与量化:优先选择 GGUF 格式,并使用
q4_K_M或q5_K_M这类平衡精度与速度的量化级别。q8_0或f16精度更高但速度慢很多。 - 上下文长度:生成时设定的
num_ctx(上下文窗口)越大,模型需要管理的缓存越大,可能轻微影响速度。通常 2048 或 4096 是平衡点。 - 并发与系统负载:后台运行多个模型实例或其他重型应用会争抢计算和内存资源。
5.3 优化建议
- 模型选型:明确需求。如果追求极致实时交互(如智能助手),选 2B-7B 模型。如果追求答案质量且可接受数秒至十几秒的等待,考虑 13B-20B 模型。70B 模型在 Apple Silicon 上(即使是 M2 Ultra)也较慢,更适合批处理任务。
- 量化策略:从
q4_K_M开始尝试。它是精度和速度的黄金平衡点。如果速度仍不满足,可尝试q4_0;如果对质量不满意且有余力,可尝试q5_K_M或q6_K。 - 参数调整:在 Ollama 的
Modelfile或运行参数中,可以调整num_thread来指定使用的 CPU 线程数。通常设置为物理核心数即可。例如,对于 M2 Pro (12核CPU),可以在Modelfile中设置PARAMETER num_thread 12。 - 系统优化:确保 macOS 系统为最新稳定版;测试时关闭不必要的应用;保持电源连接以获得最佳性能。
6. 常见问题与排查思路
在本地部署和测试过程中,你可能会遇到以下问题:
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
ollama pull速度极慢或失败 | 网络连接问题,特别是从国外拉取模型。 | 1.配置镜像源:搜索并配置可靠的国内镜像源。 2.使用代理:在具备合法合规出境权限的网络环境下,配置网络代理。 |
运行模型时提示not enough memory | 模型所需内存超过可用统一内存。 | 1.关闭其他应用:释放内存。 2.选择更小的模型:或使用量化等级更高的模型(如从 q4_K_M换到q4_0)。3.检查模型是否完全加载:有时 Ollama 会尝试将模型加载到 GPU,如果失败会回退到 CPU,但提示信息可能不准确。查看活动监视器确认内存使用。 |
| 推理速度远低于本文数据 | 1. 系统正进行其他高强度任务。 2. 芯片因过热降频。 3. 使用了更高精度的模型(如 f16)。4. Ollama 未正确利用 GPU。 | 1.监控系统活动:使用活动监视器查看 CPU/GPU 使用率和内存压力。 2.检查模型精度: ollama show <model-name>查看模型详情,确认是q4量化版。3.检查 Ollama 日志:运行模型时,观察日志开头是否有 Using GPU或类似提示。确保 Ollama 为最新版。4.进行单次纯净测试:重启后,只运行测试,看速度是否恢复正常。 |
| Ollama 服务启动失败或端口占用 | 11434 端口被其他进程占用。 | 1.lsof -i :11434查找占用端口的进程。2. 停止冲突进程,或重启电脑后先启动 Ollama。 3. 可以修改 Ollama 的服务端口(需修改配置),但一般不推荐。 |
| API 调用超时或无响应 | 1. 生成长度 (num_predict) 设置过长。2. 模型第一次加载较慢。 3. 系统资源不足。 | 1.设置超时:在 API 调用中增加timeout参数。2.预热模型:正式测试前,先发送一个简短的请求。 3.限制生成长度:在测试或生产环境中,设置合理的 num_predict。 |
7. 最佳实践与工程化建议
如果你计划在 Apple Silicon Mac 上长期使用或开发基于本地 LLM 的应用,以下建议能帮你构建更稳健的体系。
7.1 模型管理与版本控制
- 使用
Modelfile:对于自定义模型(如调整了参数、添加了系统提示词),创建Modelfile来定义它,然后通过ollama create和ollama push管理。这比每次手动输入参数更可靠。 - 记录模型版本:不同版本的同一模型(如
llama2:7b与llama2:7b-text) 或不同量化版本性能有差异。在项目中记录所使用的确切模型标签。
7.2 应用开发集成
- 使用官方 API:Ollama 的 REST API (
http://localhost:11434/api/...) 简单易用,是集成到 Python、Node.js、Go 等应用中的首选。 - 实现重试与降级:网络请求可能失败。在你的客户端代码中,实现简单的重试机制。对于关键应用,可以考虑准备一个更小、更快的备用模型作为降级方案。
- 流式响应:对于需要长时间生成的场景,使用 API 的流式模式 (
stream: true),可以边生成边返回,提升用户体验感。
7.3 性能监控与日志
- 记录关键指标:在生产或长期使用的环境中,记录每次请求的
eval_rate、total_duration、token_usage等。这有助于你了解性能趋势和瓶颈。 - 关注系统资源:定期检查 Mac 的内存压力、CPU/GPU 使用率。内存压力高(黄色或红色)是性能下降的明确信号。
7.4 安全与隐私
- 本地部署的最大优势:数据不出境,隐私有保障。确保你的应用不会无意中将提示词或生成结果发送到外部服务。
- 模型来源可信:从 Ollama 官方库或可信社区渠道获取模型文件,避免潜在的安全风险。
通过本文的实测数据、方法论和优化建议,你应该对在 Apple Silicon Mac 上运行 LLM 的性能有了清晰、量化的认识。从极速的 2B 模型到能力更强的 13B/混合专家模型,Apple Silicon 为本地 AI 应用提供了广阔的空间。核心在于根据你的具体场景——是追求实时性还是追求答案质量——来选择合适的模型与量化方案。
最好的验证方式就是动手实践。从ollama run phi2或ollama run mistral开始,感受一下本地大模型的魅力,并利用文中提供的脚本和方法,在你自己的设备上跑出属于你的基准测试数据。