MacOS 上使用 Metal GPU 加速编译 llama.cpp 完整指南

本文详细记录了在 MacOS 上使用 Metal GPU 加速编译 llama.cpp 的全过程,涵盖 cmake 安装、仓库克隆、编译配置、模型下载、GPU 验证、多模型运行测试以及性能监控工具的使用,适合需要在 Apple Silicon Mac 上本地运行大语言模型的开发者参考。

1.安装cmake

bash 复制代码
brew install git cmake


2.克隆仓库

bash 复制代码
git clone https://github.com/ggml-org/llama.cpp.git

cd llama.cpp

3. 编译(开启 Metal GPU 加速)

bash 复制代码
cmake -B build -DGGML_METAL=ON -DGGML_METAL_EMBED_LIBRARY=ON
cmake --build build --config Release -j$(sysctl -n hw.ncpu)



4.模型下载

bash 复制代码
# 安装模型下载客户端
pip install modelscope

# 下载模型
modelscope download \
  --model Tencent-Hunyuan/HY-MT1.5-7B-GGUF HY-MT1.5-7B-Q4_K_M.gguf License.txt README.md configuration.json \
  --local_dir ./HY-MT1.5-7B-Q4_K_M-GGUF

5. 验证 GPU 是否启用

bash 复制代码
./llama-cli --help
模型启动参数说明
bash 复制代码
./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.5-2B-GGUF/Qwen3.5-2B-Q4_K_M.gguf \
  -c 8192 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja 

-m 指定模型权重文件 model
-c 模型上下文 context length
-ngl 加载模型的多少层到GPU number of GPU layers
--host 指定访问的IP地址
--port 指定访问的端口号,访问的模型是通过端口号指定的,不需要传递模型名
--temp 温度,temperature
--jinja Qwen模型启动的时候,不添加 qwen3_nonthinking.jinja 这个文件,默认启动思考模式,添加这个文件可以关闭思考模型 
bash 复制代码
cd /Users/zephyrmuse/Git_projects/llama.cpp/build/bin 
     
# Qwen3.5-2B-Q4_K_M (多模态)     
./llama-cli \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.5-2B-GGUF/Qwen3.5-2B-Q4_K_M.gguf \
  -c 8192 \
  -n 512 \
  -p "你好,请用中文自我介绍" \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja
  

./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.5-2B-GGUF/Qwen3.5-2B-Q4_K_M.gguf \
  -c 8192 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja      
     
     
# Qwen3.5-4B-Q4_K_M (多模态)     
./llama-cli \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.5-4B-Q4_K_M-GGUF/qwen3-5-4B-Q4_K_M.gguf \
  -c 8192 \
  -n 512 \
  -p "你好,请用中文自我介绍" \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja 
  
    
     
  # Qwen3.5-4B-Q4_K_M (多模态) 
  ./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.5-4B-Q4_K_M-GGUF/qwen3-5-4B-Q4_K_M.gguf \
  -c 8192 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja
  
  
  
 # HY-MT1.5-7B-Q4_K_M-GGUF (翻译模型) 
 ./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/HY-MT1.5-7B-Q4_K_M-GGUF/HY-MT1.5-7B-Q4_K_M.gguf \
  -c 8192 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 
  
  
# Qwen3.6-35B-A3B-UD-Q3_K_XL.gguf

./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.6-35B-A3B-GGUF/Qwen3.6-35B-A3B-UD-Q3_K_XL.gguf \
  -c 8192 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja
  
  
# Qwen3.6-35B-A3B-UD-Q5_K_S.gguf
./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.6-35B-A3B-GGUF/Qwen3.6-35B-A3B-UD-Q5_K_S.gguf \
  -c 8192 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja
  
# Qwen3.6-35B-A3B-UD-Q5_K_M.gguf
./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.6-35B-A3B-GGUF/Qwen3.6-35B-A3B-UD-Q5_K_M.gguf \
  -c 2048 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja
  
# Qwen3.6-35B-A3B-UD-Q4_K_S.gguf
./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.6-35B-A3B-GGUF/Qwen3.6-35B-A3B-UD-Q4_K_S.gguf \
  -c 2048 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja

# 支持多模态
./llama-server \
  -m /Users/zephyrmuse/Projects/softwares/Qwen3.6-35B-A3B-GGUF/Qwen3.6-35B-A3B-UD-Q4_K_S.gguf \
  --mmproj /Users/zephyrmuse/Projects/softwares/Qwen3.6-35B-A3B-GGUF/mmproj-BF16.gguf \
  -c 2048 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja

# Qwen3.5-27B.Q6_K.gguf  3 tokens/s
./llama-server \
  -m  /Users/zephyrmuse/Projects/softwares/Qwen3.5-27B-Claude-4.6-Opus-Reasoning-Distilled-v2-GGUF/Qwen3.5-27B.Q6_K.gguf \
  -c 8192 \
  -ngl 99 \
  --host 0.0.0.0 \
  --port 8080 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --temp 0.7 \
  --jinja \
  --chat-template-file /Users/zephyrmuse/Projects/softwares/qwen3_nonthinking.jinja
  



6.测试脚步

python 复制代码
import os
import time
from openai import OpenAI
from get_system_prompt import get_system_prompt

# 初始化 OpenAI 客户端,指向本地 llama-server
client = OpenAI(
    base_url="http://localhost:8080/v1",
    api_key="sk-no-key-required"  # 本地服务不需要真实 API Key
)

