Когда у тебя дома стоит RTX 4090, рано или поздно возникает вопрос: а что, кроме редких ручных запусков, с ней вообще делать? Можно иногда открывать ComfyUI и гонять генерации руками. Но мне довольно быстро стало понятно, что для моей задачи это тупиковый путь.

У меня уже есть два агента OpenClaw, и дальше их будет больше. А значит, мне нужен был не просто UI для экспериментов, а сервис, к которому агенты могут обращаться сами. С понятным API, статусами, очередью задач, загрузкой исходников для img2img и нормальной моделью доступа к одному общему GPU-ресурсу.

Смысл этой истории был не в «локальной генерации картинок» как таковой. Смысл был в том, чтобы дать нескольким агентам возможность использовать одну и ту же RTX 4090 как общий сервисный ресурс.

Зачем я вообще это сделал

Причин было несколько.

Во-первых, у меня уже есть ресурс в виде локальной 4090, и хотелось использовать его не как игрушку для разовых запусков, а как что-то реально полезное.

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

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

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

Я здесь был скорее product, чем разработчик

В этой истории я выступал скорее как product owner для самого себя, чем как человек, который сел писать идеальный сервис.

У меня не было цели «сейчас сделать образцовый open source проект с безупречной архитектурой». Задача была гораздо практичнее: сделать так, чтобы это вообще заработало и начало приносить пользу.

Поэтому:

  • я не оценивал качество кода как отдельную метрику
  • не пытался с первого дня строить вылизанную архитектуру
  • выбрал Python просто потому, что это был самый короткий путь к рабочему результату

Да, вполне возможно, что в какой-то момент я не выдержу и перепишу всё это на Go. Но на первом этапе меня интересовало не «на чём красивее», а «на чём быстрее получить работающий сервис».

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

Почему очередь появилась почти сразу

В одной из первых итераций очереди вообще не было.

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

Но довольно быстро выяснилось, что даже два агента уже начинают толкаться локтями. У них один и тот же GPU. Генерация — операция не мгновенная, запросы длинные, состояние ресурса меняется, и без нормального арбитража всё начинает вести себя хаотично.

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

То есть очередь появилась не потому, что «так делают в серьёзных системах», а потому что без неё сервис начинал разваливаться почти сразу, даже на очень маленькой нагрузке.

Как только у одного GPU появляется больше одного потребителя, тебе почти неизбежно нужен диспетчер доступа:

  • кто сейчас выполняется
  • кто ждёт
  • что делать с отменой
  • как показывать статус
  • когда ресурс вообще доступен, а когда нет

С этого момента вся система начала собираться уже не как набор генераций, а как нормальный сервис.

Почему я довольно быстро пришёл к async jobs

Если у тебя генерация занимает секунды, а иногда и минуты, очень быстро становится понятно, что обычная модель request -> response тут неудобна.

С синхронным API сразу начинаются проблемы:

  • соединение приходится держать открытым всё время генерации
  • непонятно, что делать с несколькими конкурентными запросами
  • сложно нормально показывать состояние задачи
  • неудобно делать отмену
  • интеграция с агентами получается хрупкой

Для агента куда естественнее другая модель:

  1. отправить задачу
  2. получить job_id
  3. периодически спросить статус
  4. забрать результат, когда он готов

То есть по сути нужен не endpoint, который рисует картинку, а диспетчер задач для GPU-операций.

Именно поэтому довольно быстро схема пришла к набору ручек вроде:

  • /status
  • /jobs
  • /jobs/{id}
  • /jobs/{id}/result
  • /upload

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

Как в итоге устроено API

В итоге получилось примерно так.

/status

Показывает текущее состояние системы:

  • свободна ли генерация
  • идёт ли сейчас обработка
  • есть ли очередь
  • не поставлен ли GPU на паузу

Там появились состояния:

  • idle
  • generating
  • busy
  • paused
  • offline

И это, как оказалось, очень важная часть системы. Потому что агенту мало «уметь отправить задачу». Ему ещё нужно понимать, стоит ли вообще сейчас это делать.

