1. Що таке інцидент у світі ChatGPT Apps
У класичному вебі інцидент — це зазвичай щось на кшталт «сервер лежить», «помилок 500 стало значно більше», «затримка (latency) зросла вдвічі». Формальне визначення з ITIL таке: інцидент — це незаплановане переривання роботи сервісу або погіршення якості сервісу.
У світі ChatGPT Apps і GiftGenius картина складніша. Зʼявляється шар моделей, які можуть:
- не викликати потрібний інструмент (tool), хоча все доступно;
- викликати інструмент із неправильними параметрами;
- «галюцинувати» результат, ігноруючи ваш MCP.
Тому інцидентом може бути не лише HTTP 500, а й ситуація, коли всі бекенд-метрики зелені, а користувачі масово скаржаться: «бот гальмує й не показує подарунки». Причина може бути в тому, що модель перестала викликати suggest_gifts або плутає аргументи. Це інцидент якості (Quality incident).
Зручно мислити про інциденти за категоріями:
| Категорія | Приклад симптома | Приклад метрики (SLI) |
|---|---|---|
| Доступність (Availability) | MCP не відповідає, «Error talking to app» у ChatGPT | % успішних відповідей /mcp |
| Затримка (Latency) | підбір подарунків триває понад 10 с | p95 часу виклику suggest_gifts |
| Якість (Quality) | модель не викликає потрібний інструмент, плутає валюту | частка запитів без tool‑call за явного запиту |
| Комерція (Commerce) | checkout перестав проходити, платежі не обробляються | checkout_success_rate |
Інцидент — це момент, коли фактична метрика виходить за межі заздалегідь погодженого SLO. Наприклад:
- ми домовилися: p95 підбору подарунків < 4 с. Стало 9 с;
- ми хочемо, щоб 99 % checkout-ів за тиждень були успішні, а стало 94 %;
- ми очікуємо, що в сценаріях із покупкою модель майже завжди викликає create_checkout_session, а за логами бачимо різке зростання «пропусків».
Важливо: інцидент — це не «хтось у чаті поскаржився». Скарга — лише триґер, а рішення «так, це інцидент» ми ухвалюємо, спираючись на SLO/SLI та дашборди.
2. Як SLO/SLI перетворюються на інциденти
У модулі про спостережуваність ви вже визначали ключові метрики: затримку, доступність, частку помилок, успішність checkout. Тепер використовуємо їх як «охоронців біля дверей».
Найпростіший сценарій: у нас є SLO для checkout_success_rate. Ми ведемо структуровані логи подій:
// Приклад лог-події checkout на MCP‑сервері
logger.info({
event: 'checkout_result',
request_id,
user_id,
checkout_session_id,
status: 'success', // або 'failed'
error_code: null,
});
На основі цих логів будується метрика: частка status = "success" серед усіх checkout_result за останні N хвилин чи годин. Коли ця частка опускається нижче порога (наприклад, 95 % за 10 хв), моніторинг надсилає алерт у канал on-call. Це і є виявлення інциденту: SLI вийшла за межі SLO.
Так само можуть спрацьовувати алерти за:
- зростанням error_rate інструментів suggest_gifts, search_products;
- зростанням p95/p99 затримки;
- аномальним падінням кількості workflow_completed (люди не доходять до кінця сценарію);
- аномальним зростанням вартості LLM без зростання трафіку (економічний інцидент).
Усе це можливо лише тому, що ми логуємо структуровано, а не пишемо в логи «з checkout знову щось не так». Коли метрики й алерти налаштовані, ми навчилися помічати, що щось пішло не так. Далі постає питання: що відбувається після виявлення та хто й як реагує?
3. Життєвий цикл інциденту: від виявлення до постмортему
Щоб не жити в режимі вічної пожежі, зручно описати стандартний конвеєр інциденту. Багато SRE‑команд формалізують його як ланцюжок:
flowchart TD
D["Detection (виявлення)"] --> T["Triage (оцінка серйозності)"]
T --> M["Mitigation (швидке пом’якшення)"]
M --> R["Resolution (остаточне виправлення)"]
R --> P["Post-mortem (розбір і поліпшення)"]
Розберімо етапи на прикладі GiftGenius.
Detection — як зрозуміти, що все погано
Виявлення проблеми може бути автоматичним або ручним.
Автоматичне — це алерти з моніторингу за SLO/SLI:
- PagerDuty, Opsgenie, електронна пошта або Slack‑бот кричить: SEV-1: checkout_success_rate < 60 % за 10 хв;
- алерт за затримкою: p95(suggest_gifts) > 10 с;
- аномалія за cost: «витрати на LLM зросли вдвічі за тієї самої кількості workflow_completed».
Ручне виявлення — це коли в підтримку (або вам особисто в месенджер) надходить шквал повідомлень на кшталт «оплата не проходить», «віджет крутиться без кінця». Інколи саме це сигналізує про проблему раніше, ніж моніторинг встигає підтягнути дані.
Практичний висновок: навіть якщо у вас ще немає ідеального моніторингу, звикайте дивитися на масові скарги користувачів крізь призму метрик. Запитання просте: «яка метрика за цим стоїть і як її виміряти?».
Triage — класифікація та пріоритизація
Після виявлення треба відповісти на два питання: наскільки все погано і хто має взятися це лагодити.
Зручно мати просту шкалу серйозності:
- SEV-1: критично — користувачі не можуть купувати, застосунок не працює за ключовим сценарієм (наприклад, checkout=0 за живого трафіку).
- SEV-2: серйозно, але з деградацією — частина користувачів не може завершити сценарій, затримка різко зросла, але не «в нуль».
- SEV-3: незначні баги — один із додаткових інструментів інколи падає, ламається лише граничний випадок.
Для GiftGenius комерційні інциденти майже завжди SEV-1: якщо платежі не проходять, це не лише технічна проблема, а й прямі втрати виручки та довіри.
На цьому ж кроці призначається on-call (або ви самі, якщо команда з однієї людини) й ухвалюється рішення: «Так, це офіційний інцидент SEV‑1. Працюємо за runbookʼом №N». (Runbook — це заздалегідь описана покрокова інструкція; структуру розберемо в окремому розділі.)
Mitigation — зупинити «кровотечу»
Mitigation — це не пошук кореневої причини, а швидкі дії, щоб користувачі страждали менше. Наприклад:
- відкат останнього релізу MCP/Agents/ACP;
- вимкнення проблемного фічпрапорця;
- переведення GiftGenius у режим перегляду: рекомендації показуємо, але не даємо оформляти покупку;
- тимчасове зниження навантаження (обмеження частоти запитів, rate limiting) або вимкнення «важких» інструментів.
Типовий приклад коду для «деградованого режиму» в нашому MCP:
// Псевдокод: глобальний прапорець, який можна швидко перемкнути
let checkoutDisabled = false;
export function setCheckoutDisabled(value: boolean) {
checkoutDisabled = value;
}
export async function createCheckoutSession(args: CheckoutArgs) {
if (checkoutDisabled) {
// Повідомляємо моделі, що покупка тимчасово недоступна
return {
error: 'checkout_temporarily_disabled',
message: 'Оплата тимчасово недоступна, покажи користувачеві пояснення.',
};
}
// звичайна логіка створення сесії
}
У системі фічпрапорців ви можете смикнути setCheckoutDisabled(true) як частину mitigation. Тоді користувачі принаймні не отримуватимуть 500‑ки та «завислі» платежі, а побачать чесне повідомлення.
Resolution — остаточне виправлення
Коли «кровотечу зупинено», у вас зʼявляється час знайти кореневу причину й виправити її:
- баг у коді MCP/ACP;
- проблема зі стороннім провайдером (Stripe, платіжний шлюз);
- ліміти на OpenAI API (429, перевантаження);
- зламаний prompt або змінена модель, яка перестала викликати інструмент.
Resolution зазвичай включає:
- виправлення (patch/rollback/config);
- деплой на staging, а потім на production;
- перевірку всіх SLI/SLO;
- повернення прапорців у нормальний стан.
Post‑mortem — вчимося на помилках
Після інциденту, особливо SEV‑1/SEV‑2, проводиться постмортем: документ, у якому ви чесно відповідаєте на питання:
- що сталося (факти й таймлайн);
- як це помітили;
- як реагували;
- що спрацювало добре, а що — ні;
- які зміни ви зробите, щоб це не повторювалося.
Постмортем — не про пошук винних, а про вдосконалення системи й процесу. На його основі оновлюють runbookʼи, алерти, інколи навіть архітектуру.
4. Ролі та відповідальність: навіть якщо ви «один у полі»
Щоб описаний вище конвеєр інциденту працював у реальному житті, важливо заздалегідь домовитися, хто саме за які рішення відповідає під час «пожежі». Навіть якщо вашу команду можна зібрати в одному ліфті, є сенс формалізувати ролі під час інцидентів. Це зменшує хаос.
Зазвичай виділяють:
- On-call інженер — той, кому першим прилітає алерт і хто ухвалює технічні рішення щодо стабілізації (rollback, feature‑flags, тимчасові заглушки).
- Incident commander — людина, яка веде процес: фіксує таймлайн, ухвалює рішення про пріоритети завдань, стежить, щоб команда не металася. У мікрокоманді це той самий on-call, але з іншою «шапкою».
- Комунікації — відповідає за звʼязок із користувачами та бізнес-стейкхолдерами: повідомлення у Slack, на сторінці статусу, в інтерфейсі застосунку (віджет/чат), у крамниці ChatGPT.
- Scribe — фіксує важливі кроки й факти; потім за цим конспектом пишеться постмортем.
У команді з однієї людини всі чотири ролі — це ви. Просто корисно свідомо перемикати режим: «зараз я інженер і лагоджу», «зараз я комунікую», «зараз я записую таймлайн».
5. Runbook: регламент замість памʼяті
Runbook — це документ, у якому покроково описано, що робити за конкретного типу інциденту: які графіки переглядати, які кнопки натискати, чим можна пожертвувати. Він істотно зменшує частку імпровізації та рівень стресу.
Структура runbookʼа
Зазвичай runbook містить:
- Короткий опис інциденту та те, як його виявляють. Приклад: «Зростання помилок ACP checkout > 5 % за 5 хв» або «Error talking to app для >20 % запитів».
- Scope — кого зачіпає проблема: весь трафік, лише регіон, лише конкретний tool.
- Де дивитися: посилання на дашборди (SLO за checkout, error‑rate MCP, логи за tool_name = create_checkout_session), на MCP Inspector тощо.
- Швидкі кроки mitigation: «перевірити статус Stripe», «відкотити останній реліз ACP», «увімкнути режим рекомендацій без покупки».
- Кроки для остаточного розбору та виправлення.
- Що потрібно оновити за підсумками: алерти, код, документацію.
Міні‑приклад runbookʼа для GiftGenius (checkout падає)
Опишімо його у вигляді структурованих даних, щоб було ближче до коду:
type Severity = 'SEV-1' | 'SEV-2' | 'SEV-3';
interface RunbookStep {
title: string;
description: string;
}
interface Runbook {
id: string;
title: string;
severity: Severity;
detection: string;
steps: RunbookStep[];
}
export const checkoutFailureRunbook: Runbook = {
id: 'rb-checkout-failure',
title: 'Зростання помилок checkout у GiftGenius',
severity: 'SEV-1',
detection: 'Алерт: checkout_success_rate < 60% за 10 хвилин',
steps: [
{
title: 'Перевірити зовнішні статуси',
description: 'Відкрити статус Stripe і ACP backend, переконатися, що немає глобального outage.',
},
{
title: 'Перевірити нещодавні релізи',
description: 'Перевірити, чи були деплої MCP/ACP за останні 30 хвилин. За потреби відкотити.',
},
],
};
У реальному runbookʼі ви додасте більше кроків: увімкнути фічпрапорець read‑only, показати банер у віджеті, зібрати логи для постмортему.
Приклад тексту для віджета під час комерційного інциденту
У runbook корисно заздалегідь продумати й текст для користувача. Наприклад, у GiftGenius віджет може показати:
«Зараз у нас тимчасові технічні проблеми з оплатою. Ви все одно можете зберегти вподобані ідеї подарунків, а покупку завершимо трохи згодом.»
Такий текст потім можна «зашити» в UI‑стан:
// Псевдокод стану віджету
const [checkoutAvailable, setCheckoutAvailable] = useState(true);
if (!checkoutAvailable) {
return (
<Alert>
Оплата тимчасово недоступна. Ви все ще можете переглядати й зберігати ідеї подарунків.
</Alert>
);
}
6. Практика на GiftGenius: код навколо інцидентів
Щоб тема не залишалася суто організаційною, подивімося на кілька фрагментів коду, які напряму допомагають у керуванні інцидентами.
Health‑check endpoint для MCP/Backend
Найпростіший, але важливий інструмент — health‑check. У Next.js 16 його можна зробити через route handler:
// app/api/health/route.ts
import { NextRequest, NextResponse } from 'next/server';
export function GET(_req: NextRequest) {
// Можна додати перевірки БД, черг тощо.
return NextResponse.json({
status: 'ok',
mcp: 'healthy',
timestamp: new Date().toISOString(),
});
}
Система моніторингу періодично опитуватиме /api/health. Якщо замість 200 OK підуть таймаути або 5xx, це явний сигнал інциденту доступності (MCP «не живий»).
Класифікація інциденту за метриками
На боці аналітичного сервісу або адміністративного бекенд-скрипта можна тримати просту логіку визначення серйозності:
type Severity = 'SEV-1' | 'SEV-2' | 'SEV-3';
interface IncidentContext {
checkoutSuccessRate: number; // 0..1
giftSearchErrorRate: number; // 0..1
p95GiftSearchMs: number;
}
export function classifyIncident(ctx: IncidentContext): Severity | null {
if (ctx.checkoutSuccessRate < 0.6) return 'SEV-1'; // гроші не ходять
if (ctx.giftSearchErrorRate > 0.3 || ctx.p95GiftSearchMs > 8000) return 'SEV-2';
return null; // поки не інцидент
}
Такий фрагмент можна запускати за cron або тригерити з моніторингу: якщо повертається SEV‑1, автоматично створюється інцидент у вашій системі та надсилається сповіщення on-call.
Логування ключових подій інциденту
Інциденти — це не тільки метрики, а й події: коли інцидент створено, змінено, закрито. Їх зручно тримати в окремих логах.
function logIncidentEvent(event: {
incidentId: string;
type: 'created' | 'mitigated' | 'resolved';
severity: Severity;
requestId?: string;
message: string;
}) {
logger.warn({
level: 'WARN',
service: 'incident-manager',
...event,
timestamp: new Date().toISOString(),
});
}
Наприклад, під час увімкнення режиму «read-only» для GiftGenius:
setCheckoutDisabled(true);
logIncidentEvent({
incidentId: 'inc-2025-11-21-001',
type: 'mitigated',
severity: 'SEV-1',
message: 'Checkout disabled, app switched to recommendations-only mode',
});
Потім ці події легко знайти та зіставити з часовими рядами метрик.
7. Операційний календар: життя після «ура, все полагодили»
Керування інцидентами — це не лише гасіння пожеж, а й регулярна профілактика. У SRE‑практиках операційний цикл часто описують як операційний календар із регулярними оглядами SLO, витрат і безпеки.
Умовно активності можна поділити за періодичністю.
Щотижня
Раз на тиждень (або раз на два) має сенс:
- переглядати основні SLO: затримку, частку помилок, успішність checkout, частку інцидентів за категоріями;
- дивитися, чи були за тиждень алерти, які «затихли самі», і вирішувати, чи варто посилити або послабити пороги;
- коротко розбирати бодай один інцидент (навіть SEV‑3) — це тренує «мʼяз» постмортему.
Щомісяця
Раз на місяць добре б:
- робити огляд витрат (LLM, ACP/Stripe комісії, інфраструктура) і зіставляти їх із виручкою — відсилання до тем 1–2 модуля 19;
- дивитися продуктові метрики: activation, retention, конверсію workflow_completed → checkout_success — відсилання до модуля про маркетинг і зростання;
- пробігтися security‑логами в пошуках аномалій: дивні патерни входу, помилки авторизації, незвичні сплески запитів (місток до модуля про безпеку).
Щокварталу
Раз на квартал ви:
- ротуєте секрети: API‑ключі OpenAI, Stripe, OAuth‑клієнти тощо;
- перевіряєте, чи не застаріли SLO: можливо, застосунок виріс, і тепер p95 у 2 с замість 1 с — це норма; або навпаки, ви можете посилити цілі;
- переглядаєте runbookʼи: нові типи інцидентів, оновлені залежності (SDK, MCP‑spec тощо).
Календар можна вести просто як wiki‑сторінку або README в репозиторії GiftGenius. Важливо, щоб він був «живим» і регулярно оновлювався.
8. Інциденти, гроші й продукт: чому комерційна «пожежа» — найгарячіша
Модуль 19 загалом — про економіку й «операційне життя» застосунку, а інциденти тут тісно повʼязані з грошима. Комерційні інциденти — коли checkout не проходить, гроші блокуються або списуються двічі — майже завжди мають вищий пріоритет, ніж, скажімо, випадковий таймаут під час пошуку подарунків.
Причини прості:
- прямі втрати виручки в поточний момент;
- ризик втрати довіри (користувач, у якого списали гроші й не видали товар, навряд чи повернеться);
- потенційні юридичні та репутаційні наслідки.
Тому у вашому каталозі інцидентів GiftGenius комерційні інциденти мають бути явно позначені як SEV‑1 із жорсткими SLO за часом реакції (наприклад, «реакція on-call протягом 15 хв, mitigation протягом години»).
Економічні аномалії (наприклад, вартість LLM різко зросла без зростання виручки) — це теж інциденти, але зазвичай рівня SEV‑2. Вони не ламають UX негайно, проте можуть «зʼїсти» всю маржу, якщо вчасно їх не помітити.
З продуктової сторони будь-який великий інцидент — це привід подумати:
- чи не надто складний workflow (інколи простіше означає надійніше);
- чи не варто додати fallback‑сценарій: наприклад, якщо MCP не відповідає, модель хоча б дає поради без зовнішніх даних;
- чи не потрібно змінити UX, щоб чесно повідомляти про проблеми, а не приховувати їх.
9. Міні‑вправи (для самостійної роботи)
Хоча лекція — не практикум, дуже рекомендую реально виконати такі кроки на своєму GiftGenius:
- Описати в одному документі щонайменше два runbookʼи:
- «Масові помилки під час оплати (checkout)»;
- «MCP не відповідає / ChatGPT показує Error talking to app».
- Скласти операційний календар на місяць:
- які SLO ви переглядатимете щотижня;
- який огляд витрат зробите наприкінці місяця;
- які security‑перевірки додасте (принаймні базові).
Це займе кілька годин, але дуже змінить те, як ви дивитеся на свій застосунок: він перестане бути просто кодом і стане живим сервісом.
Типові помилки в керуванні інцидентами в ChatGPT Apps
Помилка №1: «Інцидент — це тільки коли все впало»
Багато хто за звичкою вважає інцидентом лише повне падіння MCP або бази. В AI‑застосунках часто болючіші «мʼякі» інциденти якості: модель перестала викликати потрібний інструмент, checkout‑флоу став заплутаним, користувачі не доходять до кінця, хоча HTTP‑метрики зелені. Якщо ви не вважаєте такі ситуації інцидентами й не розбираєте їх, якість застосунку непомітно деградуватиме.
Помилка №2: Відсутність чітких SLO і меж «нормальної роботи»
Без формальних SLO будь-яка суперечка про інцидент перетворюється на «мені здається, що все повільно» проти «у мене локально швидко». Саме тому SLO вважаються базою для керування інцидентами: вони роблять серйозність проблеми обʼєктивною.
Помилка №3: Імпровізація замість runbookʼів
Поширена картина: алерт, усі в паніці кидаються в продакшн, хтось відкатує реліз, хтось править конфіги. За годину «здається, полагодили», але ніхто не памʼятає, що саме допомогло. Без runbookʼів кожен інцидент — це мініхаос, і команда не вчиться. Навіть один простий runbook щодо checkout‑інциденту істотно знижує рівень стресу.
Помилка №4: Ігнорування комунікації з користувачами
Інколи інженери лагодять систему в тиші, а користувачі в цей час бачать лише «індикатор завантаження» і помилку «щось пішло не так». Для комерційних сценаріїв це особливо токсично: люди переживають за гроші. Важливо заздалегідь мати шаблони повідомлень у віджеті, в описі застосунку і, за потреби, у зовнішніх каналах, щоб чесно позначати проблему й очікуваний час виправлення.
Помилка №5: Звинувачення «винен OpenAI» без розбору своєї частини
Легко все списати на «OpenAI гальмує», але практика показує: навіть за upstream‑проблем можна багато зробити на своєму боці. Наприклад, коректно обробляти таймаути й помилки, перемикатися на режим без MCP, зменшувати кількість повторних спроб, щоб не погіршувати ситуацію. Концепція shared responsibility передбачає, що ви відповідаєте за свою частину ланцюжка, навіть якщо один із провайдерів поводиться нестабільно.
Помилка №6: Немає постмортемів і операційного циклу
Якщо інцидент закінчується фразою «ну, наче все, рухаємося далі», а жодні документи, алерти та код не змінюються — система приречена повторювати ті самі помилки. Постмортеми, регулярні огляди SLO, витрат і безпеки — це не бюрократія, а спосіб домовлятися з майбутнім собою та своєю командою, щоб за рік GiftGenius був надійнішим, а не крихкішим.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