本地模型部署方案 — Ollama on Apple Silicon

硬件参考: Mac Mini, Apple M4 Pro (14 核 CPU / 20 核 GPU), 64GB 统一内存, macOS 26.x

适用范围: 任何 Apple Silicon Mac(M1/M2/M3/M4 系列),8GB 以上内存即可,模型选择按内存调整。

最后更新: 2026-04-03


目录

  1. 为什么选 Ollama
  2. 安装
  3. 性能优化配置
  4. 模型选型指南
  5. 基准测试数据
  6. 日常使用
  7. 与 Docker 应用集成
  8. 踩坑记录
  9. 维护与更新
  10. 附录:备选方案对比
  11. 实际应用案例:ToolRef RAG 引擎

1. 为什么选 Ollama

维度OllamaLM StudioMLX (llm-mlx)
安装brew install ollama,一行命令GUI 安装包pip install mlx-lm
服务化launchd 守护进程,开机自启需手动启动 GUI无内置服务
API 兼容OpenAI-compatible /v1/ 端点OpenAI-compatible需自己包 API
Docker 集成host.docker.internal:11434 直连同上(端口 1234)需额外封装
模型管理ollama pull/list/rm,CLI 完整GUI 管理手动下载
Apple Silicon 优化Metal GPU 加速 + Flash AttentionMetal GPUMLX 原生框架
生态成熟度★★★★★★★★★★★★

结论: Ollama 在服务化、CLI 管理、Docker 集成三方面完胜,适合作为开发阶段的本地 LLM 后端。


2. 安装

2.1 通过 Homebrew 安装(推荐)

# 安装
brew install ollama

# 启动服务(注册 launchd,开机自启)
brew services start ollama

# 验证
ollama --version
# ollama version is 0.19.0

curl http://localhost:11434/v1/models | python3 -m json.tool

2.2 验证安装

# 服务状态
brew services list | grep ollama
# ollama      started         <user> ~/Library/LaunchAgents/homebrew.mxcl.ollama.plist

# API 健康检查
curl -s http://localhost:11434/ 
# Ollama is running

2.3 关键路径

路径说明
/opt/homebrew/bin/ollama可执行文件
~/.ollama/models/模型存储目录
~/Library/LaunchAgents/homebrew.mxcl.ollama.plistlaunchd 配置
/opt/homebrew/var/log/ollama.log日志文件

3. 性能优化配置

Ollama 通过 launchd plist 的 EnvironmentVariables 设置环境变量。

3.1 编辑配置

# 方法 1:直接编辑 plist
nano ~/Library/LaunchAgents/homebrew.mxcl.ollama.plist

# 方法 2:用 defaults 命令(不推荐,plist 结构复杂时容易出错)

3.2 推荐配置

在 plist 的 <dict>EnvironmentVariables<dict> 内添加:

<key>EnvironmentVariables</key>
<dict>
    <!-- Flash Attention:Apple Silicon 必开,显著提升推理速度 -->
    <key>OLLAMA_FLASH_ATTENTION</key>
    <string>1</string>
    
    <!-- KV Cache 量化:q8_0 节省显存,几乎不影响质量 -->
    <key>OLLAMA_KV_CACHE_TYPE</key>
    <string>q8_0</string>
    
    <!-- 代理(按需,用于 ollama pull 下载模型) -->
    <key>HTTP_PROXY</key>
    <string>http://127.0.0.1:7890</string>
    <key>HTTPS_PROXY</key>
    <string>http://127.0.0.1:7890</string>
</dict>

3.3 其他可选参数

环境变量默认值说明
OLLAMA_HOST127.0.0.1:11434监听地址。局域网共享改为 0.0.0.0:11434
OLLAMA_NUM_PARALLEL1并发请求数。64GB 内存可设 2-4
OLLAMA_MAX_LOADED_MODELS1同时加载模型数。64GB 可设 2(注意内存)
OLLAMA_KEEP_ALIVE5m模型卸载超时。频繁使用可设 30m1h
OLLAMA_FLASH_ATTENTION0必开。Apple Silicon Metal 加速
OLLAMA_KV_CACHE_TYPEf16q8_0 省内存,q4_0 更激进但可能影响质量

