Тихие отказы в ИИ-пайплайнах: почему зелёный статус контейнера врёт и как мы срезали 90% расхода на LLM
Запасная ветка в блоке catch без отдельного счётчика и алерта маскирует полный отказ системы: новый агентный конвейер из трёх моделей не отработал в продакшне ни разу за несколько месяцев, пока CLI зависал на пустых OAuth-конфигах MCP-серверов. Постановка детерминированного предфильтра заголовков и триграммного дедупликатора перед вызовом LLM и генерацией медиа отсекла 76,5% информационного шума и сократила ежедневные расходы на API примерно на 90% (со 100+ до 22 вызовов за прогон). Использование DEFAULT 0 вместо DEFAULT NULL при миграции колонки рейтинга молча выкинуло из выдачи 678 качественных статей, а цикл сна перед первым запуском фоновой задачи обнулял обновление курсов валют при каждом деплое.

- Экономия токенов на предфильтрации: падение доли холостых расходов с 88% до минимума, снижение вызовов LLM со 100+ до 22 за прогон (-90% бюджета)
- Эффективность детерминированного скоринга: отсев 76,5% нерелевантного входящего потока за 0 API-вызовов и освобождение 4,9 ГБ диска
- Цена ошибки в миграции БД: 678 потерянных статей из-за `DEFAULT 0` вместо `DEFAULT NULL` и рост одобренной базы с 341 до 943 после бэкфилла
- Скрытые ресурсы: 2 244 озвученных аудиофайла (6 ГБ, 69% покрытия базы), не попадавших в интерфейс из-за пропущенного поля в `SELECT`
Самый дорогой класс багов в автономных ИИ-системах — это не падение с красным трейсбеком, а тихий отказ (`silent failure`). Контейнер в `docker ps` светится статусом `Up`, крон завершается с кодом `0`, статьи выходят в ленту — а новый код, на который ты потратил неделю, в реальности не выполнился ни одного раза.
Именно это произошло в моём новостном ИИ-конвейере после переезда со связки `n8n + Airtable` на собственный серверный стек (40 часов миграции, `MIGRATION.md` на 600+ строк для сохранения контекста между сессиями). Я собрал цепочку из трёх агентов (`EditorAgent`, `WriterAgent`, `QAAgent`) и обернул её в аккуратный `try / catch` с переключением на старый `AIProcessor`.
Почему блок catch с запасной веткой маскирует пятиярусный отказ месяцами?
Поскольку запасная ветка исправно выпускала материалы, внешне система выглядела здоровой. Лишь спустя несколько месяцев я заметил в логах регулярную строку `Agent pipeline failed. Falling back to AIProcessor`. Когда мы начали снимать слои этого отказа (сессия потребовала 1 320 сообщений и 517 запусков субагентов), под капотом обнаружилась матрёшка из пяти причин:
1. Короткоживущий токен авторизации CLI протухал каждые несколько часов. 2. Настройка `timeout` принималась конструктором базового агента, но не пробрасывалась в дочерний вызов. 3. Тяжёлая модель на этапе кураторства не укладывалась в лимит времени на больших пачках (перевод на более быструю модель ускорил шаг в 3–4 раза). 4. Обновлённый бинарник CLI перестал принимать устаревший флаг `--max-tokens`. 5. Внутри контейнера CLI намертво зависал на строке `Fetched 4 servers`, пытаясь инициализировать облачные MCP-коннекторы (Notion, Figma, Linear, Sentry) с пустыми OAuth-конфигами.
Урок железный: любой fallback без отдельного счётчика и алерта — это не отказоустойчивость, а маскировка аварии. Точно так же статус `Up` у контейнера не ловит внутренний Python-скрипт в краш-лупе по `SyntaxError` на 98% CPU: настоящая проверка — стабильный `PID` старше 60 секунд и прогон `python3 -m py_compile`.
Как перестановка фаз пайплайна и триграммный дедуп экономят 90%
бюджета на модели?
Вторая ревизия вскрыла финансовую дыру: из 3 235 обработанных новостей в публикацию шло 340, но дорогие вызовы LLM, обложки и озвучка (TTS) выполнялись до финального отсева (88% бюджета сгорало впустую, а дублирующийся crontab дёргал сборщик 288 раз в сутки вместо 48). Мы поставили перед моделью бесплатный предфильтр на регулярках и весах источников (100+ паттернов на EN/RU/ZH, где для иероглифов без пробелов используется `includes()` вместо `\b`):
```javascript function scoreArticle(title, sourceName) { let score = 0; const t = (title || '').toLowerCase(); const s = (sourceName || '').toLowerCase(); if (SOURCE_TIERS.tier1.some(x => s.includes(x))) score += 4; else if (SOURCE_TIERS.tier2.some(x => s.includes(x))) score += 3; let kw = 0; for (const rx of AI_KEYWORDS) { if (rx.test(title)) kw++; } score += Math.min(kw, 4); if (AI_COMPANIES.some(c => t.includes(c))) score += 2; if (title && title.length > 20) score += 1; if (/\d/.test(title)) score += 1; return score; } ```
Этот фильтр отсекает 76,5% входящего шума за ноль токенов. Поиск дублей мы перевели с LLM на гибрид коэффициента Жаккара по триграммам и расстояния Левенштейна (снизив порог Жаккара для русской морфологии с 0,65 до 0,40 со сверкой сущностей). Расход на API упал на 90% (со 100+ до 22 вызовов за прогон), а чистка сиротских медиа освободила 4,9 ГБ (1 764 картинки и 1 398 аудио).
Почему DEFAULT 0 в миграции базы и sleep перед первым прогоном прячут данные?
Третий тихий отказ стоил месяца поисков: при добавлении колонки `ALTER TABLE ... ADD COLUMN hot_score INTEGER DEFAULT 0` все 678 старых статей получили оценку `0`, и SQL перестал отличать «ещё не считали» от «получили ноль». Переход на `DEFAULT NULL` и бэкфилл вернули в выдачу 581 статью, утроив одобренную базу с 341 до 943. Рядом нашлись забытый `LIMIT 5` в выборке оркестратора и пропущенное поле `audio_path` в `SELECT`, прятавшее 2 244 готовых аудиофайла на 6 ГБ (69% базы). Наконец, фоновая задача курсов валют начиналась с `await asyncio.sleep(86400)` до первого запуска и при ежедневных деплоях не сработала ни разу (вылечено `FIRST_RUN_DELAY_S = 90` и `last_success_at`), а проверка статики через `curl` по коду `200` на SPA-конфиге nginx получала `index.html` вместо пропавших PDF.
Эти инварианты наблюдаемости встроены в платформу [Nomad AI](https://nomadnet.ai) и облачный рантайм [agent.nomadnet.ai](https://agent.nomadnet.ai). Практикум по отладке автономных пайплайнов доступен в [Hamidun Academy](https://academy.hamidun.com) (72-часовой триал), а аудит-скрипты лежат в [Vibe Club](https://hamidun.com/club).
Вопросы и ответы по материалу
Почему блок catch с запасной веткой маскирует пятиярусный отказ месяцами?
Поскольку запасная ветка исправно выпускала материалы, внешне система выглядела здоровой. Лишь спустя несколько месяцев я заметил в логах регулярную строку `Agent pipeline failed. Falling back to AIProcessor`. Когда мы начали снимать слои этого отказа (сессия потребовала 1 320 сообщений и 517 запусков субагентов), под капотом обнаружилась матрёшка из пяти причин: 1. Короткоживущий токен авторизации CLI протухал каждые несколько часов. 2. Настройка `timeout` принималась конструктором базового агента, но не пробрасывалась в дочерний вызов. 3. Тяжёлая модель на этапе кураторст
Как перестановка фаз пайплайна и триграммный дедуп экономят 90% бюджета на модели?
Вторая ревизия вскрыла финансовую дыру: из 3 235 обработанных новостей в публикацию шло 340, но дорогие вызовы LLM, обложки и озвучка (TTS) выполнялись до финального отсева (88% бюджета сгорало впустую, а дублирующийся crontab дёргал сборщик 288 раз в сутки вместо 48). Мы поставили перед моделью бесплатный предфильтр на регулярках и весах источников (100+ паттернов на EN/RU/ZH, где для иероглифов без пробелов используется `includes()` вместо `\b`): ```javascript function scoreArticle(title, sourceName) { let score = 0; const t = (title || '').toLowerCase(); const s = (sourc
Почему DEFAULT 0 в миграции базы и sleep перед первым прогоном прячут данные?
Третий тихий отказ стоил месяца поисков: при добавлении колонки `ALTER TABLE ... ADD COLUMN hot_score INTEGER DEFAULT 0` все 678 старых статей получили оценку `0`, и SQL перестал отличать «ещё не считали» от «получили ноль». Переход на `DEFAULT NULL` и бэкфилл вернули в выдачу 581 статью, утроив одобренную базу с 341 до 943. Рядом нашлись забытый `LIMIT 5` в выборке оркестратора и пропущенное поле `audio_path` в `SELECT`, прятавшее 2 244 готовых аудиофайла на 6 ГБ (69% базы). Наконец, фоновая задача курсов валют начиналась с `await asyncio.sleep(86400)` до первого запуска и
От чтения про ИИ-агентов — к запуску своего агента за вечер
Пошаговая сборка автономных агентов и MCP-связок в Hamidun Academy (academy.hamidun.com) (72 часа бесплатно) или мгновенный запуск готовых мультишаговых агентов в облаке Nomad.
Главное из мира ИИ — раз в неделю
7 ключевых событий недели, отобранных вручную. Без шума, репостов и пресс-релизов.
Готово! Проверьте почту — мы отправили подтверждение.