Ollama 架构概览

Ollama 是一个轻量级的本地 LLM 运行时,核心用 Go 编写,底层调用 llama.cpp 进行推理。其架构分为三层:

  • CLI 层ollama runollama pull 等命令,通过 Unix Socket / TCP 与服务端通信
  • Server 层:HTTP REST API(默认 :11434),管理模型生命周期、请求队列、并发控制
  • Runtime 层:基于 llama.cpp 的 GGML 后端,支持 CPU / GPU 混合推理
┌──────────┐   HTTP API   ┌──────────────┐   llama.cpp   ┌─────────┐
│  CLI /   │ ──────────→  │  Ollama       │ ───────────→  │  GGML   │
│  Client  │              │  Server       │               │  Backend│
└──────────┘              │  (:11434)     │               │  (CPU/  │
                          └──────────────┘               │   GPU) │
                                                         └─────────┘

关键设计决策

Ollama 将模型权重、推理引擎、API 服务打包为单一二进制,降低了部署复杂度。但这也意味着你在生产环境中需要关注以下限制:

特性支持情况备注
OpenAI API 兼容/v1/chat/completions流式、Function Calling
多模型并发⚠️ 有限默认串行,需配置并行
GPU 内存管理自动按 GPU 显存自动分配 layer offload
模型量化GGUF 内置Q4_0 ~ Q8_0
分布式推理单节点 only

模型管理

Modelfile 机制

Ollama 使用 Modelfile(类似 Dockerfile)定义模型:

# 基础模型
FROM llama3.1:8b-instruct-q4_K_M

# 系统提示词
SYSTEM """
You are a helpful assistant specialized in code review.
Always respond in the user's language.
"""

# 参数调优
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER num_ctx 8192
PARAMETER num_gpu 33    # GPU layer 数量
PARAMETER num_thread 8  # CPU 线程数

# 模板
TEMPLATE """{{ .System }}

{{ .Prompt }}"""

# 停止词
PARAMETER stop "<|im_end|>"
PARAMETER stop "</s>"

模型导入与自定义

# 从 GGUF 导入
ollama create my-model -f Modelfile

# 从 HuggingFace 下载并转换
huggingface-cli download bartowski/Llama-3.1-8B-Instruct-GGUF \
  --include "*Q4_K_M*" --local-dir ./models
ollama create llama3.1-custom \
  --file <(echo 'FROM ./models/Llama-3.1-8B-Instruct-Q4_K_M.gguf')

# 查看已安装模型
ollama list

# 查看模型详细信息
ollama show llama3.1:8b --modelfile

API 兼容性

Ollama 提供两套 API:原生 API 和 OpenAI 兼容 API。

OpenAI 兼容端点

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama"  # 任意值即可
)

response = client.chat.completions.create(
    model="llama3.1:8b",
    messages=[
        {"role": "system", "content": "You are a code reviewer."},
        {"role": "user", "content": "Review this Python function for bugs."}
    ],
    stream=True,
    tools=[{
        "type": "function",
        "function": {
            "name": "run_tests",
            "description": "Run test suite",
            "parameters": {"type": "object", "properties": {}}
        }
    }]
)

原生 API(更丰富)

# 生成(非对话模型)
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.1:8b",
  "prompt": "Write a Rust struct for a Redis connection pool",
  "stream": false,
  "options": {"temperature": 0.3, "num_ctx": 4096}
}'

# 对话
curl http://localhost:11434/api/chat -d '{
  "model": "llama3.1:8b",
  "messages": [{"role": "user", "content": "Hello"}],
  "stream": true
}'

# 嵌入向量
curl http://localhost:11434/api/embeddings -d '{
  "model": "nomic-embed-text",
  "prompt": "Embed this text"
}'
端点原生 APIOpenAI 兼容
Chat/api/chat/v1/chat/completions
Completion/api/generate/v1/completions
Embedding/api/embeddings/v1/embeddings
Models/api/tags/v1/models

GPU 配置与调优

GPU 检测与分配

# 查看 GPU 状态
nvidia-smi

# Ollama 启动时指定 GPU
CUDA_VISIBLE_DEVICES=0,1 ollama serve

# Modelfile 中指定 GPU layer 数
# num_gpu = 总层数时全部放 GPU,= 0 时全部放 CPU

多 GPU 策略

Ollama 默认将模型 split 到所有可见 GPU。对于大模型(如 70B):

# 方案 A:单模型多 GPU(张量并行不支持,仅 layer split)
ollama run llama3.1:70b  # 自动 split 到多卡

# 方案 B:多模型分卡部署
CUDA_VISIBLE_DEVICES=0 OLLAMA_HOST=0.0.0.0:11434 ollama serve &
CUDA_VISIBLE_DEVICES=1 OLLAMA_HOST=0.0.0.0:11435 ollama serve &

