Когда наш ИИ-провайдер отключил модель
Смена модели, пустые ответы без ошибок и счёт, который внезапно вырос в несколько раз. Что сломалось и почему причину было так трудно увидеть.

В июле 2026 года сразу несколько функций перестали работать: ИИ-чат, ИИ-ответы в тикетах, сводки тикетов, конструктор серверов, а также модерация и перевод идей и баг-репортов.
Причина была не в нашем коде. Наш ИИ-провайдер отключил модель, которой мы пользовались.
Часть первая: модели больше нет
Это очевидная часть, и её быстро исправили. Провайдер снимает модель с поддержки, вписываешь преемника, готово.
Настоящий инцидент начался после этого.
Часть вторая: пустые ответы без ошибок
После замены ответы приходили. Только иногда они были пустыми. Не обрезанными, не испорченными, а полностью пустыми, без какой-либо ошибки.
Причина в различии, которое по названию модели не видно: преемник это модель с рассуждением. Перед самим ответом она сначала пишет внутренний ход мыслей в отдельное поле. Оба расходуют один и тот же бюджет токенов.
Если бюджет съедает рассуждение, возвращается формально корректный ответ: провайдер сообщает "достигнута длина", а поле содержимого пустое. Ни ошибки, ни подсказки, ничего, что увидел бы try/catch.
Мы воспроизвели это настоящим тестом: бюджета в пять токенов уже достаточно, чтобы каждый запрос давал пустой ответ.
Часть третья: счёт
В самом дорогом месте вызова, ИИ-конструкторе серверов, мы задали щедрый бюджет, потому что там генерируются длинные ответы. Поэтому рассуждение не упиралось в лимит, а просто шло дальше.
Последствия пришли с двух сторон сразу. Запросы длились так долго, что упирались в тайм-ауты. И стоили в несколько раз дороже, потому что каждый раз оплачивался целый невидимый ход мыслей. В конце пришло сообщение об ошибке, которое мы не планировали: недостаточно средств на балансе.
Исправление это одна строка. Рассуждение можно отключить в теле запроса, и модель снова ведёт себя как старая. С тех пор эта строка обязательна в каждом месте вызова, а их в репозитории больше нескольких.
Часть четвёртая: что мы нашли при уборке
Если всё равно трогаешь каждое место вызова ИИ, то и разглядываешь его. Так всплыла вторая тема, не связанная с инцидентом, но похожая по стоимости.
Провайдеры берут заметно меньше за промпт, начало которого остаётся неизменным и может быть обслужено из кэша. Разница между попаданием и промахом примерно тридцатикратная.
Эту скидку не получить флагом. Мы проверили это специально: поле в теле запроса, предназначенное для этого, не дало никакого эффекта, кэш и так работает автоматически. Единственный рычаг это порядок внутри промпта, от стабильного к изменчивому.
Четыре места, где мы сделали ровно наоборот:
Изменчивое значение внутри фиксированного блока инструкций. Проверка баг-репортов на дубликаты содержала название модуля в тексте инструкции. Из-за этого иначе идентичный блок получал отдельную строку кэша для каждого модуля. Значению место в переменной части, где оно и так меняется.
Новое перед стабильным. Та же проверка отправляла новый баг-репорт перед кандидатами для сравнения, которых бывает до пятидесяти. Из-за этого самый большой промпт API постоянно был полным промахом.
Данные пользователя в фиксированной части. Публичный ИИ-чат держал заметки об отдельном пользователе в блоке инструкций, то есть перед общей историей канала. Из-за этого у каждого пользователя в одном и том же канале было своё начало, и общая история оплачивалась отдельно для каждого.
Скользящее окно по истории. Если при каждом сообщении отправлять последние N сообщений, начало сдвигается при каждом сообщении. Вся история тогда постоянный промах. Правильный подход это обрезка блоками, то есть редко и сразу помногу.
Плюс одна деталь, которая выглядит как придирка, но ею не является: список внутри промпта, отсортированный только по одному критерию, при равенстве может менять порядок. Одна переставленная строка посреди блока инструкций стоит попадания для всего, что идёт после неё. Сортировкам внутри промптов нужен однозначный второй критерий.
Что мы из этого вынесли
Смена модели это не изменение конфигурации. Название выглядит как значение в переменной. За ним стояло другое поведение, и это поведение сломало наш код, а не интерфейс.
Опасным был тихий сбой. Исчезновение старой модели было видно сразу и исправлено за минуты. Пустые ответы приходили как формально корректные и могли бы оставаться такими сколько угодно.
Измеримость должна быть в месте вызова. Теперь мы логируем долю попаданий в кэш в каждом из них. Правильно построенное место после первого запроса выходит на высокую долю, неправильно построенное остаётся на нуле. Это видно в строке лога и больше нигде, потому что работают оба.
И неудобный вывод: использовать чужую модель значит, что часть твоего продукта зависит от решения, принятого где-то ещё. Поэтому с августа любой сервер может направить ИИ-функции на собственный эндпоинт, а не полагаться на наш.
Другие статьи
Как уследить за 4000 серверов Discord: Grafana, PostHog и что они нам показали
Цикл, который незаметно создавал половину нашего трафика, три миллиона бессмысленных запросов в день и атака, закончившаяся через минуту. Что видит наш мониторинг и чего он намеренно не видит.
За кулисамиЧему нас научил бот на 2000+ серверах Discord
Четыре вещи, которые на большом масштабе работают иначе, чем кажется, пока пишешь код.
За кулисамиПочему почти всё в AlphaCloud остаётся бесплатным
Большинство ботов Discord прячут свои самые полезные функции за подпиской. Мы намеренно так не делаем, и щедрости в этом меньше, чем кажется.