1. Что такое инцидент в мире ChatGPT Apps
В классическом вебе инцидент — это обычно что-то вроде «сервер лежит», «ошибок 500 стало сильно больше», «latency выросла в два раза». Формальное определение из ITIL: инцидент — незапланированное прерывание сервиса или ухудшение качества сервиса.
В мире ChatGPT Apps и GiftGenius картина сложнее. У нас появляется слой моделей, которые могут:
- не вызвать нужный tool, хотя всё доступно;
- вызвать tool с неправильными параметрами;
- «галлюцинировать» результат, игнорируя ваш MCP.
Поэтому инцидентом может быть не только HTTP 500, но и ситуация, когда все backend‑метрики зелёные, а пользователи массово жалуются: «бот тупит и не показывает подарки» — потому что модель перестала звать suggest_gifts или путает аргументы. Это инцидент качества (Quality incident).
Удобно мыслить инциденты по категориям:
| Категория | Пример симптома | Пример метрики (SLI) |
|---|---|---|
| Availability | MCP не отвечает, «Error talking to app» в ChatGPT | % успешных ответов /mcp |
| Latency | подбор подарков занимает 10+ секунд | p95 времени вызова suggest_gifts |
| Quality | модель не вызывает нужный tool, путает валюту | доля запросов без tool-call при явном запросе |
| Commerce | checkout перестал проходить, деньги не двигаются | checkout_success_rate |
Инцидент — это момент, когда фактическая метрика выходит за пределы заранее договорённого SLO. Например:
- мы договорились: p95 подбора подарков < 4 секунд. Стало 9 секунд;
- мы хотим, чтобы 99% checkout’ов в неделю были успешны, а стало 94%;
- мы ожидаем, что в сценариях с покупкой модель почти всегда вызывает create_checkout_session, а по логам видим резкий рост «пропусков».
Важно: инцидент — это не «кто‑то в чате пожаловался». Жалоба — это триггер, а решение «да, это инцидент» мы принимаем, опираясь на SLO/SLI и дашборды.
2. Как SLO/SLI превращаются в инциденты
В модуле про observability вы уже задавали ключевые метрики: latency, availability, error-rate, 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 latency;
- аномальному падению количества workflow_completed (люди не доходят до конца сценария);
- аномальному росту LLM‑стоимости без роста трафика (экономический инцидент).
Всё это возможно только потому, что мы логируем структурированно, а не пишем в логи «что‑то с checkout опять не так». Когда метрики и алерты настроены, мы научились замечать, что что‑то пошло не так. Следующий вопрос: что происходит после детекции, кто и как реагирует?
3. Жизненный цикл инцидента: от детекции до постмортема
Чтоб не жить в режиме вечного пожара, удобно описывать стандартный pipeline инцидента. Многие 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 минут;
- алерт по latency: p95(suggest_gifts) > 10 сек;
- аномалия по cost: «LLM‑затраты выросли в 2 раза при том же количестве workflow_completed».
Ручная детекция — когда в поддержку (или вам лично в Telegram) приходит шквал сообщений «оплата не проходит», «виджет крутится бесконечно». Иногда именно это подсвечивает проблему до того, как мониторинг догнал.
Практический вывод: даже если у вас ещё нет идеального мониторинга, привыкайте на любые массовые жалобы пользователей смотреть через призму метрик: «какая метрика за этим стоит и как её померить?».
Triage — классификация и приоритизация
После детекции надо ответить на два вопроса: насколько всё плохо и кто побежит чинить.
Удобно иметь простую шкалу серьёзности:
- SEV-1: критично — пользователи не могут покупать, App не работает по ключевому сценарию (например, checkout=0 при живом трафике).
- SEV-2: серьёзно, но с деградацией — часть пользователей не может завершить сценарий, latency сильно выросла, но не до нуля.
- SEV-3: минорные баги — один из дополнительных tools иногда падает, ломается только edge‑кейс.
Для GiftGenius commerce‑инциденты почти всегда 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 или сменившаяся модель, которая перестала вызывать tool.
Resolution обычно включает:
- фикс (patch/rollback/конфиг);
- деплой на staging, затем на production;
- проверку всех SLI/SLO;
- обратный перевод флагов в нормальное состояние.
Post-mortem — учимся на ошибках
После инцидента, особенно SEV‑1/SEV‑2, проводится постмортем: документ, где вы честно отвечаете на вопросы:
- что произошло (в фактах и таймлайне);
- как это заметили;
- как реагировали;
- что сработало хорошо, а что нет;
- какие изменения вы сделаете, чтобы это не повторялось.
Постмортем не про поиск виноватых, а про улучшение системы и процесса. На его основе обновляют runbook’и, алерты, иногда даже архитектуру.
4. Роли и ответственность: даже если вы «один в поле»
Чтобы описанный выше pipeline инцидента работал в реальной жизни, важно заранее договориться, кто именно за какие решения отвечает во время пожара. Даже если вашу команду можно собрать в одном лифте, имеет смысл формализовать роли при инцидентах. Это снижает хаос.
Обычно выделяют:
- On-call инженер — тот, кому первым прилетает алерт и кто принимает технические решения по стабилизации (rollback, feature‑flags, временные заглушки).
- Incident commander — человек, который ведёт процесс: фиксирует таймлайн, принимает решения о приоритете задач, следит, чтобы команда не металась. В микрокоманде это тот же on-call, но с другой «шляпой».
- Коммуникация — отвечает за связь с пользователями и бизнес‑стейкхолдерами: сообщения в Slack, на статус‑странице, в интерфейсе App (виджет/чат), в магазине 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, показать баннер в виджете, собрать логи для постмортема.
Пример текста для виджета при commerce‑инциденте
В 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, это явный сигнал Availability‑инцидента (MCP не жив).
Классификация инцидента по метрикам
На стороне аналитического сервиса или админского backend‑скрипта можно держать простую логику определения серьезности:
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; // пока не инцидент
}
Такой кусок можно запускать по крону или триггерить от мониторинга: при возврате 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: latency, error-rate, checkout‑успех, долю инцидентов по категориям;
- смотреть, были ли за неделю алерты, которые «заглохли сами», и решать, стоит ли усилить/ослабить пороги;
- кратко разбирать хотя бы один инцидент (даже SEV‑3) — это тренирует мышцу постмортема.
Ежемесячно
Раз в месяц хорошо бы:
- делать обзор затрат (LLM, ACP/Stripe комиссии, инфраструктура) и сопоставлять их с выручкой — связка с темами 1–2 модуля 19;
- смотреть продуктовые метрики: activation, retention, конверсия workflow_completed → checkout_success — связка с модулем о маркетинге и росте;
- пробегать по security‑логам на предмет аномалий: странные паттерны логина, ошибки авторизации, необычные всплески запросов (мост к модулю о безопасности).
Ежеквартально
Раз в квартал вы:
- ротируете секреты: API‑ключи OpenAI, Stripe, OAuth‑клиенты и т.д.;
- проверяете, не устарели ли SLO: может, App вырос, и теперь p95 в 2 секунды вместо 1 — это норма, или наоборот, вы можете ужесточить цели;
- пересматриваете runbook’и: новые типы инцидентов, обновившиеся зависимости (SDK, MCP‑spec и т.п.).
Календарь можно вести просто в виде Wiki‑страницы или README в репозитории GiftGenius: важно, чтобы он был «живым» и обновлялся.
8. Инциденты, деньги и продукт: почему commerce-пожар — самый горячий
Модуль 19 в целом про экономику и «операционную жизнь» App, и инциденты здесь плотно связаны с деньгами. Commerce‑инциденты — когда checkout не проходит, деньги блокируются или списываются дважды — почти всегда стоят выше по приоритету, чем, скажем, случайный таймаут при поиске подарков.
Причины просты:
- прямые потери выручки в текущий момент;
- риск потери доверия (пользователь, которому списали деньги и не дали товар, вряд ли вернётся);
- потенциальные юридические и репутационные последствия.
Поэтому в вашем incident‑каталоге GiftGenius commerce‑инциденты должны быть явно отмечены как SEV‑1 с жёсткими SLO по времени реакции (например, «реакция on-call в течение 15 минут, mitigation в течение часа»).
Экономические аномалии (например, cost на LLM резко вырос без роста выручки) — это тоже инциденты, но, как правило, уровня SEV‑2: они не ломают UX немедленно, но могут «съесть» всю маржу, если не заметить.
С продуктовой стороны любой крупный инцидент — это повод подумать:
- не слишком ли сложен workflow (может, проще — значит надёжнее);
- не стоит ли добавить fallback‑сценарий: например, если MCP не отвечает, модель хотя бы отдаёт советы без внешних данных;
- не нужно ли изменить UX, чтобы честно сообщать о проблемах, а не скрывать их.
9. Мини‑упражнения (для самостоятельной работы)
Хотя лекция — не практикум, очень рекомендую реально проделать следующие шаги на своём GiftGenius:
- Описать в одном документе хотя бы два runbook’а:
- «Массовые ошибки при оплате (checkout)»;
- «MCP не отвечает / ChatGPT показывает Error talking to app».
- Составить операционный календарь на месяц:
- какие SLO вы будете смотреть каждую неделю;
- какой cost‑обзор сделаете в конце месяца;
- какие security‑проверки включите (хотя бы базовые).
Это займёт пару часов, но очень сильно изменит то, как вы смотрите на своё приложение: оно перестанет быть просто кодом и станет живым сервисом.
Типичные ошибки в инцидент-менеджменте ChatGPT Apps
Ошибка №1: «Инцидент — это только когда всё упало»
Многие по привычке считают инцидентом лишь полное падение MCP или базы. В AI‑Apps часто более болезненны «мягкие» инциденты качества: модель перестала вызывать нужный tool, checkout‑флоу стал путаным, пользователи не доходят до конца, хотя HTTP‑метрики зелёные. Если вы не считаете такие ситуации инцидентами и не разбираете их, качество App будет деградировать незаметно.
Ошибка №2: Отсутствие чётких SLO и границ «нормальной работы»
Без формальных SLO любой спор об инциденте превращается в «мне кажется, что всё медленно» vs «у меня на локалке быстро». Именно поэтому SLO считаются базой для инцидент‑менеджмента: они делают серьёзность проблемы объективной.
Ошибка №3: Импровизация вместо runbook’ов
Распространённая картина: алерт, все в панике прыгают в прод, кто-то откатывает релиз, кто-то правит конфиги, через час «кажется, починили», но никто не помнит, что именно помогло. Без runbook’ов каждый инцидент — мини‑хаос, и команда не учится. Даже один простой runbook по checkout‑инциденту сильно снижает уровень стресса.
Ошибка №4: Игнорирование коммуникации с пользователями
Иногда инженеры чинят систему в тишине, а пользователи в это время видят только «крутилку» и ошибку «что‑то пошло не так». Для commerce‑сценариев это особенно токсично: люди переживают за деньги. Важно заранее иметь шаблоны сообщений в виджете, в описании App и, при необходимости, внешних каналах, чтобы честно обозначать проблему и ожидаемое время исправления.
Ошибка №5: Обвинение «виноват OpenAI» без разбора своей части
Легко списать всё на «OpenAI тупит», но практика показывает, что даже при upstream‑проблемах можно много сделать на своей стороне: корректно обрабатывать таймауты и ошибки, переключаться на режим без MCP, уменьшать число повторных попыток, чтобы не усугублять ситуацию. Концепция shared responsibility подразумевает, что вы отвечаете за свою часть цепочки, даже если один из провайдеров ведёт себя нестабильно.
Ошибка №6: Нет постмортемов и операционного цикла
Если инцидент заканчивается фразой «ну, вроде всё, поехали дальше», а никакие документы, алерты и код не меняются — система обречена повторять те же ошибки. Постмортемы, регулярные обзоры SLO, затрат и безопасности — это не бюрократия, а способ договариваться с будущим собой и своей командой, чтобы через год GiftGenius был надёжнее, а не хрупче.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