Ollama: 多模态模型
多模态模型让 AI 有了眼睛——看图说话,一目了然。
💡 提示:多模态模型(如llava、minicpm-v)比纯文本模型大2-3倍,且图像处理需要额外的视觉编码器计算,因此强烈推荐使用GPU加速。在CPU-only环境下,多模态模型的推理速度可能慢到无法实用(1-3 tok/s),8GB以上VRAM的GPU是流畅运行多模态模型的基本要求。
📋 前置知识:需要先掌握以下内容
- 第4课:模型管理
1. 你将学到
- 多模态模型架构:视觉编码器 + 语言解码器
- 图像输入方式
- REST API 多模态调用:images 字段
- 实战场景:产品描述、Bug 分析、OCR 辅助
- Alice 的 UI 截图分析场景
2. 一个 SaaS 创业者的真实故事
ℹ️ 信息: 目前 Ollama 支持的多模态模型主要是 LLaVA 系列(llava、llava-llama3、minicpm-v 等)。视觉理解能力不及 GPT-4V,但对 UI 截图分析、OCR 辅助、产品描述等场景已足够实用。
💡 提示: 多模态模型推荐使用
llava:13b 而非 llava:7b——13B 版本的视觉理解能力显著提升,尤其是在需要描述细节(如 UI 元素位置、图表数据)的场景下。7B 适合简单分类,13B 适合描述和分析。
(1) 痛点:用户反馈截图看不完
Alice 的 GlobalShop 电商团队每天收到 50+ 条用户反馈,每条附带 UI 截图。手动分析截图写反馈报告太耗时,Alice 希望自动化这个过程。
(2) 解法:视觉模型自动分析截图
用 LLaVA 模型自动分析 UI 截图,生成结构化反馈报告:
BASH
ollama run llava "What UI issues do you see in this image?" /path/to/screenshot.png
3. 多模态模型架构
⚠️ 警告: 多模态模型(如 llava)比纯文本模型大 2-3 倍,且图像处理消耗更多 VRAM。8GB VRAM 的 GPU 可能只能处理低分辨率图像,高分辨率图片可能导致 OOM(内存溢出)。建议先用小图测试。
(1) 视觉语言模型(VLM)原理
flowchart TD
A[Image Input] --> B[Vision Encoder<br/>CLIP/ViT]
B --> C[Image Embeddings]
D[Text Input] --> E[Text Tokenizer]
E --> F[Text Embeddings]
C --> G[Projection Layer]
F --> G
G --> H[Language Model<br/>LLaMA/Mistral]
H --> I[Text Output]
| 组件 | 作用 | 模型示例 |
|---|---|---|
| Vision Encoder | 提取图像特征 | CLIP ViT-L/14 |
| Projection Layer | 对齐视觉与语言空间 | MLP adapter |
| Language Model | 生成文本描述 | LLaMA 2 / Mistral |
(2) 可用多模态模型对比
| 模型 | 参数量 | 大小 | 强项 | 图像类型 |
|---|---|---|---|---|
| llava | 7B | 4.7 GB | 通用图像描述 | 照片/截图/文档 |
| llava-llama3 | 8B | 5.5 GB | 更强推理+视觉 | 复杂场景理解 |
| llava:13b | 13B | 7.4 GB | 更高精度 | 细节识别 |
| minicpm-v | 8B | 5.2 GB | OCR + 中文 | 文档/表格 |
| bakllava | 7B | 4.7 GB | 轻量快速 | 简单图像 |
▶ 示例 1: 拉取与运行 LLaVA
BASH
# Pull the multimodal model
ollama pull llava
# Basic image description (CLI with file path)
ollama run llava "Describe this image in detail" /path/to/photo.jpg
# Without image: text-only mode
ollama run llava "What is machine learning?"
输出:
TEXT
📖 仅展示
I'm a helpful AI assistant running locally on your machine...
4. CLI 图像输入方式
(1) 两种图像输入方式
⚠️ 注意:图像在送入模型前会被自动缩放到模型支持的最大分辨率(通常336×336或448×448像素)。极高分辨率的原图细节可能在此过程中丢失。如果需要模型识别图像中的小字或细节,建议先将图片裁剪到关键区域再输入,而非直接发送整张高分辨率图片。
| 方式 | 语法 | 适用场景 |
|---|---|---|
| 文件路径 | ollama run llava "prompt" /path/to/image.jpg |
本地图片,最简单 |
| 交互式 | 在对话中使用 .image 命令 |
动态输入图片 |
(2) 支持的图像格式
| 格式 | 扩展名 | 最大尺寸 | 说明 |
|---|---|---|---|
| JPEG | .jpg/.jpeg | 限制内 | 照片首选 |
| PNG | .png | 限制内 | 截图/含文字 |
| WebP | .webp | 限制内 | Web 图片 |
| GIF | .gif | 仅首帧 | 不支持动画 |
⚠️ 注意: 图像会缩放到模型支持的分辨率(通常 336×336 或 448×448 像素)。极高分辨率图像细节可能丢失。
▶ 示例 2: CLI 多模态交互
BASH
# Start interactive session with image
ollama run llava
>>> .image /path/to/product-photo.jpg
>>> What product is shown and what are its key features?
# Output: The image shows a pair of premium wireless headphones...
# Key features include:
# 1. Over-ear design with memory foam cushions
# 2. Active noise cancellation
# 3. USB-C charging port visible on the left ear cup
>>> .image /path/to/chart.png
>>> Summarize the data trends shown in this chart
# Output: The chart displays quarterly revenue from 2023-2024...
输出:
TEXT
📖 仅展示
I'm a helpful AI assistant running locally on your machine...
5. REST API 多模态调用
(1) API 请求格式
和 均支持 字段,传入 Base64 编码的图像:
| 字段 | 类型 | 说明 |
|---|---|---|
| images | list[string] | Base64 编码图像列表 |
| 每条 image | string | 不含 data:image/... 前缀 |
▶ 示例 3: REST API Base64 图像调用
BASH
# Convert image to Base64 and call API
IMAGE_BASE64=$(base64 -w 0 /path/to/photo.jpg)
curl http://localhost:11434/api/chat -d "{
\"model\": \"llava\",
\"messages\": [{
\"role\": \"user\",
\"content\": \"Describe this image\",
\"images\": [\"$IMAGE_BASE64\"]
}],
\"stream\": false
}"
输出:
TEXT
📖 仅展示
{"status":"ok","data":{}}
▶ 示例 4: Python SDK 多模态调用
PYTHON
import ollama
import base64
from pathlib import Path
def analyze_image(image_path: str, prompt: str, model: str = "llava") -> str:
"""Analyze an image using a multimodal model."""
# Read and encode image
image_data = base64.b64encode(
Path(image_path).read_bytes()
).decode("utf-8")
response = ollama.chat(
model=model,
messages=[{
"role": "user",
"content": prompt,
"images": [image_data]
}],
stream=False
)
return response["message"]["content"]
# Usage
result = analyze_image(
"/path/to/screenshot.png",
"List all UI issues you can identify in this screenshot"
)
print(result)
输出:
TEXT
📖 仅展示
# 函数定义成功
6. 实战场景
(1) 场景对比
| 场景 | 输入 | 模型推荐 | Prompt 示例 |
|---|---|---|---|
| 产品描述 | 产品照片 | llava | "Describe this product for an e-commerce listing" |
| Bug 分析 | UI 截图 | llava-llama3 | "What UI bugs are visible in this screenshot?" |
| OCR 辅助 | 文档扫描 | minicpm-v | "Extract all text from this document image" |
| 图表解读 | 数据图表 | llava | "Summarize the trends in this data chart" |
| 安全审查 | 内容图片 | llava | "Does this image contain any unsafe content?" |
▶ 示例 5: Alice 的 UI 截图分析
PYTHON
import ollama
import base64
from pathlib import Path
import json
def analyze_ui_screenshot(image_path: str) -> dict:
"""Analyze a UI screenshot and return structured feedback."""
image_data = base64.b64encode(
Path(image_path).read_bytes()
).decode("utf-8")
system_prompt = """You are a UI/UX expert reviewing application screenshots.
Analyze the screenshot and provide feedback in this JSON format:
{
"issues": [{"type": "layout|color|text|accessibility", "description": "...", "severity": "high|medium|low"}],
"summary": "Brief overall assessment"
}"""
response = ollama.chat(
model="llava-llama3",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": "Review this UI screenshot for issues",
"images": [image_data]}
],
stream=False,
format="json",
options={"temperature": 0.3}
)
try:
return json.loads(response["message"]["content"])
except json.JSONDecodeError:
return {"raw": response["message"]["content"]}
# Usage
feedback = analyze_ui_screenshot("/path/to/app-screenshot.png")
print(json.dumps(feedback, indent=2))
输出:
TEXT
📖 仅展示
# 函数定义成功
7. 综合示例:多模态客服辅助系统
PYTHON
# ============================================
# Comprehensive: Multimodal customer service
# Image analysis + text chat for e-commerce
# ============================================
import ollama
import base64
from pathlib import Path
from dataclasses import dataclass
from typing import Optional
@dataclass
class MultimodalSupport:
chat_model: str = "qwen2.5"
vision_model: str = "llava"
temperature: float = 0.3
def handle_product_query(
self, image_path: str, question: str
) -> str:
"""Answer product questions using image + text."""
image_data = base64.b64encode(
Path(image_path).read_bytes()
).decode("utf-8")
response = ollama.chat(
model=self.vision_model,
messages=[{
"role": "user",
"content": f"Answer this question about the product shown: {question}",
"images": [image_data]
}],
stream=False,
options={"temperature": self.temperature}
)
return response["message"]["content"]
def handle_damage_report(
self, image_path: str, order_id: str
) -> str:
"""Process a damage report with photo evidence."""
image_data = base64.b64encode(
Path(image_path).read_bytes()
).decode("utf-8")
# Step 1: Analyze damage from image
damage_desc = ollama.chat(
model=self.vision_model,
messages=[{
"role": "user",
"content": "Describe the damage visible in this product photo. Be specific about the type and severity.",
"images": [image_data]
}],
stream=False,
options={"temperature": 0.2}
})["message"]["content"]
# Step 2: Generate response using chat model
response = ollama.chat(
model=self.chat_model,
messages=[
{"role": "system", "content": "You are an e-commerce customer service agent handling damage reports."},
{"role": "user", "content": f"Order {order_id} has damage: {damage_desc}. Generate a polite response acknowledging the damage and explaining the refund/replacement process."}
],
stream=False,
options={"temperature": self.temperature}
)
return response["message"]["content"]
def extract_text_from_image(
self, image_path: str
) -> str:
"""OCR-like text extraction from document images."""
image_data = base64.b64encode(
Path(image_path).read_bytes()
).decode("utf-8")
response = ollama.chat(
model="minicpm-v",
messages=[{
"role": "user",
"content": "Extract all visible text from this image. Preserve the original layout and formatting.",
"images": [image_data]
}],
stream=False,
options={"temperature": 0.1}
)
return response["message"]["content"]
# Usage
if __name__ == "__main__":
service = MultimodalSupport()
print("=== Damage Report ===")
# print(service.handle_damage_report("damaged_item.jpg", "#12345"))
print("=== Product Query ===")
# print(service.handle_product_query("headphones.jpg", "Does this have noise cancellation?"))
print("=== OCR Extraction ===")
# print(service.extract_text_from_image("receipt.png"))
❓ 常见问题
Q 多模态模型和纯文本模型能互换吗?
A 不能。多模态模型处理图像+文本,纯文本模型只处理文本。多模态模型无图像时也可处理纯文本,但纯文本模型不能处理图像。
Q 图像分辨率会影响推理速度吗?
A 会。更高分辨率图像编码更多 token,增加推理时间。Ollama 自动缩放到模型支持的最大分辨率,无需手动调整。
Q 一张图片能包含多个问题吗?
A 可以。在 prompt 中列出多个问题,模型会逐一回答。但建议每次聚焦 1-2 个问题以获得更准确回答。
Q llava 的中文能力如何?
A llava 主要面向英文。中文图像描述建议用 minicpm-v 或 qwen2.5-vl(如果可用)。Prompt 用中文可获得中文回复。
Q 视频能处理吗?
A 当前 Ollama 多模态仅支持静态图像。视频需先提取关键帧为图片,再逐帧分析。GIF 只处理首帧。
Q Base64 编码图片太大怎么办?
A 图片先压缩到合理分辨率(如 1024px 内)。JPEG 质量设为 80 通常够用。避免发送 10MB+ 原图。
📖 小节
- 多模态模型 = 视觉编码器 + 投影层 + 语言模型,实现图文理解
- llava 系列是 Ollama 主要视觉模型,支持照片/截图/文档
- CLI 用文件路径输入图片,API 用 Base64 编码 images 字段
- 实战场景:产品描述、Bug 分析、OCR 辅助、图表解读
- Python SDK 通过 images 列表传递 Base64 图像数据
- Alice 用 llava 自动化 UI 截图分析,每张从 10 分钟缩短到 5 秒
📝 作业
- 基础题(难度⭐):拉取 llava 模型,用 CLI 分析一张产品照片,描述产品特征。
- 进阶题(难度⭐⭐):用 Python SDK 实现图片+文本多轮对话——先分析图片内容,再基于分析结果深入提问。
- 挑战题(难度⭐⭐⭐):为 Alice 构建一个 UI 截图自动审查工具:输入截图,输出结构化 JSON 格式的 Bug 报告(类型、描述、严重程度),并自动分类归档。