# 获取系统提示词
# system_prompt = get_system_prompt()
system_prompt = "你是一个乐于助人的智能助手"

# 创建对话历史存储
messages = [{"role": "system", "content": system_prompt}]

# Token 估算函数(简化版:中文约 1.5 字符/token,英文约 4 字符/token)
def estimate_tokens(text):
    if not text:
        return 0
    # 简单估算:假设平均每个 token 约 2 个字符(中英文混合)
    return int(len(text) / 2)

print("=" * 50)
print("🤖 AI 助手已启动(输入 '退出' 结束对话)")
print("=" * 50)

# 对话循环
turn_count = 0  # 对话轮数计数器

while True:
    # 获取用户输入
    user_input = input("\n👤 用户: ").strip()
    
    # 检查退出条件
    if user_input.lower() in ["退出", "exit", "quit", "q"]:
        print("\n👋 感谢使用,再见!")
        break
    
    if not user_input:
        continue
    
    # 增加轮数
    turn_count += 1
    
    # 添加用户消息到历史
    messages.append({"role": "user", "content": user_input})
    
    print("\n🤖 AI: ", end="", flush=True)
    
    try:
        # 记录请求开始时间
        start_time = time.perf_counter()
        first_token_time = None
        
        # 创建流式输出请求
        stream = client.chat.completions.create(
            model="qwen3-8b",
            messages=messages,
            stream=True,
            temperature=0.7
        )
        
        # 流式接收并打印响应
        full_response = ""
        for chunk in stream:
            if chunk.choices and chunk.choices[0].delta.content:
                content = chunk.choices[0].delta.content
                print(content, end="", flush=True)
                full_response += content
                
                # 记录首 token 时间
                if first_token_time is None:
                    first_token_time = time.perf_counter()
        
        # 记录结束时间
        end_time = time.perf_counter()
        
        print()  # 换行
        
        # 计算统计指标
        ttft = (first_token_time - start_time) * 1000 if first_token_time else 0
        total_time = (end_time - start_time) * 1000
        generation_time = (end_time - first_token_time) * 1000 if first_token_time else 0
        
        # 估算 token 数
        current_turn_tokens = estimate_tokens(full_response)
        system_prompt_tokens = estimate_tokens(system_prompt)
        total_context_tokens = estimate_tokens("\n".join([m["content"] for m in messages]))
        
        tokens_per_second = (current_turn_tokens / generation_time * 1000) if generation_time > 0 else 0
        
        # 打印统计信息
        print("\n" + "-" * 50)
        print(f"📊 性能统计 (第 {turn_count} 轮对话):")
        print(f"   ⏱️  TTFT (首字节延迟):     {ttft:.2f} ms")
        print(f"   ⏱️  总耗时:                {total_time:.2f} ms")
        print(f"   ⏱️  生成耗时:              {generation_time:.2f} ms")
        print(f"   🔢 本轮生成 Tokens:        {current_turn_tokens}")
        print(f"   🚀 生成速度:              {tokens_per_second:.2f} tokens/s")
        print(f"   📜 系统提示词 Tokens:      {system_prompt_tokens}")
        print(f"   📚 上下文总 Tokens:        {total_context_tokens}")
        print("-" * 50)
        
        # 添加 AI 回复到历史
        messages.append({"role": "assistant", "content": full_response})
        
        # 控制历史长度(保留 system + 最近 10 轮对话)
        if len(messages) > 21:
            messages = [messages[0]] + messages[-20:]
            turn_count = 10  # 重置轮数显示(因为只保留最近10轮)
            
    except Exception as e:
        print(f"\n❌ 发生错误: {e}")
        import traceback
        traceback.print_exc()
        continue

备注:llama.cpp 启动的模型,不需要指定模型名,模型的访问是通过端口绑定的

7.GPU/CPU 使用查看

bash 复制代码
brew install mactop

sudo mactop

或

pip install asitop

sudo asitop

感谢阅读!如果你在 MacOS 上成功跑通了 llama.cpp,欢迎在评论区分享你的推理速度。有任何问题也可以留言交流~

标签llama.cpp MacOS MetalGPU


本文为原创内容,版权归作者所有,转载需注明出处。

相关推荐
Naisu Xu1 天前
Mac上安装Homebrew、Git、Python等环境记录
git·python·macos·终端·brew
程序猿进阶1 天前
OpenClaw Mac 安装教程
java·macos·ai·架构·agent·openclaw
Rudon滨海渔村1 天前
macOS启动转换助理出现“不能下载该软件,因为网络出现问题 ”
网络·macos
一个人旅程~1 天前
mac-bootcamp的windows系统因升级intel驱动更新等升级驱动导致的功能异常故障?
windows·经验分享·macos·电脑
一块小土坷垃2 天前
# AutoCAD 2027 专业级CAD设计绘图软件核心解析与使用评价
macos·开源软件
Rudon滨海渔村2 天前
MacBookPro更换硬盘-重新安装macOS+Win10LTSC双系统-官方免费工具
macos
一块小土坷垃2 天前
# ArchiCAD 29.0.2(畅享版):专为建筑师打造的BIM高效建模工具
前端·数据库·macos·开源软件
代码讲故事2 天前
mac电脑上docker突然无法运行,不停的出现弹框,“com.docker.vmnetd”将对你的电脑造成伤害。附国内不同芯片高速下载地址,下载直接运行。
macos·docker·容器·arm·mac·intel·下载
一块小土坷垃2 天前
## CleanMyMac – macOS 强大的系统清理与优化工具
macos·开源软件