Информация
- В рейтинге
- 511-й
- Откуда
- Минск, Минская обл., Беларусь
- Зарегистрирован
- Активность
Специализация
Фулстек разработчик, Промпт-инженер
Ведущий
n8n
Node.js
JavaScript
API Интерфейсы
Redis
Docker
Системная интеграция
Организация работы с CRM
Управление проектами
про окс альфа у меня опыт её аналогичного теста был тоже - только там в разы по мощнее , на 60 млн. токенов - подробно опубликовал такой тест https://habr.com/ru/articles/1076084/ . Конечно на вкус и цвет товарищей нет) могу сказать что Pareto скорость выдала нереальную по сравнению с GLM 5.3 flash . Кстати в одном проекте опробовал не надолго в Visual code GLM 5.3 FlashX = кстати как и заявлено что скорость в разы от тёзки флэш модели лучше) вот только не знаю на счёт GLM 5.3 - на опен роутер в 2 раза дороже вышеперечисленных а по бенчмаркам апгрейд относительно 5.2 внушительный = на DeepSWE выдает 66.9% против прежних 46.2%)... явно затачивали под long-horizon задачи. Ей не пользовались?)
Спасибо за мощный комент!) дельные уточнения.По тестам- спорить не с чем, вы правы. Тезис статьи был про пространство триггеров: какая именно фраза уведёт reasoning-модель в тупик не перечислишь. Но инвариант обработки действительно конечен: "пустой content + completion_tokens больше 0 + finish_reason=stop не считается успехом" проверяется property-based тестом без перебора речи. На практике в n8n это делается так: отдельный тестовый воркфлоу генерирует широкий класс состояний диалога, LLM "мокается" / сигнатура инжектится прямо в валидатор, и assertion один - ниже валидатора пустота не проезжает ни при каком входе. Живую модель в тест не пускаем - она стохастична. Итого: тесты покрывают "что мы делаем с багом", прод измеряет "как часто он случается"= ваша формулировка точнее моей, заберу в follow-up.По retry - честный ответ: отдельного stable operation ID на send нет, и, насколько знаю, у send эндпоинтов Mета клиентского idempotency-key в принципе не предусмотрено. Гарантия одиночности живет на двух других уровнях.Первый: входящее событие берется в работу Redis-клеймом (SET NX на id сообщения/комментария) = конвейер на событие выполняется строго одним экземпляром.Второй: валидатор стоит до Format/send. Пустая попытка до отправки физически не доходит, а retry - это повторная генерация с "пинком" в system, а не повторная отправка. Send исполняется ровно один раз: либо выводом attempt-1, либо attempt-2. НО, признаю что ваш вопрос вскрыл уязвимое место: tool-вызовы. В наблюдаемой сигнатуре (все токены внутри think, ноль в content) тулзов модель не дергала, поэтому задвоить CRM-действия повтор было нечем. Класс же "попытка успела мутануть сделку тулом и умерла с пустым content" теоретически возможен - тогда повторный прогон агента может задвоить мутацию. Сейчас это страхует идемпотентность на уровне записей в CRM = клеймы по chatId + event_id, salesbot Идентификатор отсекает дубли сделок, но явного guard "retry после попытки с tool-calls" в валидаторе действительно нет. Добавил в бэклог, в follow-up с цифрами счетчика опишу и это - ваш коммент улучшил архитектуру))
вы абсолютно правы насчет инфраструктуры!) что у unbiased явно не бюджеты крупных поставщиков вроде Z.ai, чтобы держать миллионный DDOSнаплыв. посыл как раз про это: бесплатные окна сейчас закрываются молниеносно. Можно говорить на плохой аптайм стартапа, а можно за пару часов успеть прогнать llm для своих нужд, пока бесплатное окно открыто. Для меня этот тест окупился - повезло, хотя думал и сегодня воспользуюсь халявой, но...) а стабильность... как сказать, блин.. за стабильностью мы наверное все ходим, к примеру, к Sonnet или Opus 5 за полную стоимость)
Да, вы правы... сутки халявы закончились((.. быстро раскрылась интрига однако
да, вроде так было) у stealth/ox‑alpha неделя была - и сразу спустя это время выяснилось что за модель кто поставщик и сумма (хотя потом ещё неделю 50% скидки давали). а в данном случае абсолютно нет дедлайна
Спасибо за коммент) Рад, что разбор пригодился!) Модель только вчера выкатили - решил сразу "бросить её в бой" - как раз совпало что повод есть). Если кому-то пригодился такой тест-разбор - значит писал статью не зря))
По поводу качества эта
union-alphaреально удивила. Помимо сильного самоанализа, она отработала в разы быстрее предыдущего stealth/ox‑alpha. Ну и само что мне зашло - на выходе получился чистый JSON, что в n8n не пришлось вручную убирать/добавлять ноды.Интригует ещё вот какой момент: у stealth/ox‑alpha провайдеры хотя бы сразу прописали четкие сроки бесплатного периода а как только он кончился = сразу стало понятно, кто поставщик и что за модель). А тут вообще никакой конкретики по таймингам. Так что интрига двойная...
Запустить тот же контекст в ллм-ку, чтобы она "опять зависла с какой-то вероятностью" - это отличный способ сжечь токены, но плохой способ построить надежный бэкенд к сожалению( я уже писал выше, этот poison message давно на стенде. Но мы тестируем им валидатор, а не стохастический "черный ящик" так сказать. впринципе то у LLM-агентов регрессия самой модели не гарантирует ровным счетом ничего: завтра юзер напишет ту же мысль, но другими словами, и база тестов радостно загорится зеленым, а прод снова упадет. Именно поэтому фокус надежности смещается с регрессии модели на жесткую рантайм-архитектуру вокруг нее. Могу вкратце рассказать что когда на 2х недельном бесплатном периоде после внедрения этого проекта, мне правок в промт прилетало что то около 6 штук (таких конкретных причём), и всё из за того что на стадии согласования ТЗ из 9 листов скринов ответов для нейронки, дословно, "...таких вариантов мы не продумали, надо как то сделать чтобы не повторилось Артём..."... наверное именно поэтому данный проект запомнится на долго мне)))
Идея конечно могу сказать немного неординарная) Хотя глубокий замысел довольно таки)
И...да, ничего плохого не хочу сказать ни вкоем разе!) выглядит как натальная экзотерическая таблица что ли) ещё раз ничего плохого сказать не хочу - реально интересная задумка, и очень глубокая)
Да ну ладно вам) думаю у каждого бывает строчишь по клаве, а потом смотришь и вся орфография на уровне детского сада) про запятые и переносы вообще внимание порой не обращаешь) а с мобильника так тем более не заметно)
Спасибо за развернутый комментарий и отличные инженерные мысли! Про стат-анализ, теорию надежности и фиксацию temperature: 0 для дебага конечно абсолютно правильная база для классического бэкенда.
Однако в данном кейсе классический QA упирается в тупик. В одной из прошлых статей (https://habr.com/ru/articles/1076198/) я подробно описывал архитектуру этого агента. Промпт там не просто текст, это жесткая детерминированная карта тегов ([VERDICT:], [TASK:], [STAGE:]), совмещенная с жесткой иерархией Ступеней и JS-логикой внутри кастомных инструментов. Посмотреть на такое и становится понятно, почему автотесты на воспроизведение бессильны: 1. Комбинаторный взрыв в карте тегов. Модель обязана нарезать логику по строгим рельсам и не имеет права отвечать “из головы”. Как только на вход прилетает живая человеческая рефлексия (вне скриптов), в блоке на нулевой температуре модель гарантированно упирается в логический тупик: вызвать тул нельзя (нет триггера) = ответить от себя запрещено =единственный compliant-вывод, не нарушающий карту тегов = промолчать. Тестировать “мигание” или семантику? Да, мы можем зафиксировать temperature: 0 и отловить этот конкретный poison message. Но семантика человеческой речи бесконечна. Завтра клиент напишет метафору, послезавтра — скинет двусмысленный смайлик. Мы не можем написать миллион тестов на все оттенки человеческих мыслей, которые выбивают модель из детерминированной карты. А если мы начять крутить промпт и баланс запретов ради прохождения одного этого теста - так это гарантированно сместим веса детерминированной карты. На тесте всё будет “зеленым”, а в проде получится Reasoning Lock на сотне других живых диалогов, которых в базе тестов еще просто нет. Вы абсолютно правы в одном: QAить сам динамический валидатор — нужно. И именно для этого используется этот “отравленный” промпт на тестовом стенде. Но задача данного теста - проверить не то, что модель ответит хорошо, а то, что наш валидатор в n8n корректно перехватит пустоту, залогирует её через include_reasoning и сделает правильный ретрай с пинком. С рассуждающими LLM и жесткими бизнес-ограничениями физически нельзя гарантировать идеальное поведение модели тестами, поэтому фокус надежности смещается с “написать идеальный тест” на “построить отказоустойчивую архитектуру (слои защиты) вокруг модели”. И детерминированная карта тегов здесь как раз доказывает, что ловить такие глухие защиты нужно динамически и на лету.
Спасибо за комментарий) Поясню: в том-то и засада, что LLM стохастичны. Если температура выше нуля, модель на один и тот же промпт может 9 раз ответить нормально, а на 10-й уйти в глухую защиту и выдать пустоту. Всунуть этот кейс в автотест можно, но он будет так сказать, "мигать": тесты покажут зелёный свет, а в проде баг всё равно выстрелит. К тому же, если начать крутить системный промпт ради одной этой фразы, итогом будет сместить баланс запретов, и модель начнёт выдавать Reasoning Lock на сотне других живых диалогов, которых в тестах ещё нет.К сожалению классический QA тут сливается, эту дичь ловить приходится только динамически и прямо на лету, как раз через валидатор.
Спасибо за коммент) отличный вопрос - видно что прочитали внимательно статью)) Наверное могу сказать что прямо в корень зрите! Отвечу вкратце: я по началу думал про урезание промпта на ретрае, но тут как раз решает контекстный кэш оpenrouter, который я в таблице показывал. Поскольку базовые 6,4 к. токенов на 90% сидят в кэше, повторный прогон стоит копейки. Да и блин, если я начну на ходу подменять системный промпт на "лёгкую" версию, я просто собью кэш и заплачу за этот "лёгкий" промпт полную стоимость, что экономически невыгодно (хоть и не мои деньги то, баланс не к моим картам привязан - но заказчик их контролит знатно). да и в рамках n8n + LangChain передавать "пинок" через payload в system_kick банально проще архитектурно, чем городить ветвление с подменой текстовых шаблонов в системной ноде. Но опять же - выше сказал своё ведение и решение ) За мысль спасибо, честно))
Hello, ChimsK! Thank you for such deep, production-grade engineering questions. It’s incredibly refreshing to discuss the actual gaps between "generated" and "bulletproof" architecture in the comment section.To give you the full context: this entire pipeline was a fast-paced stress-test of the stealth/ox-alpha (GLM 5.3 Flash) model under a heavy agentic coding marathon. It was never intended to be packaged as a commercial case or put into active production—the 127-node JSON workflow is currently sitting idle as a snapshot of what a low-cost LLM can orchestrate in 3 days. However, you hit the exact architectural pain points that separate a demo from an enterprise system.Here is how these two edge cases look from my perspective:1. The Publication Gap & Distributed State ConsistencyYou are absolutely right about the danger of the gap between a side effect happening in Meta's infra and recording it in Google Sheets. In the experimental setup, if the Nginx/n8n process crashed or the Google Sheets API timed out after a successful Instagram publish, the next cron run would indeed see a DRAFT status and attempt a duplicate upload.To fix this for a real production environment, the step must be made idempotent. Since Instagram Graph API handles Reels in a two-step process—creating a media container (POST /media) and then publishing it (POST /media_publish)—the state transition must be strictly decoupled:Step 1: Generate the media container ID from Meta and immediately commit this ID and timestamps to Redis/Sheets before initiating the final publication.Step 2: On any re-run, the node router checks if a container ID already exists for the given source_url. If it does, instead of uploading a duplicate, it executes a GET request to verify the container's status on Meta’s side. If it's already published, we simply force-update the Sheet to PUBLISHED and fail-open.2. The 3% Hallucination & JSON Schema ValidationYour 97% vs 3% estimation is spot on. Models excel at mimicking plausible naming conventions, which is highly dangerous when n8n node parameters change across versions (e.g., typeVersion mismatch).For this specific experiment, I did not use an automated validator against the official n8n JSON schema. Given the scale and the rapid iteration cycle with Cline, a meticulous manual code audit during the import phase was enough to catch things like ghost parameters, phantom fields, or illegal require() calls inside JavaScript Code nodes (which I documented in the article's flaws section).However, if I were to scale this into a fully autonomous, self-healing framework without a human-in-the-loop audit, injecting a strict schema validation step (using n8n's community schema definitions) directly into the Cline output pipeline would be an absolute mandatory layer of defense.Thanks again for the brilliant breakdown. It's precisely these edge cases that make backend engineering so fascinating!
Если использовать стандартные ноды ожидания
Waitвнутри самого n8n для проверки лока под нагрузкой = естественно поймать Out of Memorу. Когда жесткий наплыв с таргета, сотни висящих в памяти процессов n8n мгновенно сожрут все ресурсы VPS.Поэтому в уровне 2 моей статьи описана сама фишка в схеме = внутри n8n никто ничего не ждет) Лок работает по неблокирующему принципу Drop-if-Locked на стороне Redis: прилетает хук, мы делаем проверку ключа лока = если лок занят (обработка уже идёт), этот поток n8n тут же завершает выполнение. Он не уходит в режим ожидания, не запускает таймеры = он просто мгновенно умирает. Память сервера свободна. Само входящее сообщение при этом уже безопасно лежит в буфере Redis (RPUSH). Выгребать этот буфер будет только самый первый поток, который этот лок и захватил. Он отработает паузу дебаунса, а затем атомарным LPOP вычистит всю очередь до нуля.
Вы правы полностью = блокирующий лок внутри самой n8n опасен!) Именно поэтому архитектура перенесена на Redis, чтобы n8n выполнял только быструю линейную работу без "засыпаний" в памяти.
да, в том то и фишка: на вопрос даже не ЗАЧЕМ агент это сделал, а просто ДЕЛАЛ ЛИ - в ответ отрицание. И вы правы - чужого системного промта не видно,увы
Хороший разбор, особенно зацепило правило "после записи состояние перечитывается". Поделюсь случаем в тему: недавно поймал похожий семантический сбой на уровне повыше - при тестировании автономного ИИ-агента (Cline + glm-5.3-flash), у которого был доступ к Browser Use. Ситуация один в один как ваш третий случай про " запрос принят, но разошелся с замыслом". Из-за конфликта внутренних системных промптов агент отказался генерировать тестовый джайсон файл, но решил по его мнению "нанести пользу" иначе. Он увидел открытую вкладку в браузере, сам распарсил DOM-дерево и бахнул клик публикации. С точки зрения API — статус 200 OK, впринципе норм и соблюден. С точки зрения логики пользователя как то не очень то). А самое веселое, что при попытке перечитать состояние постфактум и спросить агента в чате "Зачем сделал?", он из-за очистки фонового контекста выдал галлюцинацию отрицания и сказал, что ничего не делал. Агентные слои сейчас - это получается порой риск ввиду таких скрытых ошибок
Доброго времени суток! Отличный разбор) Плюс за честность, детальный таймлайн аварии и чистую команду ремонта через compose с запретом трогать зависимости! Отдельный плюс за тезис про то, что "healthy контейнера - не доказательство работоспособности бизнес-цепочки"!)
Обычно все успокаиваются на зелёной плашке в мониторинге, а тут такая засада. Знакомая ситуация...бррр.. Недавно на self-hosted n8n ловили отказ точно такого же класса: снаружи всё выглядело как просто случайный сетевой таймаут, а внутри оказалась гонка данных на общем Redis-ключе. И как у Вас один в один похоже - "очень похоже на медленную базу", да и логи идеальные. Раскрутить получилось только когда сел руками сопоставлять таймстампы двух параллельных экзекушн.
По поводу Вашего техдолга)) хочу спросить: Служебные воркфлоу (тот же SQL-мост) в отдельный пул планируете выделять вообще отдельной инсталляцией n8n или просто разнесением очередей по разным воркерам внутри той же самой инсталляции? Я такое видел в проде на нагруженных проектах, и у каждого, мягко говоря, свои специфические затыки... Интересно, в какую сторону вы смотрите?
Ваша правда: пока токен жив, параллельные запросы работают без проблем. Затык именно в момент ротации раз в сутки.
Могу по себе сказать: Redis с TTL пожалуй лишь один из вариантов, и без атомарной блокировки (вроде SET NX или flock) от гонки в момент удаления ключа он не спасет по большей части. Пачка параллельных хуков все равно может синхронно ломануться в API. Проблема специфическая как оказывается специфичная и даже скрытая = общался по этому вопросу с интегратором, у которого за плечами более 240 кейсов, и даже там этот момент со сгоранием долбанного refresh_token на нагруженных проектах вызывал ступор.
В любом случае, круто, что подняли эту тему. Было приятно подискутировать и обменяться опытом!) Ждем новых разборов по специфике работы с CRM))
Спасибо за развернутый бэкенд). Логика понятна: про expires_at в БД — абсолютно рабочая схема для большинства API впринципе. Но блин, конкретно с amoCRM есть одна жесткая подводная засада, из-за которой Redis с TTL либо аналог в памяти приходится городить с самого первого запроса. Просто при каждом обновлении access-токена старый refresh-токен моментом сгорает и выдается пара новых. Если на систему прилетает два параллельных хука ( типа юзер отправил два быстрых сообщения подряд) = два curl-запроса на обновление токена улетают одновременно. Что на выхлопе получается гонка данных: первый запрос обновит ключи, а второй падет из-за того, что его refresh-токен уже аннулирован. А итог - интеграция намертво ложится, пока клиент руками заново не авторизуется.Поэтому кэш в оперативной памяти с блокировкой повторных запросов на обновление - это в amoCRM становится вынужденная мера безопасности, и пофиг что в сутки идет всего 10 запросов. Спасибо ещё раз за интересную и продуктивную дискуссию))
Спасибо за детальный разбор кода и отличные конструктивные вопросы по логике!)) Постараюсь вкратце)
1.По поводу HTML-парсинга против регулярок.Идея с кастомными HTML-тегами (вроде <phone.....</phone>) хорошая, я её гонял на этапе проектирования контура. Но в проде вылезли грабли: на fallback-модели (в пики подхватывает Qwen через OpenRouter , сначала была Llama через грок) нейронка при генерации длинных ответов иногда тупо "забывает" закрывать теги, путает их местами или нафиг экранирует знаки < > как HTML-сущности. В итоге штатные HTML/XML парсеры в n8n на таком выводе просто падали по синтаксической ошибке.Текстовые маркеры в верхнем регистре ([VERDICT:...]) и регулярки оказались тупее, это факт...но тупо надежнее!) Флаги gm и универсальный "пылесос-очиститель" /[A-Z_]+:\s*[^\]]*/gi вытаскивают сущности, даже если модель поплыла по форматированию. А сам человекочитаемый блок с анкетой в конце - это внутренний такой "черновик" для самой LLM в рамках сессии LMemory, чтобы она не теряла контекст. Перед отправкай клиенту этот кусок всё равно срезается нодой Format Response, так что юзер его не видит.
2. Про нарезку на 180 и 140 символов.Тут в статье из-за сокращения кода получился визуальный парадокс) Логика там как раз каскадная. Нода Format Response сначала нарезает сырое полотно на абзацы (лимит 180 символов = это чисто визуальный ориентир для предложений, чтобы текст на экране смартфона не выглядел как спам-рассылка - и тут скорее , так сказать "эстетические пожелания заказчика"... А вот финальный контур отправки (сама нода Split AI Response) уже берет этот готовый красивый текст и жестко пилит его по предложениям на чанки строго до 140 символов, чтобы отправлять их в Директ порциями через цикл с Typing Delay. Так что один большой смысловой абзац может улететь двумя короткими сообщениями с имитацией живого набора текста, что визуально считывается клиентом как общение с человеком( и впринципе мало клиентов понимало что они вообще с ии говорят = что пришлось докручивать ,из юридических соображений, на штатное "Здравствуйте, я ИИ - ассистент ателье ХХХХХ" )
3. Про тег "говнокод"..) А вот тут вы попали в самую точку, тег висит не просто так) На самом деле, этот проект вытрепал мне столько мозгов и нервов, сколько ни один другой. И дело было не столько в самой разработке, а в заказчике, точнее скорее непонимании того что он хочет = не так легко и не по щелчку. Перед самым запуском и финальным расчетом мне кидали правки в промпт 6 раз(!). А в первые две недели после внедрения (на период бесплатного теста и гарантии) начался сущий ад — прилетал бесконечный вал скринов и сообщений в духе "твой ИИ говорит не как живой менеджер и не так запятые ставит". Я в какой-то момент вообще перестал семье время уделять (а когда дочери 14 лет, а сыну 1,5 года — это критично), зашился полностью в вылизывании того, что по определению детерминированным быть не может.В итоге просто ткнул пальцем в пункты подписанной оферты и прямо сказал, что сегодня же всё отключаю к чертям до выяснения отношений. Только после этого наступила тишина и ко мне прислушались) Сейчас, к слову, продукт крутится уже 4-й месяц, всё стабилизировалось и работает нормально - на октябрь расширение хотят на ещё мессенджер, к слову меня заказчик не трогает и я их))
опечатка promt в имени поля Redis-ноды, на которую завязана куча логики и которую теперь тупо и не охота трогать - официально считается частью этой так сказать выстраданной архитектуры)) ещё раз спасибо Вам за оценку кейса)