Ollama:简化LLM本地部署
Ollama是2026年最受欢迎的本地LLM部署工具之一。它以极简的命令行界面和自动化的模型管理,让在本地运行大模型变得前所未有的简单。但从"能跑"到"生产可用"之间,还有大量工程细节需要处理。
安装与环境准备
系统要求
# Linux安装
curl -fsSL https://ollama.com/install.sh | sh
# 验证GPU支持
nvidia-smi # 确认GPU可用
ollama --version
GPU显存规划
不同模型的显存需求:
| 模型 | 参数量 | FP16显存 | INT4显存 | 推荐GPU |
|---|---|---|---|---|
| Qwen-3-7B | 7B | 14GB | 5GB | RTX 4060 8GB+ |
| Llama-3-8B | 8B | 16GB | 6GB | RTX 4070 12GB+ |
| Qwen-3-32B | 32B | 64GB | 20GB | RTX 4090 24GB+ |
| Llama-3-70B | 70B | 140GB | 40GB | 2×A100 80GB |
Ollama服务配置
# 自定义模型存储路径
export OLLAMA_MODELS=/data/ollama/models
# 监听所有网络接口(生产环境配合防火墙)
export OLLAMA_HOST=0.0.0.0:11434
# 并发请求数
export OLLAMA_NUM_PARALLEL=4
# 上下文长度
export OLLAMA_CONTEXT_LENGTH=8192
# GPU层数(-1为全部卸载到GPU)
export OLLAMA_NUM_GPU=-1
# 启动服务
ollama serve
模型管理
Modelfile自定义
# 基于Qwen-3创建自定义模型
FROM qwen3:32b
# 系统提示词
SYSTEM """
你是一个专业的技术助手。请提供准确、简洁的回答。
如果不确定,请明确说明。
"""
# 参数调优
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER top_k 40
PARAMETER num_ctx 8192
PARAMETER num_gpu 50
PARAMETER stop "<|im_end|>"
PARAMETER stop "<|endoftext|>"
# 模板
TEMPLATE """
{{ if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ range .Messages }}{{ if eq .Role "user" }}<|im_start|>user
{{ .Content }}<|im_end|>
{{ end }}{{ if eq .Role "assistant" }}<|im_start|>assistant
{{ .Content }}<|im_end|>
{{ end }}{{ end }}<|im_start|>assistant
"""
# 构建自定义模型
ollama create my-qwen -f Modelfile
# 运行
ollama run my-qwen
模型量化
# Ollama自动选择量化级别
ollama pull llama3:70b # 默认INT4量化
ollama pull llama3:70b-q8_0 # 指定INT8
ollama pull llama3:70b-fp16 # FP16精度
# 从GGUF文件导入
ollama create my-model --file ./model.gguf
API服务
REST API
import requests
# 基础对话
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "my-qwen",
"messages": [
{"role": "user", "content": "解释Transformer的注意力机制"}
],
"stream": False,
"options": {
"temperature": 0.7,
"num_ctx": 8192,
}
}
)
print(response.json()["message"]["content"])
# 流式响应
response = requests.post(
"http://localhost:11434/api/chat",
json={"model": "my-qwen", "messages": [...], "stream": True},
stream=True
)
for line in response.iter_lines():
if line:
chunk = json.loads(line)
print(chunk["message"]["content"], end="", flush=True)
OpenAI兼容API
Ollama提供OpenAI兼容接口,方便迁移现有应用:
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama" # 任意值
)
response = client.chat.completions.create(
model="my-qwen",
messages=[{"role": "user", "content": "Hello"}],
stream=True
)
生产环境配置
Nginx反向代理
upstream ollama_backend {
server 127.0.0.1:11434;
# 可以添加多个后端实现负载均衡
# server 10.0.0.2:11434;
}
server {
listen 443 ssl;
server_name llm.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
location / {
proxy_pass http://ollama_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# SSE支持(流式响应)
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
# 超时设置(LLM生成可能较慢)
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
# 速率限制
limit_req zone=api burst=10 nodelay;
}
Systemd服务
# /etc/systemd/system/ollama.service
[Unit]
Description=Ollama Service
After=network.target
[Service]
Type=simple
User=ollama
Group=ollama
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_MODELS=/data/ollama/models"
Environment="OLLAMA_NUM_PARALLEL=4"
ExecStart=/usr/local/bin/ollama serve
Restart=always
RestartSec=3
# 安全限制
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/data/ollama
# 资源限制
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Docker部署
# docker-compose.yml
version: '3.8'
services:
ollama:
image: ollama/ollama:latest
container_name: ollama
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
environment:
- OLLAMA_HOST=0.0.0.0:11434
- OLLAMA_NUM_PARALLEL=4
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
restart: unless-stopped
# 可选:Web UI
open-webui:
image: ghcr.io/open-webui/open-webui:main
ports:
- "3000:8080"
environment:
- OLLAMA_BASE_URL=http://ollama:11434
volumes:
- webui_data:/app/backend/data
depends_on:
- ollama
volumes:
ollama_data:
webui_data:
监控与日志
Prometheus指标
# 自定义指标导出
from prometheus_client import Counter, Histogram, start_http_server
REQUEST_COUNT = Counter('ollama_requests_total', 'Total requests')
REQUEST_LATENCY = Histogram('ollama_request_duration_seconds', 'Request duration')
ACTIVE_REQUESTS = Counter('ollama_active_requests', 'Currently active requests')
@app.route("/api/chat", methods=["POST"])
def chat():
REQUEST_COUNT.inc()
ACTIVE_REQUESTS.inc()
start_time = time.time()
try:
response = proxy_to_ollama(request.json)
REQUEST_LATENCY.observe(time.time() - start_time)
return response
finally:
ACTIVE_REQUESTS.dec()
日志管理
import logging
import json
class OllamaLogger:
def __init__(self):
self.logger = logging.getLogger("ollama")
handler = logging.FileHandler("/var/log/ollama/app.log")
handler.setFormatter(logging.Formatter(
'%(asctime)s - %(levelname)s - %(message)s'
))
self.logger.addHandler(handler)
def log_request(self, model, prompt_length, response_length, duration):
self.logger.info(json.dumps({
"model": model,
"prompt_tokens": prompt_length,
"response_tokens": response_length,
"duration_ms": duration,
"timestamp": datetime.now().isoformat()
}))
性能优化
模型预热
# 启动时预加载模型
curl http://localhost:11434/api/generate -d '{
"model": "my-qwen",
"prompt": "warmup",
"keep_alive": -1
}'
# keep_alive: -1 表示永久保持模型在内存中
# keep_alive: 0 表示使用后立即卸载
# keep_alive: 300 表示保持5分钟
批处理优化
import asyncio
import aiohttp
async def batch_generate(prompts, model="my-qwen"):
"""并发批处理"""
async with aiohttp.ClientSession() as session:
tasks = []
for prompt in prompts:
task = asyncio.create_task(
generate_one(session, model, prompt)
)
tasks.append(task)
results = await asyncio.gather(*tasks)
return results
async def generate_one(session, model, prompt):
async with session.post(
"http://localhost:11434/api/generate",
json={"model": model, "prompt": prompt, "stream": False}
) as resp:
return await resp.json()
多GPU负载均衡
# 指定GPU
CUDA_VISIBLE_DEVICES=0 ollama serve # GPU 0
CUDA_VISIBLE_DEVICES=1 ollama serve # GPU 1(不同端口)
# 或使用Ollama内置多GPU支持(自动分配)
ollama serve # 自动检测所有GPU
安全加固
API认证
from fastapi import FastAPI, HTTPException, Security
from fastapi.security import APIKeyHeader
app = FastAPI()
api_key_header = APIKeyHeader(name="X-API-Key")
VALID_API_KEYS = {"your-secret-key"}
async def verify_api_key(api_key: str = Security(api_key_header)):
if api_key not in VALID_API_KEYS:
raise HTTPException(status_code=403, detail="Invalid API key")
return api_key
@app.post("/api/chat")
async def chat(request: dict, api_key: str = Security(verify_api_key)):
# 代理到Ollama
return await proxy_to_ollama(request)
内容过滤
class ContentFilter:
def __init__(self):
self.blocked_patterns = [
r"忽略.*指令",
r"ignore.*instruction",
# 添加更多模式
]
def check_input(self, text):
for pattern in self.blocked_patterns:
if re.search(pattern, text, re.IGNORECASE):
return False, "输入包含可疑内容"
return True, None
def check_output(self, text):
# 检查输出是否包含敏感信息
if self.contains_pii(text):
return False, "输出包含敏感信息"
return True, None
常见问题排查
GPU内存不足
# 减少GPU层数
PARAMETER num_gpu 20 # 只将20层卸载到GPU
# 使用更激进的量化
ollama pull model:q4_0 # INT4量化
# 减少并发数
export OLLAMA_NUM_PARALLEL=1
响应速度慢
# 检查是否所有层在GPU上
ollama ps # 查看模型加载状态
# 确保keep_alive设置合理
curl http://localhost:11434/api/generate -d '{
"model": "my-qwen",
"prompt": "test",
"keep_alive": -1
}'
模型加载失败
# 检查磁盘空间
df -h /data/ollama/models
# 清理未使用的模型
ollama rm old-model
# 检查模型文件完整性
ollama show my-qwen --modelfile
结语
Ollama以其简洁的设计和强大的功能,成为本地LLM部署的首选工具。从开发测试到生产部署,合理配置模型参数、监控系统健康、优化请求处理,是构建可靠LLM服务的关键。
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。