# LM Studio Vision API: отправить изображение и проверить ответ модели

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

В LM Studio Vision API отправьте изображение как base64 data URL в элементе `type: image` запроса `POST /api/v1/chat`. Сначала проверьте `capabilities.vision` и загруженный экземпляр через `GET /api/v1/models`, затем сравните описание простого тестового PNG с известным оригиналом. Успешный HTTP-ответ сам по себе не доказывает качество распознавания или отсутствие внешних сетевых соединений.

**Проверено по документации 29 сентября 2026 года.** Ниже протокол для версии LM Studio с нативным REST API `/api/v1/chat`, а не собственный прогон Modelium. Google Suggest подтверждает формулировку запроса, но не частотность; модель/веса не скачивались, распознавание не измерялось.

## Когда нужен именно LM Studio Vision API?

Если уже используете LM Studio и хотите послать картинку из своего кода, нативный REST-метод `POST /api/v1/chat` принимает текст и элемент изображения с `type: "image"`, `data_url` в формате base64 data URL [s1](#src-s1). Это отличается от API Ollama и OpenAI-совместимого endpoint других серверов: не копируйте их JSON-поля без проверки. Для обычной установки откройте [гайд LM Studio](/zhurnal/lm-studio/), а для другого runtime — [Ollama Vision API](/zhurnal/ollama-vision-api/).

Результат этого сценария — **один сохранённый запрос, один ответ и ручное сравнение с оригиналом**. Успешный HTTP 200 и непустой текст не устанавливают ни точность OCR, ни пригодность к реальным счетам. Начните с безопасного искусственного PNG, в котором известны две цветные половины; важные документы проверяйте позднее по собственной разметке и правилам доступа.

## Что проверить до передачи изображения?

Нужны установленный LM Studio с доступным нативным REST API, скачанная **именно мультимодальная LLM** и включённый сервер. Запустите `lms server start`, проверьте `lms server status` и установленный у вас порт. Документация для CLI указывает bind `127.0.0.1` по умолчанию; `--bind 0.0.0.0` открывает доступ за пределы localhost, поэтому для этого примера его не используйте [s4](#src-s4). Значение `1234` ниже — документированный пример; если вы изменили порт, измените и адрес в командах [s4](#src-s4).

lms server startlms server statuscurl -fsS http://127.0.0.1:1234/api/v1/models

`GET /api/v1/models` возвращает `models[]` с `key`, `type`, `capabilities.vision` и `loaded_instances` [s2](#src-s2). Найдите строку с `type: "llm"` и `capabilities.vision: true`; `type: "embedding"` и текстовая LLM сюда не подходят [s2](#src-s2). Для повторяемости запишите полный `key`, формат/квант из своего ответа и `loaded_instances[].id`, а не угадывайте имя модели по рекламному названию. Если такой модели нет, сначала изучите возможности конкретного артефакта, условия применения и ресурсы своего компьютера; не делайте вывод о минимальной памяти из `size_bytes` — это размер файлов модели, а не измерение её размещения [s2](#src-s2).

Если подходящая модель скачана, но `loaded_instances` пуст, загрузите **указанный в своём ответе** `key` через интерфейс LM Studio или задокументированный `POST /api/v1/models/load`; ответ должен содержать `status: "loaded"` и `instance_id` [s3](#src-s3). CLI `lms ls` показывает локальные модели, `lms load --estimate-only <model_key>` даёт предварительную оценку ресурса без загрузки, а `lms load <model_key>` выполняет её [s7](#src-s7). Оценка до запуска — не тест пригодности, скорости или точности на вашем компьютере; не заставляйте читателя загружать неизвестную крупную модель ради примера. Если сервер настроен на JIT, это отдельная политика загрузки, которую можно проверить в Server Settings [s8](#src-s8).

По умолчанию API-токен LM Studio не требует; в версии 0.4.0+ администратор может включить `Require Authentication`, после чего необходим действительный `Authorization: Bearer` [s5](#src-s5). Если защищаете API, задайте `LM_STUDIO_API_TOKEN` **локально в окружении перед скриптом**, не вставляйте секрет в статью, URL, репозиторий или снимок запроса. При ошибке 401 проверьте именно настройки токена; не отключайте защиту публичного сетевого сервера ради диагностики. В Server Settings отдельно существуют опции локальной сети, CORS и разрешений MCP, которые этот тест не использует [s8](#src-s8).

## Как создать изображение с известным эталоном?

В пустой директории создайте `test.png` этой программой Python 3 (только стандартная библиотека). Откройте полученный файл просмотрщиком: слева красная половина, справа синяя, текста и объектов нет. Это синтетический тест Modelium **как процедура для читателя**, не утверждение о том, что наша инфраструктура запускала модель.

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')

Не заменяйте тестовую картинку приватным сканом до проверки доступа, журнала запросов и применимости условий модели. Для реальной документации одного свободного описания кадра недостаточно: нужен эталон для каждого поля.

## Как вызвать нативный `/api/v1/chat`?

Следующий скрипт запускайте в той же директории после загрузки vision-модели. Он сам берёт **единственную уже загруженную** vision-LLM из `/api/v1/models`; при нуле или нескольких экземплярах останавливается, не выбирая модель наугад. `data_url` включает префикс `data:image/png;base64,` и содержимое PNG, а не путь `test.png`: так описан контракт изображения у LM Studio [s1](#src-s1)[s2](#src-s2). Если несколько моделей подходят, разгрузите лишние или отредактируйте выбор под заранее записанный точный `key`, проверив возвращённый объект.

from pathlib import Pathfrom urllib.request import Request, urlopenfrom urllib.error import HTTPError, URLErrorimport base64import jsonimport osbase = 'http://127.0.0.1:1234'headers = {'Content-Type': 'application/json'}if os.getenv('LM_STUDIO_API_TOKEN'):    headers['Authorization'] = 'Bearer ' + os.environ['LM_STUDIO_API_TOKEN']def read_json(path, payload=None):    request = Request(base + path, headers=headers,                      data=None if payload is None else json.dumps(payload).encode('utf-8'),                      method='GET' if payload is None else 'POST')    try:        with urlopen(request, timeout=180) as response:            return json.load(response)    except (HTTPError, URLError) as exc:        raise SystemExit(f'Проверьте сервер, порт, токен и модель: {exc}')models = read_json('/api/v1/models')['models']loaded = [(m['key'], item['id']) for m in models          if m.get('type') == 'llm' and m.get('capabilities', {}).get('vision') is True          for item in m.get('loaded_instances', [])]if len(loaded) != 1:    raise SystemExit(f'Нужна одна загруженная vision-LLM; обнаружено: {len(loaded)}')model_key, instance_id = loaded[0]data_url = ('data:image/png;base64,' +            base64.b64encode(Path('test.png').read_bytes()).decode('ascii'))result = read_json('/api/v1/chat', {    'model': model_key,    'input': [        {'type': 'text', 'content': 'Опиши цвета двух половин слева направо. Если текста нет, не выдумывай его.'},        {'type': 'image', 'data_url': data_url},    ],    'stream': False,    'store': False,})print('model:', model_key)print('expected loaded instance:', instance_id)print('actual instance:', result.get('model_instance_id'))messages = [item.get('content', '') for item in result.get('output', [])            if item.get('type') == 'message']print('answer:', '\n'.join(messages))

`stream: false` позволяет читать единый JSON вместо событий SSE, а `store: false` отключает сохранение этого чата в механизме данного запроса; эти поля не являются гарантиями стирания сетевых или системных логов [s1](#src-s1). Проверяйте `output[]` с элементом `type: message`, `content` и `model_instance_id` из ответа: это поля нативного API, не `choices[0].message.content` чужого контракта [s1](#src-s1). Не записывайте base64-картинку или API-токен в CI-лог. Команда задаёт только локальный адрес, не проверяет все остальные соединения устройства.

## Как понять, что тест удался?

- `GET /api/v1/models` вернул **конкретный** vision `key`, а `loaded_instances` показал загруженный экземпляр; зафиксируйте версию LM Studio и параметры вашего запуска [s2](#src-s2).

- `POST /api/v1/chat` вернул JSON с `model_instance_id` и непустым `output[].content` сообщения; сверяйте идентификатор с выбранным загруженным экземпляром. Ответ без подходящей загрузки, ошибку 401 и HTTP 400 фиксируйте отдельно [s1](#src-s1)[s2](#src-s2)[s5](#src-s5).

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

Для реального теста сохраните версию приложения, `key`/вариант модели, входной файл или его хеш, prompt, статус ответа и ручной вердикт. Не сохраняйте персональные документы в открытом репозитории. Никаких собственных vision-измерений Modelium не проводил: всё выше — **ожидаемая процедура по документации**, а не протокол выполненного прогона.

## Что делать при сбоях и как убрать тест?

- **Нет соединения:** проверьте `lms server status`, порт и привязку к `127.0.0.1`; не публикуйте сервер через `0.0.0.0` как обход ошибки [s4](#src-s4).

- **401/403:** уточните `Require Authentication`, разрешения токена и локальную переменную окружения. Не печатайте её значение [s5](#src-s5).

- **Нет vision-модели или она не загружена:** сверяйте `capabilities.vision`, `key` и `loaded_instances`, затем оцените память через `lms load --estimate-only` либо загрузите подходящий уже скачанный экземпляр; оценка не равна фактическому RAM/VRAM [s2](#src-s2)[s3](#src-s3)[s7](#src-s7).

- **Неверный формат изображения/ответа:** передайте полный base64 data URL в элементе `input` с `type: image`; ответ ищите в `output`, а не в `choices` [s1](#src-s1).

- **Нужен полностью закрытый контур:** по документации уже скачанная модель и локальный сервер могут работать офлайн, но поиск моделей, загрузка runtime и обновления требуют сети [s6](#src-s6). Локальный URL сам по себе не доказывает отсутствие внешних запросов: отдельно выполните [сетевую проверку своей установки](/zhurnal/proverka-offline-kontura-ii/).

Для отката удалите только созданный вами `test.png` и сохранённые тестовые ответы; `lms unload <model_key>` может выгрузить модель из памяти, не удаляя файлы — используйте его, только если экземпляр принадлежит вашему тесту и не обслуживает других клиентов [s7](#src-s7). **Следующий шаг:** [подготовьте локальную LM Studio](/zhurnal/lm-studio/), затем выполните цветовой тест на своём компьютере и сохраните результат рядом с эталоном.

## Источники

1. [LM Studio — REST API: Chat with a model](https://lmstudio.ai/docs/developer/rest/chat) — получено 2026-09-29
2. [LM Studio — REST API: List your models](https://lmstudio.ai/docs/developer/rest/list) — получено 2026-09-29
3. [LM Studio — REST API: Load a model](https://lmstudio.ai/docs/developer/rest/load) — получено 2026-09-29
4. [LM Studio — CLI: lms server start](https://lmstudio.ai/docs/cli/serve/server-start) — получено 2026-09-29
5. [LM Studio — Authentication](https://lmstudio.ai/docs/developer/core/authentication) — получено 2026-09-29
6. [LM Studio — Offline Operation](https://lmstudio.ai/docs/app/offline) — получено 2026-09-29
7. [LM Studio — CLI: lms load](https://lmstudio.ai/docs/cli/local-models/load) — получено 2026-09-29
8. [LM Studio — Server Settings](https://lmstudio.ai/docs/developer/core/server/settings) — получено 2026-09-29
