Дисклеймер: в статье упоминается Meta - организация, признанная экстремистской и запрещённая на территории РФ. Статья - не прогрев и не реклама курсов/самопиар и пр.. Все логи, цифры и скрины - из реальных прогонов тестового аккаунта.

Всем привет!). В финале прошлой статьи (https://habr.com/ru/articles/1076972/) я обещал разбор Reasoning Lock - того самого бага, где рассуждающая модель тратит токены и отвечает пустотой. Разбор готов, правки в воркфлоу заказчика встают в бой, и я хочу выпустить его с живой метрикой, после нескольких дней наблюдений в проде за тем, как изменения работают. А пока счётчик тикает, публикую из бэклога мини - историю, которая созрела ещё в двадцатых числах августа - в разгар фурора вокруг загадочной stealth-модели. Фурор уже стих, но эксперимент от этого хуже не стал: за три дня стелс-модель "навайбкодила" воркфлоу на 127 нод, который реально ходит по API, генерирует медиа и публикует Reels. Ниже я покажу архитектуру, код, честный список косяков модели и моих собственных, и экономика эксперимента. Постараюсь вкратце и по существу.)

Цель, так сказать, эксперимента - нагрузочное тестирование свежей LLM в роли кодера на сложном распределённом пайплайне: пять внешних API, бинарные потоки, три десятка условий ветвления, асинхронные поллинги - и всё в одном воркфлоу! Сейчас на западном рынке бум автономных связок в духе "скрапинг-генерация фото/видео-автопостинг". Я сам контентом не занимаюсь - мне интересны пайплайны и отказоустойчивость. Но задача подходит как идеальное ТЗ!)

И тут совпало: с 20 по 25 августа на OpenRouter открылся бесплатный доступ к загадочной модели stealth/ox-alpha. Позже она деанонизировалась - FAQ OpenRouter это официально подтверждает: это Z.ai, GLM 5.3 Flash (z-ai/glm-5.3-flash в селекторе Cline). Расклад по ней такой: контекст 1М токенов, нативная мультимодальность (текст, картинки, видео на вход), заявка от Z.ai "efficient coding and long-horizon agent tasks" - всё вы про это читали и знаете). Релиз состоялся 26 августа, то есть стелс-окно дало неделю игры до официального анонса. Большой контекст, нулевая цена. Я открыл VS Code, запустил Cline и закинул ТЗ на полноценный медиа-конвейер в n8n.

За три дня (с 21 по 23 августа) ушло 60,9 млн токенов - 85,3% из них кеш-хиты, итоговый счёт по blended-цене $0,07/1M составил около $4. Суть что на выходе - воркфлоу на 127 нод (изначально 156, потом рефакторил), который реально ходит по API, генерит медиа и публикует Reels. Ниже - архитектура, код, честный список косяков модели и моих собственных, и экономика эксперимента.

ТЗ: не "сделай мне хайповые и залётные рилсы", а "ты - senior n8n solutions architect"

Все тут понимают что LLM - это не волшебник/экстрасенс. Банальное правило: чем точнее вход - тем меньше галлюцинаций на выходе. Поэтому в Cline я прописал не "придумай автопостинг с алертами в телеграм", а максимально (вроде как)) структурированный бриф с итерациями. Сокращённая версия реального промпта стала такой:

ROLE
You are a senior n8n solutions architect. You produce production-ready,
importable n8n workflow JSON. You never invent API parameters or node
fields; when unsure, you say so explicitly.

PROJECT CONTEXT
БЭКЛОГ: «AutoContent-Factory v1.0» — автономный конвейер
ИИ-аналитики трендов, генерации мультимедиа и автопостинга
в Instagram на базе self-hosted n8n.

КОНТУРЫ:
1  — парсинг конкурентов (ScrapeCreators API), формула виральности
1.5 — семантический фильтр (LLM-reranker, порог релевантности)
2  — AI-диспетчер (строгий JSON: сценарий/промпт видео/caption)
3  — мультимодальная генерация (видео/голос/обложка через OpenRouter)
5  — автопостинг (Instagram Graph API)

