В эпоху, когда большие языковые модели (LLM) стали неотъемлемой частью разработки, способность ИИ не только читать текст, но и «видеть» мир через изображения открывает совершенно новые горизонты для автоматизации. Представьте себе сценарий, где ваша система автоматически анализирует сканы счетов-фактур, извлекает данные из сложных графиков или помогает пользователям находить информацию в технических инструкциях с иллюстрациями. Это уже не футуристическая концепция, а рабочая реальность, доступная через стандартные API.
Однако, чтобы заставить LLM «понять» изображение, недостаточно просто загрузить файл. Необходимо правильно сформировать структуру запроса, выбрать подходящую модель и учесть технические нюансы, такие как токенизация изображений и стоимость обработки. В этом подробном руководстве мы разберем, как эффективно отправлять изображения в LLM через API, используя платформу OpenRouter, и как построить надежные мультимодальные пайплайны для production-среды.
01Основы: Как прикрепить изображение к чату
Базовый принцип работы с мультимодальными моделями прост, но требует понимания специфической структуры данных. В отличие от текстовых запросов, где поле content является простой строкой, при добавлении изображения оно превращается в массив объектов. Каждый объект в этом массиве имеет свой тип: text для текста и image_url для изображения.
Ключевой момент, который часто упускают новички: порядок элементов в массиве content имеет значение. Текстовая часть должна идти первой, а затем следует часть с изображением. Это связано с тем, как парсеры интерпретируют входящие данные. Если ваша логика требует, чтобы изображение было «в центре внимания» до текста, перенесите этот контекст в системное промпт-сообщение, а не пытайтесь менять порядок в массиве контента пользователя.
text. Пример: [{"type": "text", "text": "Что изображено на фото?"}, {"type": "image_url", "image_url": {"url": "..."}}]. Это гарантирует корректную обработку запроса большинством провайдеров.Эндпоинт для таких запросов — стандартный POST /api/v1/chat/completions. Тело запроса содержит массив сообщений, где роль пользователя (user) включает в себя этот составной контент. После того как вы освоили эту базовую структуру, форма запроса остается неизменной. Единственное, что меняется, — это поле model, позволяющее вам переключаться между различными моделями, поддерживающими анализ изображений, без переписывания кода интеграции.

02Выбор модели: URL против Base64
Поле image_url.url принимает два формата данных: публичную ссылку HTTP(S) или строку в формате base64 data URL. Выбор между ними зависит от того, где физически хранится ваш файл.
Публичные URL: Если изображение уже доступно в интернете — например, оно лежит на CDN, в публичном бакете S3 или на вашем веб-сервере — используйте прямую ссылку. Это делает запрос более легким, так как провайдер сам загружает байты изображения. Однако этот метод уязвим к проблемам с доступом: если ссылка истечет, будет заблокирована географически или потребует авторизации, запрос может завершиться ошибкой.
Base64: Для локальных файлов, конфиденциальных данных (например, сканы паспортов) или изображений, не имеющих публичного доступа, необходимо закодировать файл в формат base64 и передать его внутри запроса. Хотя это увеличивает размер полезной нагрузки и время загрузки, это гарантирует, что файл покидает вашу систему только через защищенный API-вызов. Оба формата поддерживают PNG, JPEG, WebP и GIF.

