most-AI.com

Генерация изображений по API: что учесть при интеграции

Денис Коростелёв7 мин

Подключить генерацию изображений выглядит просто ровно до первого продакшена. Дальше начинаются вещи, которых нет в примерах из документации, — и все они стоят денег или нервов.

Разберём четыре, которые встречаются в каждом втором проекте.

1. Генерация асинхронна, и это меняет архитектуру

Картинка не возвращается в ответе на запрос. Вы отправляете задачу, получаете идентификатор и опрашиваете статус, пока не появится результат. Синхронного варианта нет и не будет: генерация занимает от нескольких секунд до минут.

Значит, вам нужны три вещи, о которых стоит подумать до написания первой строки:

Очередь задач. Пользовательский запрос не должен держать HTTP-соединение всё время генерации.

Хранилище состояния. Минимум: идентификатор задачи, статус, время создания, кто заказал. Без этого вы не сможете ни показать пользователю прогресс, ни разобраться, что произошло вчера.

Разумный интервал опроса. Не чаще, чем нужно. Опрос раз в секунду для задачи, которая идёт минуту, — это шестьдесят лишних запросов на каждую генерацию. Разумно начинать с 2–3 секунд и увеличивать интервал по мере ожидания.

2. Повторы должны быть идемпотентными

Самая дорогая ошибка интеграции — повторный запуск уже оплаченной генерации.

Сценарий банальный: запрос ушёл, ответ не дошёл (таймаут, обрыв, перезапуск пода). Наивный ретрай отправляет задачу заново — и вы платите дважды за одну картинку.

Правильная схема:

  1. Сначала записать намерение в свою базу: «задача X для пользователя Y, промпт Z, статус: создаётся».
  2. Отправить запрос.
  3. Получив идентификатор — сохранить его немедленно, до любой другой работы.
  4. Ретрай привязывать к своей записи, а не к факту «запрос упал». Если у записи уже есть идентификатор, повтор должен спрашивать статус, а не создавать новую задачу.

Ключевая мысль: точка невозврата — это момент, когда у вас появился идентификатор. Всё, что после, — уже оплачено, и повторять нельзя.

3. Таймауты задавайте явно и по фазам

Скалярный таймаут HTTP-клиента часто не покрывает то, что нужно. Классический отказ: соединение установлено, заголовки пришли, а тело ответа читается бесконечно. Клиент с одним общим timeout в этой ситуации может висеть часами, удерживая сокет.

Задавайте таймауты раздельно:

connect  — 10 с    (установка соединения)
read     — 60 с    (чтение ответа)
write    — 10 с    (отправка тела)
pool     — 10 с    (ожидание свободного соединения в пуле)

Отдельно — общий предохранитель на всю операцию. Даже с раздельными таймаутами процесс может зависнуть на системном вызове, который их не соблюдает. Жёсткий лимит на задачу целиком, после которого процесс завершается, спасает от зомби, удерживающих ресурсы.

Это не теория: зависший на TLS-сокете обработчик выглядит как «сервис работает, но ничего не происходит» — самый неприятный вид аварии, потому что мониторинг молчит.

4. Считайте себестоимость с первого дня

Логируйте стоимость каждой генерации сразу, а не когда бухгалтерия придёт с вопросом. Через месяц вы захотите понять, какая функция продукта съедает бюджет, и восстановить это задним числом будет уже нечем.

Минимальный набор полей:

Поле Зачем
task_id Связать с задачей и с пользователем
model Понять, какая модель сколько стоит на вашем профиле нагрузки
status Отделить успешные генерации от оплаченных неудач
duration Найти модели, которые тормозят очередь
cost Собственно деньги

Пятого поля достаточно, чтобы ответить на большинство вопросов о расходах. И обязательно логируйте неуспешные генерации тоже: задача, упавшая после старта, чаще всего уже оплачена.

Что ещё ломается в проде

Модерация. Часть промптов будет отклонена, и ответ об этом не всегда очевиден: иногда это внятная ошибка, иногда — общий internal error. Заложите ветку «сгенерировать не удалось по содержанию» и покажите пользователю понятный текст, а не «ошибка 500».

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

Разные модели — разные допустимые параметры. Соотношение сторон, длительность, наличие звука у видео — набор различается. Не пишите один жёсткий набор параметров на все модели: либо читайте схему модели, либо явно ведите таблицу поддерживаемых значений и валидируйте до отправки.

Всплески нагрузки. Ограничьте параллельность на своей стороне. Провайдер вернёт вам 429, и обрабатывать это лучше очередью с плавным темпом, чем экспоненциальными ретраями, которые множат нагрузку.

Минимальный план внедрения