API FACTS (from official docs)
- 1 credit = 1 request; cache hits = 0 credits
- GET /v1/instagram/user/reels — метрики БЕЗ caption
- GET /v2/instagram/media/transcript — 10–30 s, timeout >= 60 s
- HTTP 402 = out of credits; 5xx = transient

RULES
One contour per message. No secrets. Defensive JS (try/catch,
null-checks). If ambiguous — ask ONE clarifying question.

Оглашу ключевые приёмы, которые сэкономили мне нервы:

  • Роль вместо просьбы. "Senior-архитектор" меняет тон генерации: модель пишет defensively, а не разговорно - упрощенно.

  • Явно запрещено выдумывать параметры. Нет уверенности - скажи и добавь в список "VERIFY MANUALLY".

  • Итерации по контурам. По одному контуру за сообщение - модель не путается в зависимостях.

  • Output Contract = Один JSON-блок + инструкции по импорту + список сомнительных параметров.

Единственное что забыл дать модели по задачам, в самом конце сборки готового воркфлоу - так это детальную техническую документацию. Так бы и статью написал более детальнее и проще!)

 Первые шаги: stealth/ox-alpha шуршит в консоли... пишется JSON-конфиг для нод
Первые шаги: stealth/ox-alpha шуршит в консоли... пишется JSON-конфиг для нод

Архитектура воркфлоу: 5 контуров, 127 нод

 В процессе сборки: примерно 2/3 готового воркфлоу на холсте
В процессе сборки: примерно 2/3 готового воркфлоу на холсте

Честная арифметика воркфлоу, чтобы никто не пересчитывал за меня: 127 = 113 нод в пяти контурах (23 + 17 + 17 + 37 + 19) + 2 входных триггера (Schedule и Manual) + 4 disabled-заглушки под будущие итерации + 8 стикеров-документации. Рабочих нод, соответственно, 115: 113 контурных + 2 триггера. Подробнее поясню каждый контур:

1 -й контур: назовём "Разведка" (23 ноды)

Схема такая: Schedule (24ч) - список конкурентов - Reels через ScrapeCreators - математика виральности: views > avg × 2.5 - тег TRENDING - для трендовых дотягиваются caption (/v1/НЕЛЬЗЯgram/post) и транскрипт (/v2/instagram/media/transcript, таймаут 60с; null - caption-only). Пока список конкурентов - статические тестовые хендлы: для реального внедрения подставляются желаемые ниши.

Контур 1.5: назовём "Семантический фильтр" (17 нод)

LLM-reranker оценивает релевантность в выбранной нише (я выбрал по автоматизации на n8n) по шкале 0-1. На роль реранкера я выбрал Qwen3 Reranker 8B через chat/completions. В его промпт зашит рубрикатор с живыми примерами: "Строим LLM-агента в n8n для обработки заявок" = 0.95 (core ниша), "Как настроить ChatGPT" = 0.75 (AI productivity), ИИ в целом = 0.5-0.69, смежное (саас бизнес) = 0.2-0.49, личные влоги = 0.0-0.19. Всё ниже порога улетает в тупик Drop: Below Threshold. Без этого контура данная "фабрика" генерировала бы контент по случайно залетевшему личному влогу автора контента.

2 -й контур: AI-диспетчер (17 нод)

Модель не копирует чужой пост! Зачем штамповать однотипный контент. Она "выжимает ДНК виральности" (хук, триггер, формат, призыв) и собирает оригинальную идею. Выход - строгая JSON-схема: angle, hooks, voice_script (120–160 символов), video_prompt, НЕЛЬЗЯgram_caption. Валидный черновик падает в Google Sheets со статусом DRAFT.

3- й контур: медиа-цех (37 нод)

Видео:seedance-2.0-mini с фулбэком на veo-3.1-lite, асинхронный поллинг (Wait 10s × 20 попыток). Голос: TTS отдаёт сырой PCM, который конвертится в WAV на лету. Конфиг в "Clean Voice Script" рассказывает о себе ещё одну вещь: флаги ARCHIVE_TO_DRIVE=false и MUSIC_ENABLED=false - это эконом-конфиг: seedance-2.0-mini/ 480p/ 5s с фолбэком на veo-3.1-lite. Обложка: image-generation с неоновым тех-вайбом. Всё с ретраями, варнингами и статусами MEDIA_READY / MEDIA_FAILED.