3.4 应用配置变更

# 重启 Ollama 服务使配置生效
brew services restart ollama

# 验证配置
ollama ps  # 查看当前加载的模型

4. 模型选型指南

4.1 当前已安装模型

模型参数量量化磁盘架构用途
qwen3:30b-a3b30.5B (MoE, 3B 激活)Q4_K_M18 GBqwen3moe主力推理,速度快
qwen3.5:35b-a3b36B (MoE, 3B 激活)Q4_K_M23 GBqwen35moe多模态(支持 vision),quality > speed
qwen2.5:32b32.8B (Dense)Q4_K_M19 GBqwen2备用,Dense 架构速度较慢
qwen2.5:14b14.8B (Dense)Q4_K_M9 GBqwen2轻量任务 / RAGAS LLM judge
vicuna:7b7B (Dense)Q4_03.8 GBllama测试用,不推荐生产

总磁盘占用: ~70 GB(~/.ollama/models/

4.2 选型决策树

需要 vision(图片理解)?
  → Yes: qwen3.5:35b-a3b(当前唯一多模态)
  → No: 继续 ↓

对速度敏感(实时交互 / API 后端)?
  → Yes: qwen3:30b-a3b(MoE, 64.7 tok/s)
  → No: 继续 ↓

需要最高质量(评估 / 复杂推理)?
  → Yes: qwen3.5:35b-a3b(更大参数量 + thinking)
  → No: qwen3:30b-a3b(默认选择)

内存有限(< 32GB)?
  → qwen2.5:14b(9 GB,25 tok/s)
  
最低配(8GB Mac)?
  → vicuna:7b 或 qwen2.5:7b

4.3 MoE vs Dense 的关键区别

MoE (Mixture of Experts): qwen3/qwen3.5 的 a3b 后缀表示 active 3B——虽然总参数 30-36B,但每次推理只激活 3B 参数。

  • 优势: 推理速度接近 3B 模型,质量接近 30B 模型
  • 劣势: 加载时仍需完整模型的内存(18-23 GB)
  • 实测: qwen3:30b-a3b(64.7 tok/s)比 Dense qwen2.5:32b(11.7 tok/s)快 5.5 倍

这是为什么我们从 qwen2.5 迁移到 qwen3 MoE 的核心原因。

4.4 拉取新模型

# 搜索可用模型
ollama search qwen

# 拉取
ollama pull qwen3:30b-a3b

# 查看模型信息
ollama show qwen3:30b-a3b

# 删除不需要的模型(释放磁盘)
ollama rm vicuna:7b

5. 基准测试数据

测试环境: Mac Mini M4 Pro 64GB, Ollama 0.19.0, Flash Attention ON, KV Cache q8_0

测试方法: POST /api/generatestream: false,取 eval_durationeval_count

5.1 生成速度

模型加载时间生成 tokens生成耗时速度 (tok/s)总耗时
qwen3:30b-a3b0.1s (hot)73911.4s64.711.8s
qwen3.5:35b-a3b10.1s (cold)10840380.1s28.5393.0s
qwen2.5:32b15.1s (cold)23019.7s11.735.6s
qwen2.5:14b8.0s (cold)2379.4s25.117.9s

: qwen3.5 生成了 thinking tokens(10840 tokens 含 thinking 输出),实际输出约 200 tokens。thinking 模式下总耗时显著增加。

5.2 实际应用延迟(ToolRef RAG pipeline)

环节耗时
Embedding (BGE-M3, CPU)~0.5s
Milvus 检索~0.1s
Reranking (BGE-Reranker-v2-M3, CPU)~6s (10 docs)
LLM 生成 (qwen3:30b-a3b)40-80s
语义缓存命中0.2-0.3s
端到端(首次查询)~50-90s
端到端(缓存命中)~0.3s

LLM 生成是瓶颈。RAG prompt 含大量 context(5 个 source chunks),输入 token 多,输出也长。

5.3 内存占用参考

Apple Silicon 的统一内存被 CPU 和 GPU 共享。Ollama 加载模型时占用的是 GPU 内存(Metal)。

模型Q4_K_M 磁盘运行时内存(估算)
qwen3:30b-a3b18 GB~20 GB
qwen3.5:35b-a3b23 GB~25 GB
qwen2.5:32b19 GB~21 GB
qwen2.5:14b9 GB~11 GB

64 GB 机器可以同时加载 qwen3:30b + qwen2.5:14b,但建议 OLLAMA_MAX_LOADED_MODELS=1 避免内存压力。


6. 日常使用

6.1 CLI 交互

# 对话模式
ollama run qwen3:30b-a3b

# 单次提问
ollama run qwen3:30b-a3b "解释 RAG 是什么"

# 查看当前加载的模型
ollama ps

# 列出所有已安装模型
ollama list

6.2 API 调用(OpenAI 兼容)

Ollama 在 http://localhost:11434/v1/ 提供 OpenAI-compatible API:

# 列出模型
curl http://localhost:11434/v1/models

# Chat Completion
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3:30b-a3b",
    "messages": [{"role": "user", "content": "什么是向量数据库?"}],
    "temperature": 0.7
  }'