Если начинаете с нуля, порядок такой:

  1. Одна модель, один сценарий, синхронный прототип «отправил — опросил — получил».
  2. Очередь и хранение состояния.
  3. Идемпотентные ретраи.
  4. Логирование стоимости.
  5. И только потом — вторая модель и выбор между ними.

Пункты 2–4 кажутся скучными на фоне «давайте добавим ещё модель», но именно они определяют, будет ли интеграция работать через полгода.

Как считать нагрузку

Прежде чем выбирать архитектуру очереди, полезно прикинуть порядок.

Допустим, продукт генерирует картинку по действию пользователя, и таких действий 500 в сутки, из них 60% приходится на четыре часа пиковой активности.

  • Средняя нагрузка: около 20 задач в час.
  • Пик: около 75 задач в час, то есть примерно одна задача в 48 секунд.
  • При длительности генерации 30 секунд одновременно в работе будет 1–2 задачи.

Вывод: на таком объёме сложная распределённая очередь не нужна, хватает одной таблицы со статусами и воркера. Считать это стоит до того, как разворачивать брокер сообщений.

Другое дело — пакетные сценарии: «обработать 3 000 карточек товара за ночь». Там ограничитель не ваша инфраструктура, а лимиты провайдера, и планировать нужно от них.

Что логировать помимо стоимости

Четыре поля, которые почти всегда добавляют задним числом, потратив на это день:

  • Полный текст промпта. Без него невозможно разобрать жалобу «получилось не то».
  • Версия шаблона промпта. Если промпт собирается кодом, вы будете его менять. Не зная версию, вы не сравните качество до и после.
  • Идентификатор пользователя. Для разбора инцидентов и для лимитов.
  • Причина неуспеха. Модерация, таймаут, ошибка провайдера — это три разных проблемы с тремя разными решениями.

Частые вопросы

Сколько ждать результата генерации?

От нескольких секунд до минут, в зависимости от модели и типа задачи. Видео заметно дольше изображений. Проектируйте интерфейс так, чтобы ожидание не блокировало пользователя.

Что делать при ошибке 429?

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

Как понять, что генерация отклонена модерацией?

Обрабатывайте это как отдельную ветку и показывайте понятный текст. Не всякий отказ приходит внятным кодом — заложите fallback на общее сообщение.

Нужно ли хранить результат у себя?

Да. Ссылки провайдера не вечны, а для пользователя исчезнувшая картинка выглядит как потеря его данных.

Можно ли проверить модель до интеграции?

И нужно. Прогоните свой типовой сценарий руками в кабинете: увидите реальное качество, скорость и стоимость на своих данных, а не на демо-промптах.

Как выбрать между несколькими моделями?

Не по чужим сравнениям. Возьмите 10 своих реальных запросов, прогоните через кандидатов по три раза и сравните худшие результаты — в проде вас подводит не потолок модели, а её пол.

Чек-лист перед выкаткой

Пройдитесь по нему до того, как открывать доступ пользователям.

  • Повторный запрос с тем же идентификатором задачи не создаёт вторую генерацию.
  • Таймауты заданы по фазам, есть общий предохранитель на операцию.
  • Отказ модерации обрабатывается отдельной веткой с понятным текстом.
  • Файл результата скачивается к себе сразу после успеха.
  • Стоимость и причина неуспеха пишутся в лог с первого дня.
  • Параллельность ограничена на своей стороне, 429 обрабатывается очередью.
  • Есть ручной способ посмотреть, что происходит с зависшей задачей.

Последний пункт выглядит необязательным ровно до первого инцидента.

Что дальше

Каталог доступных моделей и их типы — в разделе нейросетей. Для разработчиков есть отдельная страница с условиями работы по API — Most AI для разработчиков.

Если задача не требует своей интеграции, а нужно просто получать картинки под контент — возможно, хватит обычного интерфейса: что можно попробовать бесплатно.

Частая ошибка на старте

Самая дорогая ошибка не техническая, а продуктовая: интеграцию начинают с выбора модели.

Правильный порядок обратный. Сначала опишите, что должен получить пользователь и насколько он готов ждать. Пять секунд ожидания и минута — это два разных продукта с разной архитектурой, и модель тут вторична.

Дальше проверьте сценарий руками в кабинете на десятке реальных запросов. Половина идей отсеивается на этом шаге, ещё не превратившись в код.

И только потом — очередь, ретраи, логи и выбор модели. Так вы пишете интеграцию под задачу, которая уже проверена, а не под предположение о ней.

Денис Коростелёв

Продуктовый аналитик

Сравнивает модели на одинаковых промптах и считает себестоимость результата. Не верит сравнениям без методики — включая собственные.