Последний контур: дистрибуция (19 нод)

Внутри - ещё один сюрприз: склейка видео с голосом через ffmpeg (Write -Exec -Read в /tmp). Голос опционален: нет голоса = видео уходит как есть под ключом final_mp4. Плюс у контейнера Instagram свой поллинг FINISHED - Wait 5s * 12.

Google Drive (upload + share publicly) - Instagram Graph API (контейнер REELS - publish) - permalink - обновление Sheets - отчёт в Telegram.

Диспетчер статусов на Google Sheets

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

Каждый драфт проходит цепочку статусов DRAFT - MEDIA_READY - PUBLISHED (или MEDIA_FAILED / PUBLISH_FAILED), обновление - по source_url
Каждый драфт проходит цепочку статусов DRAFT - MEDIA_READY - PUBLISHED (или MEDIA_FAILED / PUBLISH_FAILED), обновление - по source_url

Рефакторинг ради стабильности: было 156 - стало 127

Первая версия собиралась по принципу "если соберёт воркфлоу - то лишь бы работало" и раздулась до 156 нод. Минус 29 за пару вечеров:

  • дублирующиеся error-ветки сведены в единый паттерн Failed? → 402? → alert / fail-open;

  • Честности ради: в списке disabled - reserve-нода Search google, которую стелс-модель напланировала "на будущее" и которую я не стал удалять. Пусть лежит.)

  • все медиа-конфиги и модели вынесены в одну Code-ноду (Clean Voice Script) вместо россыпи Set-нод;

  • убраны промежуточные хэндоф-заглушки от старых версий архитектуры.

Раскладка по типам нод:

Тип

Количество

Зачем

IF (условия)

30

ошибки, 402, статусы, наличие бинарников

Code (JS)

28

парсинг, нормализация, PCM в WAV, конфиги

Telegram

12

алерты на каждый критический сбой

HTTP Request

11

все внешние вызовы

NoOp

11

точки передачи между контурами + тупики дропов

Sticky Note

8

документация прямо на канвасе

LangChain

6

2 агента + 2 модели + 2 structured-парсера

Google Sheets

4

статистика: append + 3 update

StopAndError

4

жёсткий стоп при 402

Триггеры

3

Manual, Schedule, ExecuteWorkflow-триггер (disabled)

Disabled-заглушки

3

2 ноды scrapeCreators, Call "Hunter_Media"

*p.s. Воркфлоу я назвал Hunter content = отсюда и названия контуров

Set

2

финальные выходы контуров 1 и 1.5

Google Drive

2

upload + share publicly

SplitInBatches

1

цикл по хендлам

Wait

1

поллинг видео (10s)

НЕЛЬЗЯagram (community)

1

публикация Reels

Можно чётко увидеть, что больше трети нод - это защитная логика. Это в принципе осознанная цена автономности.

Теперь как говориться, инженерная нутрянка

Жемчужина: PCM - WAV на лету

TTS-модель отдаёт сырой PCM (24 кГц, 16 бит, mono) без контейнера - ни n8n, ни НЕЛЬЗЯgram такой поток не понимают. Модель сгенерировала Code-ноду, пришивающую корректный RIFF-заголовок:

function wavHeader(len) {
  const sr = 24000, ch = 1, bits = 16;
  const b = Buffer.alloc(44);
  b.write('RIFF', 0); b.writeUInt32LE(36 + len, 4); b.write('WAVE', 8);
  b.write('fmt ', 12); b.writeUInt32LE(16, 16); b.writeUInt16LE(1, 20);
  b.writeUInt16LE(ch, 22); b.writeUInt32LE(sr, 24);
  b.writeUInt32LE(sr * ch * bits / 8, 28); b.writeUInt16LE(ch * bits / 8, 32);
  b.writeUInt16LE(bits, 34); b.write('data', 36); b.writeUInt32LE(len, 40);
  return b;
}

const pcm = await helpers.getBinaryDataBuffer(i, 'voice_mp3');
const wav = Buffer.concat([wavHeader(pcm.length), pcm]);
bin.voice_mp3 = await helpers.prepareBinaryData(wav, 'voice.wav', 'audio/wav');