# Streaming
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3:30b-a3b",
    "messages": [{"role": "user", "content": "什么是向量数据库?"}],
    "stream": true
  }'

6.3 Python SDK

# 方式 1:OpenAI SDK(推荐,通用性好)
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama"  # Ollama 不验证 key,但 SDK 要求非空
)

response = client.chat.completions.create(
    model="qwen3:30b-a3b",
    messages=[{"role": "user", "content": "什么是 RAG?"}],
    temperature=0.7
)
print(response.choices[0].message.content)

# 方式 2:Ollama 官方 SDK
import ollama

response = ollama.chat(
    model="qwen3:30b-a3b",
    messages=[{"role": "user", "content": "什么是 RAG?"}]
)
print(response["message"]["content"])

6.4 关闭 Thinking 模式

qwen3/qwen3.5 默认启用 thinking(长链推理),会生成大量 thinking tokens,显著增加延迟。对于 API 后端场景,建议关闭:

# CLI:加 /nothink
ollama run qwen3:30b-a3b /nothink "简单问题"

# API:通过 chat_template_kwargs(Ollama 原生 API)
# 或在应用层 .env 配置
LLM_DISABLE_THINKING=true

7. 与 Docker 应用集成

这是最常见的使用场景:Docker 容器内的应用需要调用宿主机的 Ollama。

7.1 网络拓扑

┌─────────────────────────┐
│  macOS Host              │
│  Ollama :11434           │
│                          │
│  ┌────────────────────┐  │
│  │ Docker Desktop      │  │
│  │                     │  │
│  │  container-a ──────────── host.docker.internal:11434
│  │  container-b ──────────── host.docker.internal:11434
│  │                     │  │
│  └────────────────────┘  │
└─────────────────────────┘

Docker Desktop for Mac 提供 host.docker.internal DNS 名称,指向宿主机。

7.2 应用 .env 配置

以 ToolRef 为例(任何使用 OpenAI SDK 的应用通用):

# LLM 配置
LLM_PROVIDER=openai
LLM_MODEL=qwen3:30b-a3b          # ⚠️ Ollama 模型名,不带 provider 前缀
LLM_TEMPERATURE=0.1

# OpenAI-compatible 端点
OPENAI_API_KEY=ollama              # Ollama 不验证,但 SDK 要求非空
OPENAI_API_BASE=http://host.docker.internal:11434/v1   # Docker → Host

# 可选:关闭 thinking(减少延迟)
LLM_DISABLE_THINKING=true

7.3 关键注意事项

⚠️ 模型名格式:

  • qwen3:30b-a3b(Ollama 格式)
  • qwen/qwen3-30b-a3b(HuggingFace 格式,Ollama 会报 404)