Примеры кода на разных языках
Давайте рассмотрим практическую реализацию на трех популярных языках программирования. Обратите внимание, что единственная строка, которую нужно изменить для тестирования разных моделей, — это переменная MODEL.
# cURL (использование публичного URL)
curl https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-opus-4.8",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "Какова общая сумма на этом чеке?" },
{ "type": "image_url", "image_url": { "url": "https://example.com/receipt.jpg" } }
]
}
]
}'# Python (локальный файл → base64)
import base64, os, requests
def to_data_url(path: str, mime: str = "image/jpeg") -> str:
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")
return f"data:{mime};base64,{b64}"
MODEL = "anthropic/claude-opus-4.8" # замените эту строку на любую vision-модель
resp = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}"},
json={
"model": MODEL,
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "Какова общая сумма на этом чеке?"},
{"type": "image_url", "image_url": {"url": to_data_url("receipt.jpg")}}
]
}],
},
)
print(resp.json()["choices"][0]["message"]["content"])// TypeScript (локальный файл → base64)
import { readFile } from "node:fs/promises";
const MODEL = "anthropic/claude-opus-4.8"; // измените только это для смены модели
const bytes = await readFile("receipt.jpg");
const dataUrl = `data:image/jpeg;base64,${bytes.toString("base64")}`;
const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: MODEL,
messages: [{
role: "user",
content: [
{ type: "text", text: "Какова общая сумма на этом чеке?" },
{ type: "image_url", image_url: { url: dataUrl } },
],
}],
}),
});
const data = await res.json();
console.log(data.choices[0].message.content);
03Выбор Vision-модели: Что и зачем
Не каждая модель на рынке умеет работать с изображениями. Модель считается «vision-моделью» (VLM — Vision Language Model), если она сочетает текстовую модель с энкодером изображений, позволяя обрабатывать пиксели наряду с токенами. В каталоге OpenRouter вы можете проверить поддержку изображений, посмотрев архитектуру модели: если в input_modalities есть значение image, модель принимает изображения.
Разные модели специализируются на разных задачах. Вот сравнительная таблица популярных вариантов:

anthropic/claude-opus-4.8 | $5.00 | 1M | Сложные документы, тщательный анализ графиков и таблиц |
| anthropic/claude-sonnet-5 | $2.00 | 1M | Баланс между пониманием документов и стоимостью |
| google/gemini-3-flash-preview | $0.50 | 1M | Высокий объем скриншотов, общие вопросы, низкая задержка |
| google/gemini-2.5-flash | $0.30 | 1M | Дешевый пакетный OCR и создание описаний |
| qwen/qwen3-vl-235b-a22b-instruct | ~$0.26 | 256K | Открытый вес, OCR и извлечение текста на нескольких языках |
| meta-llama/llama-4-scout | ~$0.10 | 1.3M | Открытый вес, общее зрительное понимание, удобно для самохостинга |
Цены и окна контекста могут меняться, поэтому всегда проверяйте актуальные данные через API /models. Преимущество использования таких платформ, как OpenRouter, заключается в возможности программно фильтровать каталог. Вы можете запросить список всех моделей, поддерживающих изображения, и выбирать их динамически на основе цены, скорости или точности, не меняя код интеграции.
import requests
models = requests.get("https://openrouter.ai/api/v1/models").json()["data"]
vision = [m["id"] for m in models if "image" in m["architecture"]["input_modalities"]]
print(vision) # модели, принимающие изображения04Работа с несколькими изображениями и документами
Вы не ограничены одним изображением в запросе. Вы можете добавить столько объектов image_url, сколько необходимо, в массив контента. Это полезно для сравнения «до и после», анализа многостраничных сканов или ответа на вопрос, который охватывает несколько графиков одновременно.
Однако здесь вступают в силу практические ограничения. Хотя универсального лимита на количество изображений нет, каждый провайдер устанавливает свои пределы. Отправка десятков изображений одновременно может привести к ошибкам или высокой стоимости. Каждое изображение добавляет токены, поэтому цена растет пропорционально количеству и разрешению изображений, особенно при отправке полных сканированных документов.
05Как работает токенизация изображений
Понимание того, как модели «видят» изображения, критически важно для контроля затрат. Изображения разбиваются на патчи (кусочки), преобразуются в эмбеддинги, а затем обрабатываются как токены. Энкодер изображений, обычно Vision Transformer, разрезает изображение на сетку фиксированных патчей. Каждый патч преобразуется в вектор (эмбеддинг), представляющий этот фрагмент. Эти эмбеддинги передаются языковой модели как токены, смешиваясь с вашими текстовыми токенами.
Модель никогда не видит «сырые» пиксели. Она видит эмбеддинги патчей. Следствие простое: больше пикселей означает больше патчей, а больше патчей означает больше токенов в вашем счете. Именно поэтому уменьшение масштаба изображения (downscaling) напрямую снижает количество токенов, которые генерирует энкодер. Точное количество токенов для конкретного изображения варьируется в зависимости от провайдера, поэтому для точного планирования бюджета изучайте документацию конкретной модели.
06Мультимодальный RAG: Поиск по документам с изображениями
Мультимодальный RAG (Retrieval-Augmented Generation) позволяет индексировать изображения, графики и сканированные страницы вместе с текстом. Это решает проблему, когда ключевая информация в документе (например, число в столбчатой диаграмме) не может быть найдена текстовым поиском, так как она не представлена в виде текста. Обычный OCR часто ошибается в сложных графиках или пропускает их.
Существует две основные стратегии индексирования:
- Стратегия A: Суммаризация в текст. На этапе индексации отправляйте каждый график или скан через VLM, прося создать текстовое описание. Затем создайте эмбеддинг этого описания вместе с обычным текстом. Это позволяет использовать любые существующие векторные базы данных. Недостаток: качество поиска зависит от качества суммаризации. Если VLM упустит деталь при создании описания, она не будет найдена позже.
- Стратегия B: Нативные мультимодальные эмбеддинги. Пропустите шаг суммаризации и используйте модель эмбеддинга, которая помещает изображения и текст в одно векторное пространство. Текстовый запрос может напрямую сопоставляться с изображением. Это сохраняет больше визуальных деталей, но требует наличия мультимодальной модели эмбеддингов в вашем стеке.
На этапе ответа (answer step) для обеих стратегий используется один и тот же подход: вы берете лучшие текстовые и визуальные фрагменты, собранные поиском, и формируете единый массив контента, включающий вопрос, извлеченный текст и извлеченные изображения.
def answer(question, retrieved):
content = [{"type": "text", "text": question}]
for r in retrieved:
if r["type"] == "text":
content.append({"type": "text", "text": r["text"]})
else: # chunk изображения
content.append({"type": "image_url", "image_url": {"url": r["url"]}})
return requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}"},
json={
"model": "anthropic/claude-opus-4.8",
"messages": [{"role": "user", "content": content}],
},
).json()07Что это значит на практике
Интеграция мультимодальных возможностей в ваши приложения требует внимательности к деталям, но предлагает огромную гибкость. Вот три ключевых вывода, которые стоит запомнить:
- Универсальное тело запроса. Один и тот же формат JSON работает для всех vision-моделей. Вам не нужно переписывать логику отправки данных при смене модели с Claude на Gemini или Llama. Вы меняете только одну строку — идентификатор модели.
- Выбор формата передачи. Используйте публичные URL для уже размещенных в сети изображений для экономии трафика и скорости. Используйте base64 для локальных или конфиденциальных файлов, чтобы обеспечить безопасность и избежать проблем с доступом. В обоих случаях старайтесь уменьшать разрешение изображений перед отправкой, чтобы оптимизировать стоимость.
- RAG как надстройка. Мультимодальный RAG добавляет слой поиска перед стандартным вызовом API. Индексируйте графики и сканы рядом с текстом, извлекайте релевантные фрагменты и отправляйте их в модель, используя тот же базовый запрос, что и для простых изображений.
Этот подход не идеален для всех задач. Он не предназначен для обработки видео в реальном времени (где нужны специализированные пайплайны выборки кадров) или для сверхточного OCR мелкого текста в низком разрешении. Также помните, что этот метод предназначен только для ввода изображений. Генерация или редактирование изображений требуют совершенно других API и форматов запросов.
В заключение, отправка изображений в LLM стала стандартом де-факто для создания интеллектуальных систем, способных работать с реальными документами. Освоив базовую структуру запроса, выбрав правильную модель и оптимизировав обработку изображений, вы сможете строить мощные приложения, от автоматизации бухгалтерии до интеллектуальных помощников по технической документации.
Источник: OpenRouter ↗