Я перепроверил каждый байт: 44-байтный заголовок - все вычисляются, а не хардкодятся, и используются правильные binary-helpers n8n, а не наивное item.binary.data

Static Data: аккумулятор цикла без дублей

Логика сбора трендов: крутим цикл по хендлам в нише, бережно копим данные в static data воркфлоу, а на выходе вычитываем этот буфер, чистим его и до кучи делаем финальную дедупликацию по URL :

// внутри цикла:
const sd = $getWorkflowStaticData('global');
sd.acf_trending = sd.acf_trending || [];
sd.acf_trending.push(...$input.all().map(i => i.json));

// после цикла:
const rows = sd.acf_trending || [];
sd.acf_trending = [];               // состояние не течёт между запусками
const seen = new Set();
return rows.filter(r => {
  const key = r.post_url || r.shortcode;
  if (seen.has(key)) return false;
  seen.add(key); return true;
}).map(r => ({ json: r }));

402 не равно 5xx: две разные смерти сервиса

Система различает между "сервис временно умер" и "кончились у.е.". Универсальная проверка, которую модель штампует в каждой error-ветке:

const e = $json.error || {};
const sc = Number($json.statusCode || e.statusCode || e.status || 0);
const msg = String(e.message || '');
const is402 = sc === 402 || msg.indexOf('402') !== -1;

Политика в данной схеме такая: 402 = алерт в Telegram + StopAndError (штамповать ретраи без денег бессмысленно); 5xx - retry помноженное на 3 = fail-open: хендл пропускается, конвейер живёт. Отвал TTS не убивает рилс просто уйдёт без голоса, с warning в таблице.

Формула виральности в коде - не магическое число в условии, а именованная константа:

```javascript
// Phase 1: average views per handle; views > avg * 2.5 => tag TRENDING.
const TREND_MULTIPLIER = 2.5;
```

Под неё - defensive-обёртка pickNumber(), вытаскивающая счётчик просмотров из какой угодно формы ответа API.

Отдельная жемчужина - fail-open нода реранкера. Если Qwen3 умер после трёх ретраев, всем документам присваивается нейтральный 0.5 = который порог 0.75 честно отсекает. Конвейер не ломается: он просто тихо пропускает раунд. Комментарий в ноде это признаёт дословно: "0.5 < MIN_RELEVANCE_SCORE (0.75), so the filter drops them; pipeline stays healthy".

Финальный мерджер бинарников

HTTP-ноды в file-режиме стирают бинарники из $input. stealth/ox-alpha сама предложила вытягивать их напрямую из нод-производителей, минуя текущий поток:

function grabBinary(nodeNames, keys) {
  for (const n of nodeNames) {
    try {
      const bin = ($(n).first() || {}).binary || {};
      for (const k of keys)
        if (bin[k] && (bin[k].data || bin[k].fileName)) return bin[k];
    } catch (e) {}
  }
  return null;
}
const vid = grabBinary(['Fetch Video'], ['video_mp4', 'video', 'data']);
const voi = grabBinary(['PCM to WAV', 'Generate Voice'], ['voice_mp3']);
const cov = grabBinary(['Download Cover', 'Normalize Cover'], ['cover_png']);

Где модель тупила и мои собственные затупы

Без этого подраздела статья была бы наверное в стиле пресс-релиза, так что вот самы краткий список "болячек" (хотя как понимаете на 60 млн. токенов их было уйма):

Косяки модели:

  • require(‘crypto’) в Code-ноде. В n8n require недоступен - пришлось душить Cline переписывать на встроенные функции.

  • Google стирает бинарники. Google Drive нода возвращает только свой json, и голос/видео терялись после апдейта строки. Родилась нода Rebuild Handoff Item, восстанавливающая item из нод - производителей.

  • Фантомные ноды. Пару раз в JSON приезжали type/typeVersion, которых нет в нынешней версии n8n - сверял вручную.

  • Хардкод IG_USER_ID. Модель не догадалась вынести ID в credentials - в коде торчит константа. Для теста ок, для запуска - выносить в env.