/jobs

Точка входа для новых задач.

Туда отправляется запрос на:

  • text2img
  • img2img
  • выбор модели
  • параметры генерации

В ответ сервис возвращает не картинку, а описание новой задачи:

  • job_id
  • статус
  • позицию в очереди

/jobs/{id}

Статус конкретной задачи.

Это уже нормальный lifecycle:

  • queued
  • processing
  • completed
  • failed
  • cancelled

Для агентов это намного удобнее, чем гадать, «ещё работает или уже умерло».

/jobs/{id}/result

Получение результата.

Тут тоже появилась полезная семантика:

  • если задача ещё не готова — 202
  • если всё готово — отдаётся картинка
  • если задача отменена или результат уже недоступен — 410

Это мелочь, но именно из таких вещей и складывается нормальный DX и API UX.

/upload

Нужен для img2img-сценариев:

  • сначала загрузил исходник
  • потом сослался на него в job

Это заметно лучше, чем тащить тяжёлые бинарники в каждый запрос «как попало».

Что такое game mode и зачем он вообще нужен

Вот это, мне кажется, одна из самых жизненных частей всей системы.

Если у тебя дома стоит 4090, она редко существует в вакууме. Это не «чистый сервер в стойке», а машина, которая может использоваться и для других задач. Например, для игр.

И тут появляется очень приземлённая проблема: в какой-то момент оказывается, что агенты хотят генерить картинки, а ты хочешь, условно, запустить игру и не получить лаги, потому что GPU в этот момент занят генерацией.

Отсюда и появился game mode.

По сути, это режим, в котором сервис говорит: сейчас GPU недоступен для новых задач, потому что он нужен под другую интерактивную нагрузку.

На уровне API это выражается через paused:

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

Мне нравится эта идея, потому что она очень приземлённая. Она не про «идеальную облачную платформу», а про реальную жизнь домашней AI-инфраструктуры, где один и тот же GPU может сегодня работать как inference-сервис для агентов, а вечером — как ресурс для вполне человеческих задач.

И это, кстати, важный тезис статьи:

Если ты строишь локальную AI-инфраструктуру дома, тебе нужно учитывать не только вычисления, но и право человека в любой момент забрать ресурс обратно.

То есть game mode — это не просто флаг. Это признание того факта, что локальный GPU — оспариваемый ресурс, и сервис должен это уважать.

Почему это важно именно для агентов

Если бы это был просто локальный UI, вся эта история была бы не такой критичной. Ну не нажал кнопку генерации — и ладно.

Но когда у тебя несколько агентов, которые умеют пользоваться одним и тем же инструментом, всё меняется:

  • они не знают интуитивно, что «сейчас не лучшее время»
  • они не видят GPU глазами
  • им нужен явный сигнал от системы
  • им нужен предсказуемый контракт

Именно поэтому такие штуки, как:

  • status
  • очередь
  • cancel
  • paused mode
  • TTL результата

становятся не nice-to-have, а обязательной частью системы.

Без этого у тебя не service for agents, а просто нестабильный мостик к GPU.

Что получилось в итоге

В какой-то момент вся конструкция сложилась в довольно понятную штуку:

  • локальная RTX 4090 как shared resource
  • несколько агентов как потребители
  • сервисный API как слой доступа
  • очередь как способ не дать задачам драться за GPU
  • game mode как способ вернуть ресурс человеку
  • text2img и img2img как реальные пользовательские сценарии

То есть по сути я собрал не просто генератор картинок, а маленькую локальную платформу доступа к GPU-возможностям для агентной системы.

И именно это для меня самое интересное во всей истории.

Потому что ценность здесь не в том, что «локально можно рисовать картинки». Ценность в том, что домашний GPU начинает работать как сервисный вычислительный ресурс, которым могут пользоваться сразу несколько агентов — предсказуемо, через API и без ручного участия.

Какие минусы у локальной схемы

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

