Ollama превращает тяжёлые мультимодальные модели типа LLaVA в обычную CLI-команду, которую можно гонять на своём железе, засовывать в Python-скрипт и масштабировать на целые папки с изображениями. Ниже полный маршрут от одного снимка до production-пайплайна.
Что это
Ollama: единый менеджер моделей с локальным HTTP API на http://localhost:11434. Он умеет запускать не только текстовые LLM, но и мультимодальные модели типа LLaVA (Large Language and Vision Assistant), которые принимают на вход изображение и текстовый промпт и возвращают связный ответ. Внутри LLaVA это vision encoder (как правило, CLIP) и языковая модель, соединённые через проекционный слой; пользователю не нужно собирать это вручную, Ollama скачивает готовые веса и поднимает рантайм одной командой.
Мультимодальность: это способность модели принимать и связывать несколько типов входа (текст плюс изображение, иногда аудио) и генерировать ответ, который опирается на весь контекст. Для визуального ИИ это означает переход от «у нас есть координаты bbox и метки классов» к «модель понимает, что на снимке, как объекты связаны и какую историю они рассказывают».
Ollama как фреймворк делает это локальным: модели крутятся на вашем CPU/GPU, HTTP API доступен любому скрипту, никаких внешних ключей и квот. С версии 0.4 в Ollama есть нативный format для JSON-Schema, что превращает «опиши картинку» в надёжный structured output для интеграций.
Зачем нужно
- Чувствительные изображения остаются на вашем контуре: медицинские снимки, корпоративные документы, личная переписка не уходят в стороннее облако, что важно для GDPR и HIPAA.
- Предсказуемая задержка и нулевая зависимость от сети. Пайплайн не падает, когда у провайдера outage или лимиты на бесплатный tier.
- Edge-сценарии и offline-инструменты: инспекция линий, полевые утилиты, обработка скриншотов на устройстве.
- Снижение стоимости на больших объёмах. Разница между $0.14 за 1M токенов у облачного vision API и нулевой стоимостью локальной модели становится заметной, когда обрабатываешь тысячи картинок в сутки.
- Демократизация: мультимодальные модели больше не требуют команды CV-инженеров: одна команда, одна модель, и через минуту идёт ответ.
- Контроль над экспериментами: выбор модели (7B, 13B, 34B), температура, system prompt, формат вывода настраиваются локально, без согласований с вендором.
Как устроено
| Vision encoder | Превращает изображение в эмбеддинги | Внутри модели (обычно CLIP-L) |
|---|---|---|
| Проекционный слой | Связывает визуальные токены с пространством LLM | Внутри модели |
| Языковая база | Vicuna / Mistral / Hermes-Yi для LLaVA-1.6 | Веса скачиваются Ollama |
| HTTP API | http://localhost:11434/api/generate, images: \[base64\] | Поднимается командой ollama serve |
| Modelfile | Системный промпт, параметры, шаблон | ollama create -f Modelfile |
Поток выглядит так: изображение читается с диска → кодируется в Base64 (или передаётся в CLI как путь) → уходит в POST /api/generate с model: "llava" и prompt: "..." → Ollama гоняет forward pass через vision encoder + LLM → возвращает текст ответа (или JSON, если задан format).
Для LLaVA в экосистеме Ollama доступны три основных размера:
| 7B (Vicuna / Mistral) | Лёгкий, ~5–8 GB VRAM в q4 | Старт, тест концепции, деплой на малом железе, базовое описание сцен и объектов |
|---|---|---|
| 13B (Vicuna) | Средний, ~10–14 GB VRAM в q4 | Заметный прирост к качеству понимания контекста и детализации по сравнению с 7B |
| 34B (Hermes-Yi) | Тяжёлый, ~20+ GB VRAM в q4 | Самый сильный в линейке LLaVA-1.6, лучше на MMMU и MathVista, нужен мощный GPU |
LLaVA-1.6 с Hermes-Yi-34B обходит Gemini Pro на бенчмарках MMMU и MathVista по данным официального репозитория.
Когда использовать
| Медицинский снимок нужно описать без отправки в облако | Да | GDPR/HIPAA, полный контур остаётся на вашем железе |
|---|---|---|
| Девять тысяч скриншотов из regression-тестов надо проверить на наличие ключевых элементов | Да | Batch-режим на CPU-пуле процессов, structured output для автоматической валидации |
| Разметка каталога товаров для интернет-магазина (50–100 фото в день) | Да | Дешевле облачного vision API, не зависит от квот |
| Интерактивный ассистент, который по фото объясняет «что на снимке» в реальном времени | Да | Локальная latency стабильна, нет сетевых пиков |
| Точная медицинская диагностика или юридический анализ документа | Нет | LLaVA, не сертифицированный диагностический инструмент. Нужны профильные модели с клиническими валидациями |
| Задача требует 100% uptime в production с горизонтальным масштабированием | С оговоркой | Ollama оптимизирован под один узел, для HA нужен внешний балансировщик и реплики |
| Одноразовая проверка одной картинки, железо слабое | Возможно | Если есть 7B и хотя бы 8 GB RAM, пройдёт на CPU медленно; иначе проще облако |
| OCR паспортов с извлечением полей в JSON | С оговоркой | LLaVA понимает макет и читает текст, но для продакшна-OCR нужен fine-tune или специализированная модель |
Пример
Базовый CLI-вызов для одного снимка (актуальный синтаксис по официальной документации Ollama: промпт и путь через пробел в кавычках):
ollama run llava "Опиши, что происходит на этой фотографии, и выдели все надписи" /путь/к/изображению.jpg
Для интеграции в Python через HTTP API:
import base64
import requests
OLLAMA = "http://localhost:11434"
def describe_image(path: str, prompt: str) -> str:
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")
r = requests.post(f"{OLLAMA}/api/generate", json={
"model": "llava",
"prompt": prompt,
"images": [b64],
"stream": False,
})
return r.json()["response"]
print(describe_image("cat.jpg", "Что на фото? Перечисли объекты и настроение сцены."))
Пакетная обработка папки с параллелизмом и сохранением JSON:
import base64
import json
import os
from concurrent.futures import ProcessPoolExecutor
import requests
OLLAMA = "http://localhost:11434"
def analyze(path: str) -> dict:
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")
r = requests.post(f"{OLLAMA}/api/generate", json={
"model": "llava",
"prompt": "Опиши изображение. Верни строго JSON: {\"objects\":[],\"scene\":\"\",\"mood\":\"\"}",
"images": [b64],
"stream": False,
"format": {
"type": "object",
"properties": {
"objects": {"type": "array", "items": {"type": "string"}},
"scene": {"type": "string"},
"mood": {"type": "string"},
},
"required": ["objects", "scene", "mood"],
},
}, timeout=120)
return {"file": path, "result": r.json().get("response", "")}
def batch(input_dir: str, output_json: str, max_workers: int = 4):
files = [
os.path.join(input_dir, f)
for f in os.listdir(input_dir)
if f.lower().endswith((".jpg", ".jpeg", ".png", ".webp"))
]
results = []
with ProcessPoolExecutor(max_workers=max_workers) as pool:
for r in pool.map(analyze, files):
results.append(r)
with open(output_json, "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
return results
if __name__ == "__main__":
batch("./screenshots", "./report.json", max_workers=4)
Интеграция в FastAPI-бэкенд для веб-приложения:
from fastapi import FastAPI, UploadFile, File
import base64, requests
app = FastAPI()
@app.post("/vision")
async def vision(file: UploadFile = File(...), prompt: str = "Что на картинке?"):
data = await file.read()
b64 = base64.b64encode(data).decode("utf-8")
r = requests.post("http://localhost:11434/api/generate", json={
"model": "llava",
"prompt": prompt,
"images": [b64],
"stream": False,
}, timeout=120)
return {"answer": r.json().get("response", "")}
Ограничения
Ограничения
Что учитывать
Короткое вводное предложение.
Синтаксис CLI в сторонних гайдах устаревает
ранние примеры использовали флаг -i /path, в актуальной документации Ollama изображение передаётся в одних кавычках через пробел после промпта; всегда сверяйтесь с docs.ollama.com/cli.
LLaVA-1.6 34B требует мощного GPU
Hermes-Yi-34B в квантизации q4 занимает более 20 GB VRAM, на 8-гиговых картах запустится только 7B или 13B.
Latency на CPU ощутима
один снимок 1024×1024 на 7B без GPU обрабатывается 5–15 секунд; для batch в тысячи файлов нужен multiprocessing или вынос на GPU-ноду.
Structured output не гарантирует 100% валидности
JSON-Schema через format сильно повышает надёжность, но на длинных или хитрых картинках модель может вернуть частично невалидный JSON; в production нужен парсер с fallback.
LLaVA
не сертифицированный диагностический инструмент — для медицины, права, финансов её ответы нужно валидировать человеком или профильной моделью, прошедшей клинические испытания.
Ollama оптимизирован под один узел
горизонтальное масштабирование требует внешнего балансировщика и поднятия нескольких инстансов; «из коробки» HA нет.
Контекстное окно ограничено визуальным токеном
длинные документы с десятками страниц подаются постранично, общая связность между страницами не сохраняется автоматически.
Антипаттерны
Антипаттерны
Чего не делать
Короткое вводное предложение.
Не отправляйте чувствительные снимки в облако «для скорости», а потом обратно в Ollama
теряется смысл локального запуска и создаётся двойной контур утечек.
Не пишите «опиши картинку» и парсите свободный текст в production
используйте format с JSON-Schema и валидацию, иначе интеграция ломается на каждом втором ответе.
Не гоняйте 34B на CPU без теста памяти
процесс упадёт по OOM в середине батча, потеряются уже обработанные файлы; сначала прогон на 1–2 картинках.
Не считайте LLaVA заменой специализированного OCR
для паспортов, чеков, юридических документов точность ниже, чем у PaddleOCR / EasyOCR / Tesseract + fine-tune.
Не забывайте про rate control — даже локальный Ollama можно забить запросами:
для нагруженных пайплайнов добавляйте Redis-очередь или файл-очередь, иначе GPU-память закончится.
Не вызывайте `ollama run` на каждую картинку из Python-цикла
поднимайте ollama serve один раз и работайте через HTTP API, иначе на каждой итерации модель выгружается и загружается снова.
Не используйте один и тот же промпт для разных задач
для «найди кнопку Оплатить и верни координаты или null» и для «опиши сцену» нужны разные system-prompt и разные схемы format, иначе модель будет фантазировать.
Чеклист
Чеклист
Проверка перед запуском
Короткое вводное предложение.
Ollama установлена и `ollama —version` отдаёт ≥ 0.4
без поддержки format для JSON-Schema structured output работает, но интеграции хрупкие.
Модель скачана:
`ollama pull llava` (или llava:7b, llava:13b, llava:34b) — без pull HTTP API вернёт 404 на незнакомое имя.
`ollama serve` поднят и порт 11434 отвечает
проверить curl http://localhost:11434/api/tags.
Хватает VRAM под выбранный размер модели
7B ~5–8 GB q4, 13B ~10–14 GB q4, 34B ~20+ GB q4; на CPU закладывать RAM с запасом ×1.5.
Для batch есть multiprocessing и сохранение промежуточных результатов
иначе ошибка на одном файле обнулит весь прогресс.
Промпт и `format` протестированы на 5–10 реальных изображениях
структурированный вывод валидируется парсером, не «на глаз».
Для веб-интеграции есть CORS и лимит размера загрузки
браузер не отдаст файл >10 MB без дополнительной настройки FastAPI/Flask.
Логи и метрики собираются
total\_duration, eval\_count, prompt\_eval\_count из ответа /api/generate помогают ловить регрессии.