Где я сам накосячил (выловил только на ручном аудите):

  • Порог реранкера разъехался. В стикере-документации MIN_RELEVANCE_SCORE = 0.75, а в IF-ноде на время отладки стоит >= 0.4 - и я честно забыл вернуть. Поймал себя на том самом "одном и том же релевантном рилсе каждый день". Вывод: конфиг должен жить в одном месте, а не в стикере и в ноде раздельно.

  • Поллинг видео 20 помножить 10с. В часы пик очереди Veo/Seedance могут быть длиннее -MAX_ATTEMPTS придётся поднять.

А теперь пример затупов/косяков, и почему это не провал:

 Самое крутое - система не умерла молча. Мне в Telegram прилетел аккуратный алерт со ссылкой на конкретную ошибку, а сам черновик видео спокойно остался лежать в таблице
Самое крутое - система не умерла молча. Мне в Telegram прилетел аккуратный алерт со ссылкой на конкретную ошибку, а сам черновик видео спокойно остался лежать в таблице

Видео не сгенерировалось = драфт не потерян, помечен MEDIA_FAILED. Публикация не прошла = алерт с причиной и ссылкой на Drive для ручной загрузки. Мелочь для внимательных: Telegram съел подчёркивания, и в сообщении красуется "MEDIAFAILED" - можно считать это бесплатной цензурой маркдауна.

Реальный запуск воркфлоу в цифрах: сколько это ест ресурсов

 Тот самый момент, когда честно скрестил пальцы на все 4 минуты)
Тот самый момент, когда честно скрестил пальцы на все 4 минуты)

Скажу честно: когда я запускал этот тест (ведь ждал в конце хоть и кривую копеечную генерацию), то реально скрестил пальцы)). Ожидания оправдались: лог выполнения (Execution) выдал заветный зеленый статус!))) 

Для тех, кто крутит тяжелую автоматизацию, эти цифры на скрине - самый сок: 

  • Время выполнения (4м 13сек): Для сквозного процесса, где внутри сидят генерация видео через API (с постоянным поллингом статуса), озвучка от Gemini и кастомная склейка байтов, четыре минуты с копейками - это отличный результат. Основное время, понятное дело, уходит на ожидание ответов от серверов генерации. 

  • Потребление памяти (8 MB): Весь запуск огромной махины сожрал всего 8 мегабайт. Помните наш трюк с пакетной сборкой трендов в $getWorkflowStaticData('global') вместо раздувания стандартного контекста внутри цикла? Вот это и есть главное доказательство того, что оптимизация сработала. Мы не держим тяжелые бинарники в оперативной памяти n8n, благодаря чему сервер чувствует себя прекрасно и не улетает в Out of Memory. 

А вот и результат в профиле

Обложка от google/gemini-3.1-flash-image: кириллица читается, модель сама придумала контраст "грустный базовый ChatGPT vs n8n"
Обложка от google/gemini-3.1-flash-image: кириллица читается, модель сама придумала контраст "грустный базовый ChatGPT vs n8n"
Кадр: seedance снял ровно то, что просил video_prompt - интерфейс n8n без людей. Caption собран по схеме: боль - ценность - CTA с кодовым словом + 8 хэштегов
Кадр: seedance снял ровно то, что просил video_prompt - интерфейс n8n без людей. Caption собран по схеме: боль - ценность - CTA с кодовым словом + 8 хэштегов

Рилс ушёл в публикацию через Graph API: в таблице статус PUBLISHED с permalink, у поста дата "3 дн.". Цепочка отработала целиком: скрапинг - реранкер - диспетчер - медиа-цех - Drive - НЕЛЬЗЯgram. Поясню: это тестовый прогон на тестовом аккаунте - целью была проверка воркфлоу, а не сбор просмотров(!). Факт: текст, обложка, видео и публикация сгенерированы цепочкой; я лишь нажал ExecuteWorkflow.

Экономическая сторона: 60,9 млн токенов за примерно 4 у.е.

Да, +217211% - до "эксперимента" аккаунт будто проставивал
Да, +217211% - до "эксперимента" аккаунт будто проставивал