⚠️ .env 变更后必须重建容器:

# ❌ 错误:restart 不会重载 .env
docker restart my-container

# ✅ 正确:up -d 会检测 .env 变化并重建
docker compose up -d

⚠️ 代理冲突: 如果宿主机设置了 ALL_PROXY=socks5://...all_proxy=socks5://...,Python httpx 会尝试通过 SOCKS 代理连接 Ollama,导致 ImportError: socksio not installed。解决方案:

# 在脚本中清除代理环境变量
import os
for var in ["ALL_PROXY", "all_proxy", "HTTP_PROXY", "http_proxy", "HTTPS_PROXY", "https_proxy"]:
    os.environ.pop(var, None)

或在 Docker Compose 中显式设置:

environment:
  - ALL_PROXY=
  - all_proxy=
  - NO_PROXY=host.docker.internal,localhost

7.4 验证连通性

# 从宿主机验证
curl http://localhost:11434/v1/models

# 从 Docker 容器内验证
docker exec <container-name> curl -s http://host.docker.internal:11434/v1/models

8. 踩坑记录

R17: docker restart 不重载 .env

现象: 修改 .env 中的 LLM_MODELdocker restart backend,容器仍用旧配置。

原因: docker restart 只重启进程,不重新读取 .envdocker-compose.yml

解决: 用 docker compose up -d,Compose 会检测变化并 recreate 容器。

R-Ollama-1: 模型名格式错误

现象: openai.NotFoundError: model 'qwen/qwen3-30b-a3b' not found

原因: Ollama 的模型 ID 格式是 name:tag(如 qwen3:30b-a3b),不是 HuggingFace 的 org/model 格式。

解决: .env 中写 LLM_MODEL=qwen3:30b-a3b。可通过 ollama list 确认正确名称。

R-Ollama-2: SOCKS 代理导致连接失败

现象: Python httpx 报 ImportError: socksio not installed

原因: 宿主机设了 ALL_PROXY=socks5://127.0.0.1:7890,httpx 发现 SOCKS 代理但缺少 socksio 库。

解决: 清除 ALL_PROXY/all_proxy 环境变量(见 7.3)。

R-Ollama-3: 冷启动加载慢

现象: 第一次请求模型耗时 10-15s,后续 <0.5s。

原因: Ollama 按需加载模型到 GPU 内存(Metal),默认 5 分钟无请求后卸载。

解决:

<!-- 在 plist EnvironmentVariables 中增加 -->
<key>OLLAMA_KEEP_ALIVE</key>
<string>30m</string>  <!-- 30 分钟不卸载 -->

R-Ollama-4: qwen3.5 thinking 导致超长输出

现象: 简单问题生成 10000+ tokens,耗时 6 分钟。

原因: qwen3.5 默认开启 thinking 模式,会在 <think> 标签中输出长链推理。

解决: 在应用配置中关闭 thinking(LLM_DISABLE_THINKING=true),或用 qwen3(thinking 可控性更好)。


9. 维护与更新

9.1 更新 Ollama

brew upgrade ollama
brew services restart ollama

9.2 更新模型

# 拉取同 tag 的最新版本
ollama pull qwen3:30b-a3b

# 清理旧版本残留
# Ollama 自动管理 blob 去重,通常不需要手动清理

9.3 监控

# 查看运行日志
tail -f /opt/homebrew/var/log/ollama.log

# 查看当前加载模型及内存
ollama ps

# 磁盘占用
du -sh ~/.ollama/models

9.4 开机自启验证

Homebrew 安装的 Ollama 通过 launchd 自动启动:

# 确认已注册
brew services list | grep ollama
# ollama      started    <user>  ~/Library/LaunchAgents/homebrew.mxcl.ollama.plist

# 如果未启动
brew services start ollama

10. 附录:备选方案对比

LM Studio

  • 优势: GUI 友好,模型市场直观,支持 GGUF/MLX 双格式
  • 劣势: 无 CLI 管理,无 launchd 服务化,端口默认 1234(需配置)
  • 适合: 个人实验、可视化对比模型

