Коли наш ШІ-провайдер вимкнув модель
Заміна моделі, порожні відповіді без помилки й рахунок, що раптом виріс у кілька разів. Що зламалося і чому причину було так важко побачити.

У липні 2026 року кілька функцій перестали працювати одночасно: ШІ-чат, ШІ-відповіді в тікетах, підсумки тікетів, конструктор серверів, а також модерація й переклад ідей і звітів про баги.
Причиною був не наш код. Наш ШІ-провайдер вимкнув модель, якою ми користувалися.
Частина перша: моделі більше немає
Це очевидна частина, і її виправили швидко. Провайдер припиняє підтримку моделі, ти вказуєш наступницю, готово.
Справжній інцидент почався потім.
Частина друга: порожні відповіді, без помилок
Після заміни відповіді надходили. Лише іноді вони були порожніми. Не обрізаними, не пошкодженими, а повністю порожньою відповіддю без жодної помилки.
Причина в різниці, яку назва моделі не розкриває: наступниця є моделлю міркувань. Перед власне відповіддю вона спершу записує внутрішній хід думок в окреме поле. Обидва беруть із того самого бюджету токенів.
Якщо бюджет вичерпано міркуваннями, повертається формально коректна відповідь: провайдер повідомляє «досягнуто довжини», а поле вмісту порожнє. Жодної помилки, жодної підказки, нічого, що побачив би try/catch.
Ми відтворили це справжнім тестом: бюджету в п'ять токенів уже достатньо, щоб отримувати порожню відповідь на кожен запит.
Частина третя: рахунок
У найдорожчому місці виклику, ШІ-конструкторі серверів, ми встановили щедрий бюджет, бо там створюються довгі відповіді. Тож міркування не впиралися в ліміт, вони просто тривали.
Наслідки прийшли з двох боків одночасно. Запити тривали так довго, що впиралися в тайм-аути. І вони коштували в кілька разів більше, бо щоразу оплачувався повний невидимий хід думок. Наприкінці прийшло повідомлення про помилку, якого ми не планували: недостатньо коштів на балансі.
Виправлення це один рядок. Міркування можна вимкнути в тілі запиту, і тоді модель знову поводиться як стара. Відтоді цей рядок належить до кожного місця виклику, а в репозиторії їх більше ніж кілька.
Частина четверта: що ми знайшли під час прибирання
Якщо ти вже торкаєшся кожного місця виклику ШІ, ти на них дивишся. Так виринула друга тема, не пов'язана з інцидентом, але так само дорога.
Провайдери беруть значно менше за промпт, початок якого залишається незмінним і може бути відданий із кешу. Різниця між влученням і промахом приблизно тридцятикратна.
Цю знижку не отримаєш через прапорець. Ми перевірили це окремо: поле в тілі запиту, призначене для цього, мало нульовий ефект, кеш і так застосовується автоматично. Єдиний важіль це порядок усередині промпту, від стабільного до мінливого.
Чотири місця, де ми зробили точнісінько навпаки:
Мінливе значення всередині фіксованого блоку інструкцій. Перевірка дублікатів для звітів про баги мала назву модуля в тексті інструкції. Це давало в іншому ідентичному блоку власний рядок кешу для кожного модуля. Значення належить до змінної частини, де воно й так змінюється.
Нове перед стабільним. Та сама перевірка надсилала новий звіт про баг перед до п'ятдесяти кандидатами для порівняння. Через це найбільший промпт API був постійним повним промахом.
Дані окремого користувача у фіксованій частині. Публічний ШІ-чат мав нотатки про окремого користувача в блоці інструкцій, тобто перед спільною історією каналу. Це давало кожному користувачеві в тому самому каналі власний початок, і спільна історія оплачувалася окремо для кожного користувача.
Ковзне вікно над історією. Якщо з кожним повідомленням надсилати останні N повідомлень, початок зсувається з кожним повідомленням. Тоді вся історія є постійним промахом. Правильний підхід це обрізання блоками, тобто рідко й суттєво.
Плюс одна деталь, що виглядає як прискіпливість, але нею не є: список у промпті, відсортований лише за одним критерієм, може змінювати свій порядок за рівних значень. Один переставлений рядок посеред блоку інструкцій коштує влучання для всього, що за ним. Сортуванням усередині промптів потрібен однозначний додатковий критерій.
Що ми з цього винесли
Заміна моделі не є зміною конфігурації. Назва виглядає як значення в змінній. За нею стояла інша поведінка, і ця поведінка зламала наш код, а не інтерфейс.
Небезпечним збоєм був тихий. Зникнення старої моделі було видно одразу, і його виправили за кілька хвилин. Порожні відповіді поверталися як формально коректні відповіді й могли б залишатися такими нескінченно.
Вимірюваність належить до місця виклику. Тепер ми записуємо частку влучань у кеш у кожному з них. Правильно побудоване місце після першого запиту виходить на високу частку, погано побудоване залишається на нулі. Це видно в рядку журналу й ніде більше, бо обидва працюють.
І незручний висновок: користуватися чужою моделлю означає, що частина твого продукту залежить від рішення, ухваленого деінде. Тому з серпня будь-який сервер може спрямувати ШІ-функції на власний ендпоінт замість того, щоб покладатися на наш.
Інші статті
Як ми стежимо за 4000 серверами Discord: Grafana, PostHog і що вони нам показали
Цикл, який непомітно створював половину нашого трафіку, три мільйони марних запитів на день і атака, що закінчилася за хвилину. Що бачить наш моніторинг і чого він свідомо не бачить.
За лаштункамиЧого нас навчила робота бота на понад 2000 серверах Discord
Чотири речі, які за великих масштабів працюють інакше, ніж ти припускаєш, коли пишеш код.
За лаштункамиЧому майже все в AlphaCloud залишається безкоштовним
Більшість ботів Discord ховають свої найкорисніші функції за підпискою. Ми свідомо цього не робимо, і це має менше спільного зі щедрістю, ніж здається.