Вопрос возникает сходу: почему так дёшево?! Во-первых, stealth-окно было бесплатным. Во-вторых, итерактивная разработка в Cline - это перечитывание одного и того же контекста, и prompt кэшинг превращает 85% запросов в кэш-хиты.

Сразу закрою ожидание: это не обзор модели по бенчмаркам - таких с релиза вышло десяток, и все пересказывают одни и те же таблицы. Здесь 127 нод, живой тестовый НЕЛЬЗЯagram и счёт в долларах за реальные прогоны.

И факты по модели после деанона: Z.ai GLM 5.3 Flash - нативная мультимодальность (текст, картинки, видео на вход), контекст 1М токенов, релиз 26 августа. Цены сейчас: $0.075/$0.25 за 1M (in/out) при скидке Z.ai −50% до 9 сентября, кэш-рид $0.015. И вишенка из статистики: по объёму токенов в топ-3 приложений модели входит Cline - тот самый, через который это всё и "навайбкодилось".

Сколько бы стоил такой объём на платных моделях (по самой верхней таксе, 90/10 input/output). Да, модели в таблице не по принципу "топ под задачу"! Честно- я просто ткнул пять моделей из разных ценовых категорий каталога OpenRouter, чтобы показать вилку. Это сравнение ценников, которые я посчитал по среднему, а не бенчмарк.

LLM

Цена за 1M (in/out)

Оценка за 60,9M

Anthropic: Claude Opus 4.8

$5 / $25

около 426$

OpenAI: GPT-5.6 Terra

$2 / $12

около 183$

Anthropic: Claude Sonnet 5

$2 / $10

около 171$

Qwen: Qwen3.8 27B

$0,35 / $2,75

около 36$

DeepSeek: V3.1 Terminus ( единственный минус упомяну что у модели контекст всего 164К.)

$0,27 / $1

около 21 $

stealth/ox-alpha + кэш

$0,07

около 4$

То есть формально, если говорить про именно LLM из таблицы, то все пять под задачу "агентный кодинг марафон" подходят по позиционированию, разница - в ценовой категории и размере окна. Единственная реальная оговорка что 164K у DeepSeek против проделанных мега сессий. И да, парадокс, который можно подчеркнуть: бесплатная загадочная модель построила фабрику, которая крутится на копеечных DeepSeek, Gemini-flash и seedance, которые жгут центы за публикацию.

Итоги

  • Модель - это джуниор разраб с энциклопедической памятью и нулевым опытом. Защитный код (defensive-парсинги, fail-open, корректная бинарная арифметика) она выдаёт только тогда, когда защитный код запрошен в ТЗ. Мой промпт - не магия, а чёткие инструкции.

  • Бенчмарки не показывают главное. Анонимная stealth-модель бесплатно вытянула в принципе стабильную сборку с пятью API, бинарниками и асинхронщиной - это проверяется только спустя наверное с пару десятков запусков воркфлоу.

  • Отказоустойчивость - это наверное фишка номер 1. Ведь, блин, согласитесь, что ценность не в том, что конвейер работает, когда всё работает, а в том, что он не теряет данные, когда всё падает!)

Зоны роста воркфлоу

От себя, могу в теории предложить развитие данного проекта (если бы это был реальный кейс) примерно в таком направлении:

  • разбор монолита на три воркфлоу (Radar / Generate / Publish),

  • Telegram-бот с human-in-the-loop управлением ("Опубликовать / Перегенерировать")

  • ветка нейроаватара ( модель, к примеру, HeyGen: Avatar IV недавно вышедшая - хорошо подойдёт на эту роль);

Вместо заключения

Из каждого угла сейчас можно прочитать: "...ИИ заменит программистов и ИТшников все, просто скажи “сделай мне сайт”...". Этот эксперимент = аргумент против. Модель за три дня сожгла 60,9 млн токенов, чтобы получилось то, что получилось: отличную заготовку, требующую ручного аудита каждого порога, каждой ноды, каждого байта заголовка WAV. "Сделай мне сайт" она бы сожгла за вечер - вместе с продакшеном. Заменит не ИИ. Заменит человек, который научился им пользоваться, тем же, кто умел пользоваться компилятором и Stack Overflow. Инструмент новый. Профессия та же: отвечать за результат.