MLX (Apple 原生框架)

  • 优势: Apple Silicon 最底层优化,理论性能上限最高
  • 劣势: 生态不成熟,无服务化,模型格式不通用(.safetensors + MLX config)
  • 适合: 研究、需要极致性能的特定场景

vLLM

  • 优势: 生产级推理服务,PagedAttention,高并发
  • 劣势: 需要 NVIDIA GPU(不支持 Apple Silicon Metal)
  • 适合: 云 GPU(AutoDL 4090)部署验证

我们的选择

开发阶段用 Ollama(稳定 + 服务化 + Docker 友好),生产部署验证用 vLLM on 云 GPU。MLX 持续关注但暂不投入。


11. 实际应用案例:ToolRef RAG 引擎

这是 Ollama 在我们项目中的真实使用场景,展示完整的集成方式和性能表现。

11.1 项目背景

ToolRef 是一个生产级 RAG 引擎,提供 Chat UI + MCP Server 双入口。Ollama 作为 LLM 生成后端,负责根据检索到的文档片段生成最终回答。

架构链路:

User Query
  → BGE-M3 Embedding (CPU, 容器内)
  → Milvus 向量检索 (dense + sparse hybrid)
  → BGE-Reranker-v2-M3 重排序 (CPU, 容器内)
  → CRAG 自校正 (判断相关性,必要时重写 query)
  → Ollama qwen3:30b-a3b 生成回答 (宿主机 GPU)
  → 语义缓存写入 Redis
  → 返回答案 + Source 卡片

11.2 服务架构

┌──────────────────────────────────────────────────────┐
│  macOS Host                                          │
│  Ollama :11434  (qwen3:30b-a3b, Metal GPU)           │
│                                                      │
│  ┌─────────────────────────────────────────────────┐ │
│  │ Docker Compose (9 容器)                          │ │
│  │                                                  │ │
│  │  toolref-frontend (:3002)     ← Chat UI          │ │
│  │  toolref-backend (:8000)      ← FastAPI          │ │
│  │  toolref-mcp-server (:8080)   ← MCP Server       │ │
│  │  toolref-ingestion-worker     ← 文档摄入          │ │
│  │  toolref-postgres (:5432)     ← 文档元数据        │ │
│  │  toolref-redis (:6379)        ← 语义缓存          │ │
│  │  toolref-milvus (:19530)      ← 向量存储          │ │
│  │  toolref-minio (:9000)        ← 文件存储          │ │
│  │  toolref-etcd                 ← Milvus 依赖       │ │
│  │                                                  │ │
│  │  backend → host.docker.internal:11434 → Ollama   │ │
│  └─────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘

11.3 .env 配置(实际使用)

# LLM 生成
LLM_PROVIDER=openai
LLM_MODEL=qwen3:30b-a3b
LLM_TEMPERATURE=0.1
LLM_DISABLE_THINKING=true          # 关闭 thinking,减少延迟
OPENAI_API_KEY=ollama
OPENAI_API_BASE=http://host.docker.internal:11434/v1

# Embedding(容器内 CPU 推理,不走 Ollama)
EMBEDDING_MODEL=BAAI/bge-m3
EMBEDDING_DIM=1024
EMBEDDING_BATCH_SIZE=32

注意:Embedding 和 Reranking 模型在容器内 CPU 运行(HuggingFace SentenceTransformers),不经过 Ollama。只有 LLM 生成走 Ollama GPU 推理。

11.4 知识库规模

指标数据
知识库来源Claude/Anthropic 官方文档 (claude-wiki mirror)
Namespaceclaude
文档数量1370 篇
文档格式Markdown + YAML frontmatter
覆盖范围API Docs, Claude Code, MCP, Prompt Engineering, Tool Use 等 20 个类别
摄入耗时~4 小时(单 worker, CPU embedding, ~10s/doc)
另有 default namespace4 篇测试文档

11.5 端到端性能数据(实测)

测试条件: Mac Mini M4 Pro 64GB, Ollama 0.19.0, qwen3:30b-a3b, Flash Attention ON, top_k=5