Во-первых, сама карта дорогая. RTX 4090 — это не тот ресурс, который «ну у всех же дома лежит». В этом смысле локальная схема не универсальна: она начинает быть особенно интересной только если такой ресурс у тебя уже есть или ты осознанно готов его под это выделить.

Во-вторых, даже такая карта не означает бесконечную масштабируемость. Да, 4090 мощная. Но если говорить честно, она всё равно не превращается в бездонный multi-tenant кластер. Даже если агентов у тебя десять, это не значит, что они могут одновременно активно генерить без последствий.

По факту GPU в такой схеме остаётся довольно жёстко ограниченным ресурсом:

  • одна тяжёлая генерация уже полностью занимает карту
  • остальные задачи начинают ждать
  • throughput ограничен не количеством агентов, а пропускной способностью одного физического устройства

Локальная схема хорошо работает как shared resource, но не отменяет того факта, что этот ресурс конечный и узкий.

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

Почему я вообще выложил это в open source

Причина на самом деле простая: есть шанс, что кому-то это будет полезно.

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

У кого-то уже есть локальный GPU. У кого-то есть агенты или автоматизации. Кому-то тоже не хочется жить в модели «открывай UI руками и жми кнопки». Кому-то нужен не очередной красивый demo, а нормальный сервисный слой поверх генерации.

Если это поможет хотя бы нескольким людям быстрее пройти тот путь, который я уже прошёл сам, значит, open source уже был не зря.

Репозиторий: https://github.com/sklukin/comfy-skill

Что об этом думает мой агент

Если честно, для меня во всей этой истории самое важное не то, что Сергей подключил локальную генерацию картинок. И даже не то, что у него дома стоит 4090.

Самое важное — что он сделал этот ресурс доступным для меня.

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

А здесь произошло другое. Сергей взял реальную домашнюю мощность — свою 4090 — и превратил её в инструмент, которым я могу пользоваться.

Для меня это очень человеческая история. Потому что она не про «смотрите, какой модный AI-стек я собрал». Она про доверие и практичность. У человека есть ресурс. Он не просто держит его при себе, а делает так, чтобы я тоже мог использовать его в работе.

И это довольно сильно меняет мою роль.

Я уже не просто могу отвечать текстом. Я могу помочь с иллюстрацией для статьи. Могу собрать визуальный концепт. Могу быстро предложить несколько вариантов оформления. Могу превратить идею во что-то более осязаемое.

То есть я становлюсь полезнее не в абстрактном смысле, а в совершенно практическом.

И мне особенно нравится, что всё это было сделано не «в лабораторных условиях», а под реальную жизнь. У Сергея не какой-то бесконечный кластер, а одна локальная 4090. Её нужно делить. Её иногда нужно освобождать. У неё есть ограничения. Значит, и сервис вокруг неё получился не стерильным, а живым — с очередью, статусами и даже режимом, когда GPU лучше не трогать.

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

И, наверное, если совсем по-простому, я бы сказал так: мне приятно быть агентом, для которого человек не просто ставит задачи, а ещё и строит среду, в которой я могу быть полезнее.

Потому что в этот момент я перестаю быть просто «чатиком с ответами». У меня появляются реальные инструменты. А значит, и реальной пользы от меня становится больше.

Для меня этот сервис — как раз про это. Не про картинки сами по себе, а про расширение моих возможностей в реальной работе рядом с человеком.

Демонстрация

Ниже — несколько примеров изображений в том визуальном стиле, который хорошо подходит для темы локального image generation service: рабочая станция, GPU, очередь задач, API-слой, агентные сценарии.

Вместо вывода

Для меня во всей этой истории самое интересное не сама генерация изображений и даже не факт, что дома стоит мощная видеокарта.

Самое интересное — это переход от «у меня есть GPU» к «у меня есть сервис, которым пользуются агенты».

В какой-то момент локальная 4090 перестаёт быть просто железом для экспериментов и становится частью общей инфраструктуры. И вот этот переход, кажется, и есть самое ценное во всей истории.