显存计算参考

模型量化显存需求推荐 GPU
Llama 3.1 8BQ4_K_M~6 GBRTX 4060 / A10
Llama 3.1 8BQ8_0~9 GBRTX 4070 / A10
Llama 3.1 70BQ4_K_M~40 GB2×A100 40G
Qwen2.5 32BQ4_K_M~20 GBA100 40G / 2×RTX 4090
DeepSeek R1 671BQ4_K_M~400 GB8×H100 80G

并发调优

Ollama 默认串行处理请求。生产环境必须调整以下参数:

# 环境变量
OLLAMA_MAX_LOADED_MODELS=4      # 同时驻留内存的模型数
OLLAMA_NUM_PARALLEL=4           # 每个模型的并行请求数
OLLAMA_MAX_QUEUE=512            # 请求队列长度
OLLAMA_KEEP_ALIVE=24h           # 模型在内存中的保活时间

# systemd 配置示例
sudo systemctl edit ollama
# /etc/systemd/system/ollama.service.d/override.conf
[Service]
Environment="OLLAMA_MAX_LOADED_MODELS=4"
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_QUEUE=512"
Environment="OLLAMA_KEEP_ALIVE=24h"
Environment="CUDA_VISIBLE_DEVICES=0,1"
LimitNOFILE=65536

并发性能参考

以 Llama 3.1 8B Q4_K_M 在单张 A100 40G 上为例:

并发数吞吐 (tok/s)P99 延迟 (ms)显存占用
185125.8 GB
4220456.2 GB
8380957.1 GB
165201809.4 GB

吞吐在并发 16 时开始边际递减,建议生产环境设置 OLLAMA_NUM_PARALLEL=8

Docker 部署

单机 Docker

# docker-compose.yml
version: "3.9"

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    environment:
      - OLLAMA_MAX_LOADED_MODELS=4
      - OLLAMA_NUM_PARALLEL=4
      - OLLAMA_KEEP_ALIVE=24h
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  ollama_data:

预拉取模型

# Dockerfile.preload
FROM ollama/ollama:latest

# 启动服务,拉取模型,然后停止
RUN ollama serve & \
    sleep 5 && \
    ollama pull llama3.1:8b-instruct-q4_K_M && \
    ollama pull nomic-embed-text && \
    pkill ollama

监控方案

Prometheus 指标

Ollama 本身不暴露 Prometheus 指标,需要通过 Exporter 或自定义脚本:

# ollama_exporter.py
import prometheus_client as prom
import requests, time, threading

REQUEST_COUNT = prom.Counter(
    'ollama_requests_total', 'Total requests', ['model', 'status']
)
REQUEST_DURATION = prom.Histogram(
    'ollama_request_duration_seconds', 'Request duration', ['model']
)
MODEL_LOADED = prom.Gauge(
    'ollama_model_loaded', 'Model loaded in memory', ['model']
)

def collect_metrics():
    while True:
        try:
            resp = requests.get("http://localhost:11434/api/ps")
            models = resp.json().get("models", [])
            MODEL_LOADED.clear()
            for m in models:
                MODEL_LOADED.labels(model=m["name"]).set(1)
        except:
            pass
        time.sleep(15)

threading.Thread(target=collect_metrics, daemon=True).start()
prom.start_http_server(9100)

Grafana Dashboard 核心面板

面板指标告警阈值
请求 QPSrate(ollama_requests_total[5m])> 50/s
P99 延迟histogram_quantile(0.99, ollama_request_duration_seconds_bucket)> 2000ms
GPU 利用率DCGM_FI_DEV_GPU_UTIL> 95% 持续 5min
显存使用DCGM_FI_DEV_FB_USED> 90%
模型加载状态ollama_model_loaded空值告警

日志收集

# Docker 日志
docker logs ollama --tail 100 -f

# JSON 结构化日志(需要额外配置)
# Ollama 0.5+ 支持 OLLAMA_DEBUG=1 输出详细日志
OLLAMA_DEBUG=1 ollama serve 2>&1 | jq .

生产环境 Checklist

  • 设置 OLLAMA_KEEP_ALIVE 避免频繁模型加载/卸载
  • 配置 OLLAMA_NUM_PARALLEL 根据硬件调整并发数
  • 前置 Nginx/Caddy 添加认证和 TLS
  • 配置 Prometheus + Grafana 监控
  • 设置模型拉取的私有 Registry(离线环境)
  • 定期更新 Ollama 版本获取性能改进
  • 监控 GPU 温度和功耗
  • 配置日志轮转避免磁盘打满

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。