У нас работает продакшен, где ИИ-агенты делают тридцатисекундные рекламные ролики от начала до конца — планируют, пишут сценарий, рендерят, проверяют, публикуют. 04.08.2026 мы прочитали всю очередь багов целиком: 134 репорта, из них около 85 — настоящие дефекты. И сгруппировали их не по фиче, в которой они всплыли, а по механизму поломки.
Два самых дорогих класса — примерно 24 репорта, и каждый заканчивался потраченными деньгами и клиентом, которому сказали, что всё получилось, — имели один корень: агент, который произвёл результат, был единственным, кто судил о качестве этого результата.
Три чека из той очереди, каждый измерен, а не вспомнен:
- Тридцатисекундный ролик объявили готовым.
blackdetectпоказал 26.4 секунды чёрного кадра из 30.0 — звук и субтитры собрались, видеоряд в файл не попал (репорт019fa3f6, 27.07.2026). - Джоб монтажа отчитался об успехе и вернул файл, побайтово совпадающий с
результатом другого джоба: тот же хеш, чужой человек в кадре. От настоящего
успеха неотличимо, пока не посмотрит человек (репорт
019fa5a8). - Карточка персонажа вернулась со статусом «succeeded» и нулём файлов.
Агент отправил движок в фон, пообещал «доложить, как только результат
подтвердится на диске», и завершил ход. $0.12 потрачено, не нарисовано
ничего (репорт
019fce2d).
Лечилось это не лучшей моделью, не лучшим промптом и не добавлением агентов. Лечилось двумя структурными изменениями в том, как движется работа, — дальше измеренный отчёт по обоим. Посмотреть систему, которая это исполняет →
Граф был не самой трудной частью
Нынешнее модное имя дисциплины — «graph engineering»: проектируйте работу ИИ как джобы, соединённые стрелками, с общим состоянием между ними. Планировщик делит задачу, исполнители работают параллельно, результаты сливаются, человек одобряет то, что уходит наружу. Рамка полезная, и термин вирусится с августа 2026 года.
Что нас удивило, когда мы приложили эту рамку к своей системе: сам граф — это как раз та часть, которая у нас уже была. Наш конвейер рендерит видео для карточек товара и ролики с постоянным ведущим ровно этой формой: планировщик, параллельные стадии рендера, слияние, ревью. Она есть у большинства команд, доживших до продакшена. Её показывают в каждом демо фреймворка.
Чего рамка недоговаривает — и за что заплатила наша очередь багов, — так это что два узла в ней не такие, как остальные. В 134 репортах почти нет планирования и параллелизма. Они почти целиком про суждение: кто решает, что работа сделана, и кто решает, что она может идти дальше.
Ограничение этой секции: по схеме графа нельзя понять, есть ли у вас эти два узла. Наша на доске выглядела полной месяцами — и всё это время отгружала чёрные видео.
Проверяющий — не автор
Правило, которое закрыло наш самый дорогой класс дефектов, старое до скуки: агент, собравший результат, не имеет решающего голоса в вопросе, годен ли этот результат к выдаче.
Работать на практике его заставило то, что проверяющий стал структурным, а не пришитым к конкретному багу. После каждой из трёх поломок выше мы выкатывали точечную заплатку — и класс возвращался на следующем типе выдачи. Остановил его (выкачено 08.08.2026) реестр постусловий: каждый тип рендера в системе обязан объявить свои проверки доставки — файл существует, он не пустой, он проигрывается, слайдов столько же, сколько заказано, и в заказанном размере, картинка читается, — а конвейер выполняет их после того, как движок отчитался об успехе, и до того, как джобу разрешено сказать «succeeded». Тест сверяет реестр со списком типов, поэтому новый тип не может доехать до прода, не назвав, что для него значит «доставлено».
Два решения оказались важнее, чем мы ожидали:
- Сначала детерминированные проверки, суждение модели — последним. Почти
всё, что стоит проверять, измеряется через
ffprobeи хеш: длительность, размер кадра, чёрные кадры, «выход не является побайтовой копией входа». Проверку зрительной моделью мы держим для единственного, чего измерение не видит, — тот ли это человек и та ли этикетка на продукте от кадра к кадру, — и она работает в совещательном режиме, пока не измерена её доля ложных срабатываний. - Непройденная проверка — это упавший джоб с причиной на человеческом языке, а не выданный дефект с припиской. Честное падение стоит доверия меньше, чем чёрный прямоугольник, объявленный готовым.
Лучшее доказательство, что правило обобщается: оно поймало наш собственный
чекер. Первая версия считала слайды карусели только по картинкам, а
агент-ревьюер на нашем пуш-гейте — проверяющий, который не автор, наведённый на
код, — заметил, что анимированные слайды уезжают как .mp4. То есть каждая
анимированная карусель, собранная движком ровно как заказано, была бы
забракована как дефектная. Один заблокированный пуш вместо инцидента на проде.
Ограничение: проверка доставки судит только о том, что лежит на диске. Она не скажет вам, что ролик скучный, — это остаётся человеческому гейту ниже и проверкам формата, которые идут до того, как потрачены деньги, а не после.
Гейт — это пауза, а не два джоба
Наши гейты человеческого одобрения раньше были хирургией. Конвейер, который повторяет чужой формат ролика, требует, чтобы человек одобрил карточку продукта и стартовые кадры до платного рендера, — и мы разрезали его на два отдельных джоба со вторым сабмитом и второй сметой, потому что джоб не умел ждать.
Оркестрационное лечение (выкачено 08.08.2026) — сделать ожидание состоянием
джоба. Движок, дошедший до контрольной точки, пишет маленький файл-запрос:
что именно спрашивается, человеческими словами, и какие артефакты смотреть, —
а джоб паркуется в статусе waiting_approval. Одобрение возвращает его в
очередь одним защищённым запросом к базе (двойной клик или гонка — это отказ,
никогда не второй переход), припаркованные артефакты подставляются обратно, и
тот же самый джоб продолжается. Два сабмита стали одним, вторая смета
исчезла, а мост передачи между половинами перестал быть поверхностью отказа.
Два продакшен-урока приехали вместе с этим, и оба поймало ревью до выката:
- Припаркованный джоб, о котором никто не услышал, припаркован навсегда — и уже оплачен. Первая версия писала уведомление и тут же отфильтровывала его и из ленты, и из списка пушей. Если у вашего оркестратора есть состояние «ждём человека», то самая громкая поверхность, которая у вас есть — в нашем случае пуш на телефон, — принадлежит сообщению «нужно ваше решение».
- Деньги должны быть ограничены до гейта, а не после. Смета единого джоба оценивает платную половину по верхней границе (секунды на бит зажаты той же константой, которой их зажимает движок), поэтому потолок, который клиент одобрил, покрывает ровно то, что может быть потрачено. А сообщение гейта показывает уже измеренный план — биты, секунды, всё, что выброшено, — до того, как рендер потратит цент.
Ограничение: гейт хорош ровно настолько, насколько хорош его вопрос. Наш шлёт измеренный план и артефакты; гейт, который спрашивает «одобряете?» без доказательств, — это резиновая печать с дополнительной задержкой.
Во что обходятся прогоны
Клиентские цены по сметам самой системы на 08.08.2026; цифры рендера — из опубликованного прогона 05.08.2026.
| шаг | цена | примечание |
|---|---|---|
| Подготовка до гейта (паспорт, карточка продукта, 4 стартовых кадра) | $0.36 | паркуется на гейте; отказались здесь — это и вся трата |
| Готовая 15-секундная часть, чистовая полоса | $3.88 | Seedance 2.0 — модель, удержавшая лицо и этикетку |
| Та же часть, черновая полоса | $0.91 | Grok Imagine — 85–90% результата, для итераций |
| Проверки доставки на рендер | $0.00 | детерминированные: ffprobe и хеши |
| Гейт ожидания человека | $0.00 | состояние джоба, а не второй джоб |
Ограничение: это цены нашего каталога на названные даты. Модели переоценивают себя, и обязывающая цифра — смета перед конкретным прогоном.
Ошибки, каждая со своим ценником
- Одна модель и пишет, и оценивает. Цена: оплаченный тридцатисекундный
рендер, выданный как 26.4 секунды чёрного, найденный клиентом (репорт
019fa3f6). Это поведение по умолчанию у любого одноагентного цикла. - Точечные заплатки на структурный класс. Цена: три починенных бага и тот же класс на четвёртом типе выдачи — пока реестр постусловий не сделал ответ на вопрос «что значит доставлено» обязательным для каждого типа.
- Проверяющий унаследовал слепое пятно автора. Цена: один заблокированный пуш. Наш подсчёт слайдов только по картинкам забраковал бы каждую валидную анимированную карусель. Ревьюйте свои чекеры как код — чекером, который их не писал.
- Состояние «ждём человека» без достижимого человека. Цена: две блокирующие находки ревью. Уведомление существовало, но лента и пуш-списки его отфильтровывали. Каждый припаркованный джоб ждал бы вечно — с уже потраченными деньгами подготовки.
Чек-лист, по которому ии агенты перестают верить себе на слово
Выжимка из эпика, закрывшего класс, — шесть пунктов, и каждый оплачен выше:
- Рисуйте наименьший граф, который улучшает качество. Больше агентов — больше шума; мы добавили ноль агентов и два типа узлов.
- Каждый производящий узел называет свои постусловия, и проверяющий, который не автор, выполняет их до того, как разрешено сказать «готово».
- Детерминированные проверки — раньше модельного суждения; модель-судья работает совещательно, пока вы не измерили её долю ложных срабатываний.
- Непройденная проверка роняет джоб с причиной, которую человек может прочитать.
- Ожидание человека — полноценное состояние: реаперы не имеют права его убивать, самая громкая поверхность уведомлений обязана о нём сказать, а одобрение обязано быть устойчивым к гонке.
- Ограничивайте деньги до гейта и показывайте на нём измеренный план.
Ничего из этого не требует фреймворка на старте. У нас это строки в очереди и один файл реестра; конвейер с постоянным лицом работал ручной версией того же графа задолго до того, как у состояний появились имена.