场景延迟说明
语义缓存命中0.2-0.5s相同/相似 query 直接返回缓存结果
首次查询(cache miss)40-80s完整链路:embed → search → rerank → generate
其中 Embedding~0.5sBGE-M3, CPU
其中 Milvus 检索~0.1sdense + sparse hybrid search
其中 Reranking~6sBGE-Reranker-v2-M3, 10 docs, CPU
其中 LLM 生成30-70s瓶颈环节,取决于 context 长度和输出长度
语义缓存 TTL24h自动过期

实测采样(2026-04-03):

Query: "What is prompt caching and how to enable it?"
  Cache hit:  0.2s ✅
  Cache miss: 44.1s ✅ (含 LLM 生成)

Query: "How to implement streaming with Claude API?"
  Cache miss: 44.1s ✅

11.6 质量验证结果

5 个测试 query 全部通过(检索正确 + 生成正确):

Query检索质量生成质量
Prompt Caching✅ 正确召回 Prompt Caching 文档✅ 详细说明原理和启用方式
Tool Use✅ 正确召回 Tool Use 文档✅ 给出设置和配置步骤
MCP✅ 正确召回 MCP 文档✅ 准确描述协议标准
Claude Code Best Practices✅ 正确召回 Claude Code 文档✅ 输出 context management 等建议
Rate Limits✅ 正确召回 Rate Limits 文档✅ 给出 exponential backoff 方案

评估基线(RAGAS + IR Metrics):

  • Hit Rate: 100%, MRR: 1.0, Recall@5: 100%
  • Answer Relevancy: 0.936
  • Context Recall: 0.370(偏低,待优化 ground truth 质量)

11.7 踩坑总结(ToolRef 集成相关)

编号问题解决方案
R17.env 改了 LLM_MODELdocker restart 不生效docker compose up -d 重建容器
R-OL1模型名写成 qwen/qwen3-30b-a3b 报 404Ollama 格式是 qwen3:30b-a3b
R-OL2ALL_PROXY 导致 httpx 连接 Ollama 失败清除 SOCKS 代理环境变量
R-OL4qwen3.5 thinking 输出 10000+ tokensLLM_DISABLE_THINKING=true 或选 qwen3
R-P1首次 query 超慢(80s+)Ollama 冷启动加载模型(设 OLLAMA_KEEP_ALIVE=30m

11.8 性能优化建议

策略效果复杂度
语义缓存 (已实施)重复 query 0.2s(降 99%)
OLLAMA_KEEP_ALIVE=30m避免冷启动 15s
Flash Attention (已启用)推理速度提升 ~20-30%
KV Cache q8_0 (已启用)省内存,支持更长 context
换更小模型 (qwen2.5:14b)生成速度 ×2,质量下降中(需评估)
云 GPU (vLLM + 4090)生成速度 ×5-10高(需运维)
Streaming 输出 (已支持)用户感知延迟大幅降低

快速开始清单(给新人)

# 1. 安装 Ollama
brew install ollama

# 2. 启动服务
brew services start ollama

# 3. 优化配置(编辑 plist 加 Flash Attention + KV Cache 量化)
nano ~/Library/LaunchAgents/homebrew.mxcl.ollama.plist
# 添加 OLLAMA_FLASH_ATTENTION=1 和 OLLAMA_KV_CACHE_TYPE=q8_0
brew services restart ollama

# 4. 拉取推荐模型
ollama pull qwen3:30b-a3b      # 主力,速度优先(64GB 机器推荐)
ollama pull qwen2.5:14b         # 轻量备用(32GB 以下推荐)

# 5. 验证
ollama run qwen3:30b-a3b "Hello, world!"
curl http://localhost:11434/v1/models

# 6. (可选)Docker 应用集成
# .env: OPENAI_API_BASE=http://host.docker.internal:11434/v1
# .env: LLM_MODEL=qwen3:30b-a3b
# .env: OPENAI_API_KEY=ollama

搞定 ✅