# Ollama Vision API: как отправить изображение и проверить ответ локально

Источник: https://modelium.tech/zhurnal/ollama-vision-api/

Для анализа изображения в локальной Ollama выберите модель с поддержкой Image input и передайте PNG как base64 в `messages[].images` метода `/api/chat`. Начните с искусственного рисунка с известными цветами, проверьте JSON-ответ и сверьте описание с оригиналом. Успешный HTTP-ответ не доказывает корректность распознавания или отсутствие обращений в сеть.

**Документация и каталог просмотрены 26 сентября 2026 года.** Команда и тест ниже описывают способ самостоятельной проверки, а не измерение Modelium: мы не скачивали модель и не выполняли inference. Формулировка запроса найдена в Google Suggest; его частотность неизвестна.

## Что делает Vision API и когда он подходит?

Vision-модель принимает изображение вместе с текстовым вопросом. Документация Ollama показывает два пути: локальный CLI и REST-вызов, где изображение в `images` передают в base64; в Python/JavaScript SDK допускаются также путь, URL и байты [s1](#src-s1). Здесь разбираем **локальный REST API**, чтобы видеть входной JSON, HTTP-ответ и текст модели по отдельности. Для пилота выберите изображение с заранее известной истиной, а не секретный скан клиента.

Задача этого гайда — получить описание простой картинки и отличить три результата: сервер ответил; мультимодальная модель действительно получила изображение; её ответ совпал с наблюдаемым содержимым. Первое не гарантирует второе и третье. Если нужны поля счёта или УПД, сравните задачу с [извлечением документов для 1С](/zadachi/raspoznavanie-dokumentov-1s/): свободное описание картинки не равно верифицированному OCR и разбору реквизитов.

## Какая модель и компьютер нужны до вызова API?

Предположим, что Ollama уже установлена и сервер слушает только локальный интерфейс. Для установки и проверки обычного сервера есть [базовый гайд Ollama](/zapusk/ollama/). Зафиксируйте вашу версию командой `ollama --version`; это значение пользователь получает **на своей машине**, а не из статьи. Без измерения на вашем устройстве не обещаем скорость или минимальную память.

В каталоге Ollama тег `gemma3:4b` обозначен `Text, Image`, а `gemma3:1b` — `Text`: **не заменяйте** 4b на 1b только потому, что он меньше [s6](#src-s6). На дату просмотра у `gemma3:4b` в каталоге указан файл 3,3 ГБ и сокращённый идентификатор `a2af6cc3eb7f`; это размер артефакта и метка каталога, **не** нижняя граница RAM/VRAM, не benchmark и не гарантия неизменности тега [s6](#src-s6). Для другого железа/качества выберите иной вариант с Image input; не переносите свойства модели автоматически на всё семейство.

# Команды выполняются на ВАШЕЙ локальной машине с уже установленной Ollama.curl -fsS http://127.0.0.1:11434/api/tagsollama pull gemma3:4bcurl -fsS http://127.0.0.1:11434/api/tags

`/api/tags` возвращает локальные модели, их `name`, `digest` и размер на диске; найдите там ровно `gemma3:4b` и запишите **полный** digest своего экземпляра для повторяемости [s4](#src-s4). `ollama pull` обращается к реестру для получения весов: это сетевой шаг, а не проверка полностью автономного контура; документирован также POST `/api/pull` [s7](#src-s7). До загрузки оцените свободное место и разрешённость модели/её условий для своей организации отдельно. Если модель уже установлена, повторная загрузка для выполнения примера не нужна. Никакого вывода об оперативной памяти из размера загрузки не делайте.

## Как создать безопасную картинку с известным ответом?

Ниже **собственный тестовый сценарий**, а не характеристика Ollama. Python 3 из стандартной библиотеки создаёт PNG размером 192×96: слева сплошной красный прямоугольник, справа сплошной синий. Реальных документов и персональных данных здесь нет. Запускайте в пустом рабочем каталоге, чтобы не перезаписать свой `test.png`:

from pathlib import Pathimport structimport zlibw, h = 192, 96raw = b''.join(    b'\x00' + b''.join(        b'\xff\x00\x00' if x < w // 2 else b'\x00\x00\xff'        for x in range(w)    )    for _ in range(h))def chunk(tag, data):    return (struct.pack('!I', len(data)) + tag + data            + struct.pack('!I', zlib.crc32(tag + data) & 0xffffffff))png = (b'\x89PNG\r\n\x1a\n'       + chunk(b'IHDR', struct.pack('!2I5B', w, h, 8, 2, 0, 0, 0))       + chunk(b'IDAT', zlib.compress(raw))       + chunk(b'IEND', b''))Path('test.png').write_bytes(png)print('Создан test.png:', len(png), 'байт')

Откройте `test.png` обычным просмотрщиком, прежде чем обращаться к API. Истина для этой пробы: **красный слева, синий справа; никаких букв, людей и предметов**. Отдельно отметьте файл и дату пробы: если впоследствии подставить другое изображение, сравнение потеряет смысл.

## Как отправить PNG в `/api/chat`?

В REST поле `images` находится **внутри сообщения** `messages[]`. Передавайте base64-содержимое PNG, не строку `test.png`: путь к файлу в примере документации работает для SDK, но JSON REST ожидает base64 [s1](#src-s1)[s2](#src-s2). Этот пример выполняет один запрос к `127.0.0.1` без сторонних Python-пакетов; если сервер на другом компьютере, настройка сетевого доступа и его защита — отдельная задача, не выставляйте порт 11434 в интернет.

from pathlib import Pathfrom urllib.request import Request, urlopenfrom urllib.error import HTTPError, URLErrorimport base64import jsonimage = base64.b64encode(Path('test.png').read_bytes()).decode('ascii')payload = {    'model': 'gemma3:4b',    'messages': [{        'role': 'user',        'content': 'Опиши только цвета двух половин изображения слева направо. Если текста нет, не придумывай его.',        'images': [image],    }],    'stream': False,}request = Request(    'http://127.0.0.1:11434/api/chat',    data=json.dumps(payload).encode('utf-8'),    headers={'Content-Type': 'application/json'},    method='POST',)try:    with urlopen(request, timeout=120) as response:        result = json.load(response)except (HTTPError, URLError) as exc:    raise SystemExit(f'Проверьте локальный сервер, модель и HTTP-ответ: {exc}')print('model:', result.get('model'), 'done:', result.get('done'))print('answer:', result.get('message', {}).get('content', ''))

`stream: false` важен для простого `json.load`: иначе API по умолчанию отправляет поток JSON-событий. Непотоковый `/api/chat` возвращает `message.content` и `done`; `done: true` означает завершение генерации, а **не верность ответа** [s2](#src-s2). Не смешивайте вызовы: `/api/generate` кладёт `images` в корень JSON и отдаёт текст в `response`; этот пример намеренно использует только `/api/chat` [s3](#src-s3). Не сохраняйте чувствительное изображение или длинный base64 в CI-логи.

## Что считать подтверждённым результатом?

- `/api/tags` после загрузки содержит нужный тег и digest; запишите также `ollama --version`, ОС и путь к вашему PNG. Это подтверждает **наличие модели**, а не её использование [s4](#src-s4).

- POST возвращает HTTP 200, `done: true`, поле `model` соответствует выбранному тегу и ответ не пуст. Это подтверждает завершение запроса, а не корректное восприятие картинки [s2](#src-s2).

- Сравните ответ с `test.png`: красный должен быть слева, синий справа. Отметьте отдельно перепутанные цвета/стороны, придуманный текст или отказ; не переписывайте ожидаемый ответ по итогам модели. Повторите с переставленными цветами в *новом* PNG и новой записью истины, чтобы исключить шаблонное угадывание. **Это предлагаемый протокол, не опубликованная оценка точности Modelium.**

- После обращения запросите `curl -fsS http://127.0.0.1:11434/api/ps`: список показывает действительно загруженные модели, а `size_vram` — использование VRAM данным процессом в момент ответа. Пустой список позднее не доказывает отсутствие прогона: модель могла выгрузиться [s5](#src-s5). `ollama ps` помогает увидеть размещение CPU/GPU; это не минимальное требование к железу [s8](#src-s8).

Если все четыре проверки пройдены, у вас есть подтверждение **собственного** теста на синтетическом PNG и вашей ревизии модели. Это ещё не валидация для фото, русских сканов, таблиц или классификации документов. Для реальной задачи соберите раздельный набор с эталонной разметкой и фиксируйте ошибки по типам, а не один удачный ответ.

## Почему запрос не работает или даёт неверный ответ?

- **Соединение отклонено:** сначала проверьте запуск Ollama и точный адрес `127.0.0.1:11434`; руководство по [установке Ollama](/zapusk/ollama/) отделяет сервер от модели. Не чините локальную ошибку публикацией незащищённого API в интернет.

- **Модель не найдена:** сверьте строку `model` с `/api/tags`, дождитесь окончания `ollama pull` и зафиксируйте локальный digest [s4](#src-s4)[s7](#src-s7).

- **Текстовый тег вместо vision:** проверьте входные модальности **именно тега**, а не название семейства; `gemma3:1b` в просмотренном каталоге не отмечен как Image input [s6](#src-s6).

- **Неверный JSON или пустой **`**message.content**`**:** проверьте base64 PNG без префикса `data:image/...`, вложенность `messages[].images`, `stream: false`, HTTP-ошибку и поле `done` [s1](#src-s1)[s2](#src-s2).

- **Ответ уверенно неверен:** зафиксируйте неудачу; другой prompt или модель — новый эксперимент, а не правка эталона. При сложной картинке сопоставляйте с исходным изображением и человеческой разметкой. Смена размера файла весов не даёт оценки качества.

- **Нужен закрытый контур:** локальный адрес запроса не доказывает отсутствие прочих сетевых вызовов. По FAQ, облачные функции отключаются отдельно с `OLLAMA_NO_CLOUD=1` или конфигурацией `server.json`; отдельно выполните [проверку сетевого контура](/zhurnal/proverka-offline-kontura-ii/) [s8](#src-s8).

Для отката теста сохраните результаты и digest, затем удалите только созданный вами `test.png`. Удалять установленную модель ради отката одного запроса не нужно. Если задача стала извлечением реквизитов или данных таблиц, перейдите к [сценарию документов для 1С](/zadachi/raspoznavanie-dokumentov-1s/) вместо расширения одного vision-prompt. **Следующий шаг:** [подготовьте и проверьте локальную Ollama](/zapusk/ollama/), после чего выполните цветовой тест на своей машине и сохраните ответ рядом с эталоном.

## Источники

1. [Ollama — Vision](https://docs.ollama.com/capabilities/vision.md) — получено 2026-09-26
2. [Ollama — API: Generate a chat message](https://docs.ollama.com/api/chat.md) — получено 2026-09-26
3. [Ollama — API: Generate a response](https://docs.ollama.com/api/generate.md) — получено 2026-09-26
4. [Ollama — API: List models](https://docs.ollama.com/api/tags.md) — получено 2026-09-26
5. [Ollama — API: List running models](https://docs.ollama.com/api/ps.md) — получено 2026-09-26
6. [Ollama — каталог тегов Gemma 3](https://ollama.com/library/gemma3/tags) — получено 2026-09-26
7. [Ollama — API: Pull a model](https://docs.ollama.com/api/pull.md) — получено 2026-09-26
8. [Ollama — FAQ: локальный режим, облако и размещение модели](https://docs.ollama.com/faq.md) — получено 2026-09-26
