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 APIhttp://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 помогают ловить регрессии.