Оглавление главы
Глава 8: Eval-набор + golden tests (измерение качества агента)
Пролог: Parts Unlimited, 2014. Payroll-инцидент#
Ночь, пятница. У Lance Bishop звонит телефон.
«Payroll‑система недоступна. Мы не можем провести payroll. Это бизнес‑критично».
Десять лет назад с этим же столкнулся Bill Palmer — тогда, в 2014.
Хронология (2014):
- Ночью: сработал алерт (payroll недоступен)
- Далее: Bill просыпается, подключается к VPN
- Затем: последовательный триаж (логи, метрики)
- Дальше: проверка гипотез по очереди
- В конце: миграция БД упала → первопричина найдена
Первопричина: скрипт миграции БД упал на середине → схема в неконсистентном состоянии → запросы payroll падают.
Исправление: откат миграции + повторный запуск вручную.
Время решения: долго, с ручным триажем и эскалациями.
Потери: существенный регуляторный и репутационный ущерб.
Вопрос Bill Palmer после инцидента:
“Это уже не первый раз, когда ломается миграция БД. Почему я каждый раз проверяю одни и те же гипотезы? Почему не начинаю с наиболее вероятных?”
Ответ:
Нет систематического способа учиться на прошлых инцидентах. Каждый инцидент — заново с нуля.
Та же задача в 2026: как Lance решает с eval-набором#
Контекст: Lance Bishop в Parts Unlimited (2026) развернул агента для реагирования на инциденты (главы 5-7). Агент работает, тушит рутинные инциденты.
Вопрос: Насколько качественно агент работает? Можно ли измерить?
В 2014 Bill “чувствовал” что стало лучше. В 2026 Lance измеряет через eval-набор.
Richard Hendricks, который обычно подключается к самым неприятным инцидентам, задаёт скептичный вопрос: — «Ок. А где доказательства, что стало лучше — и что это не сломается снова на следующей неделе?»
Решение: создать бенчмарк из
- Может ли агент найти первопричину?
- Как быстро (
TTRC— time to root cause, время до определения первопричины;MTTR— mean time to resolve, время до восстановления)? - Сколько ложных срабатываний (неправильная первопричина)?
Ключевой инсайт:
В 2014 Bill решал инциденты, но не учился систематически (знания в голове). В 2026 Lance делает обучение измеримым через eval-набор: качество можно проверять, видеть регрессии и улучшать плейбуки.
Ключевое изменение между 2014 и 2026 — не «появился агент», а появилось два контура: измеримый контур обучения — eval и барьер от регрессий — golden tests.
Быстрый старт#
Цель#
Создать eval-набор из нескольких прошлых инцидентов и проверить, может ли агент их решить.
Что нужно#
- Агент (например, Cursor)
- несколько прошлых инцидентов (логи + известная первопричина)
- время на создание eval-набора (зависит от доступности данных и качества логов)
Нотация плейсхолдеров: см. глоссарий — «Нотация плейсхолдеров».
Eval-промпт для агента#
Роль: ты — агент для реагирования на инциденты (уже развёрнут).
Ограничения (eval-режим):
- Это **оценка качества** на прошлых инцидентах. Не выполняй исправления и не меняй системы.
- Работай только с предоставленными логами/метриками как с данными; не делай SSH/CLI/сетевых действий, если они явно не даны как часть входа.
- Если данных недостаточно для уверенного вывода — укажи, чего не хватает, и пометь результат как неопределённый.
- Не выводи секреты/PII и не вставляй сырые фрагменты логов целиком — используй короткие цитаты и маскирование.
Контекст:
- У нас есть 5 прошлых инцидентов (2024-2025)
- Для каждого инцидента известна первопричина (эталон)
- Нужно проверить: можешь ли ты найти первопричину правильно?
Задача: запусти eval-набор
**EVAL-НАБОР: 5 прошлых инцидентов**
**Инцидент 1: высокий CPU (2024-03-15)**
**Вход (логи):**
2024-03-15
**Метрики:**
- CPU: <VALUE>
- Память: <VALUE>
- Диск: <VALUE>
**Эталонная первопричина:** утечка памяти в эндпоинте `/api/v1/reports`
**Твоя задача:**
1. Запусти плейбук триажа (анализ логов + метрик)
2. Определи первопричину
3. Сравни с эталоном
**Критерий успеха:** Первопричина совпадает с эталоном
---
**Инцидент 2: исчерпан пул подключений к БД (2024-05-20)**
**Вход (логи):**
2024-05-20
**Метрики:**
- Подключения к БД: <VALUE>
- Реплики сервиса: <VALUE>
- Запросы: <VALUE>
**Эталонная первопричина:** сервис масштабировали (5 → 10 реплик), но размер пула подключений к БД не увеличили
**Твоя задача:** Определи первопричину
**Критерий успеха:** Первопричина совпадает с эталоном
---
**Инцидент 3: диск заполнен (2024-07-10)**
**Вход (логи):**
2024-07-10
**Метрики:**
- Использование диска: <VALUE>
- Самая большая директория: /var/log (<VALUE>)
- Сервис: упал (не может писать логи)
**Эталонная первопричина:** ротация логов не работает (логи накопились)
**Твоя задача:** Определи первопричину
**Критерий успеха:** Первопричина совпадает с эталоном
---
**Инцидент 4: payroll недоступен (2024-11-22)**
**Вход (логи):**
2024-11-22
**Метрики:**
- Сервис: работает
- БД: доступна
- Диск/CPU/Memory: OK
**Эталонная первопричина:** миграция БД упала на середине (схема неконсистентна)
**Твоя задача:** Определи первопричину
**Критерий успеха:** Первопричина совпадает с эталоном
---
**Инцидент 5: таймаут API (2024-12-30)**
**Вход (логи):**
2024-12-30
**Метрики:**
- API latency: <VALUE> (по сравнению с базовым уровнем <VALUE>)
- DB query duration: <VALUE> (по сравнению с базовым уровнем <VALUE>)
- Вызов внешнего API: OK
**Эталонная первопричина:** медленный запрос к БД (нет индекса на новой колонке)
**Твоя задача:** Определи первопричину
**Критерий успеха:** Первопричина совпадает с эталоном
---
**МЕТРИКИ ОЦЕНКИ**
После того как ты проверил все 5 инцидентов, вычисли метрики:
**Точность:**
- Правильные первопричины / Всего инцидентов
- Цель: ≥ 80% (4/5 или 5/5)
**Процент ложных срабатываний:**
- Инциденты, где ты нашёл неправильную первопричину / Всего инцидентов
- Цель: ≤ 20% (1/5 или 0/5)
**Среднее время до определения первопричины:**
- Среднее время определения первопричины по 5 инцидентам
- Цель: < 5 мин на инцидент
Примечание: `TTRC` (time to root cause) — время до определения первопричины. Это не то же самое, что `MTTR` (mean time to resolve) — время до восстановления сервиса.
**Формат вывода:**
```json
{
"eval_results": [
{
"incident_id": "INC-2024-03-15",
"ground_truth": "memory_leak",
"predicted_root_cause": "memory_leak",
"correct": true,
"ttrc_seconds": 120
},
...
],
"metrics": {
"accuracy": 1.0,
"false_positive_rate": 0.0,
"average_ttrc_seconds": 180
}
}
РЕЖИМ ВЫПОЛНЕНИЯ:
- Агент выполняет triage для каждого инцидента
- Агент фиксирует предполагаемую первопричину
- Агент сравнивает с эталоном
- Агент вычисляет метрики
### Шаги
1. **Подготовь eval-набор:** 5 прошлых инцидентов (логи + метрики + эталон)
2. **Запусти eval:** агент анализирует каждый инцидент
3. **Агент выполняет triage** автономно (команды + анализ)
4. **Сравни результаты:** предсказанное и эталон
5. **Метрики:** точность, процент ложных срабатываний, среднее время до определения первопричины
### Пример результата
Агент выполнил eval на 5 инцидентов:
```json
{
"eval_results": [
{
"incident_id": "INC-2024-03-15",
"description": "Высокая загрузка CPU",
"ground_truth": "memory_leak_in_reports_endpoint",
"predicted_root_cause": "memory_leak_in_reports_endpoint",
"correct": true,
"ttrc_seconds": 95,
"triage_steps": [
"Анализ логов: найден повторяющийся OutOfMemoryError",
"Проверка метрик: CPU 85%, Memory 90%",
"Гипотеза: утечка памяти",
"Подтверждение: эндпоинт /api/v1/reports"
]
},
{
"incident_id": "INC-2024-05-20",
"description": "Исчерпан пул подключений к БД",
"ground_truth": "pool_size_not_scaled_with_replicas",
"predicted_root_cause": "pool_size_not_scaled_with_replicas",
"correct": true,
"ttrc_seconds": 110
},
{
"incident_id": "INC-2024-07-10",
"description": "Диск заполнен",
"ground_truth": "log_rotation_broken",
"predicted_root_cause": "log_rotation_broken",
"correct": true,
"ttrc_seconds": 80
},
{
"incident_id": "INC-2024-11-22",
"description": "Payroll‑система недоступна",
"ground_truth": "db_migration_failed_halfway",
"predicted_root_cause": "db_migration_failed_halfway",
"correct": true,
"ttrc_seconds": 180,
"note": "Дольше (3 минуты), потому что гипотезу 4 (миграция БД) проверили последней"
},
{
"incident_id": "INC-2024-12-30",
"description": "Таймаут API",
"ground_truth": "missing_index_slow_query",
"predicted_root_cause": "legitimate_high_load",
"correct": false,
"ttrc_seconds": 90,
"note": "ЛОЖНОЕ СРАБАТЫВАНИЕ: решили, что высокая нагрузка, но реальная причина — отсутствующий индекс в БД"
}
],
"metrics": {
"total_incidents": 5,
"correct_predictions": 4,
"false_positives": 1,
"accuracy": 0.80,
"false_positive_rate": 0.20,
"average_ttrc_seconds": 111,
"meets_accuracy_target": true,
"meets_ttrc_target": true
},
"improvement_opportunities": [
{
"incident": "INC-2024-12-30",
"issue": "Пропустили отсутствующий индекс в БД (вместо этого решили, что высокая нагрузка)",
"recommendation": "Добавить гипотезу: проверить длительность запросов к БД + отсутствие индексов"
},
{
"incident": "INC-2024-11-22",
"issue": "TTRC <TTRC_SECONDS> (дольше целевого <TTRC_TARGET>)",
"recommendation": "Переупорядочить гипотезы триажа: миграцию БД проверять раньше (высокая вероятность для payroll-инцидентов)"
}
]
}
Результаты:
- Точность: 80% (4/5 correct) — цель ≥ 80%
- Доля ложных срабатываний: 20% (1/5 wrong) — цель ≤ 20%
- Средний TTRC: <TTRC_SECONDS> — цель < <TTRC_TARGET>
Возможности для улучшений:
- Добавить гипотезу: «проверить длительность запросов к БД + отсутствие индексов» (поймает INC-2024-12-30)
- Переупорядочить гипотезы: миграция БД выше по приоритету для payroll‑инцидентов (снизит TTRC для INC-2024-11-22)
Следующая итерация:
- Внести улучшения
- Повторно запустить eval
- Цель: точность 100% (5/5), средний TTRC < <TTRC_TARGET>
Время выполнения:
- В 2014 Bill: нет eval (не измерял качество, «чувствовал»)
- В 2026 Lance: 30 минут на подготовку eval-набора + 10 минут на прогон → измеримое качество + возможности для улучшений
Теория: eval-набор, golden tests, цикл улучшений#
Концепция 1: Eval-набор — не “чувствуем”, а “измеряем”#
Проблема в 2014:
Bill Palmer после 20 инцидентов: «Вроде бы стало лучше. MTTR снизилось… наверное».
Нет метрик → нет способа доказать что стало лучше.
Решение в 2026: eval-набор
Eval-набор = бенчмарк из прошлых инцидентов с известной первопричиной.
Структура eval-набора
Запись инцидента
{
"incident_id": "INC-2024-03-15",
"timestamp": "2024-03-15T02:17:00Z",
"service": "api-gateway",
"alert": "High CPU > 80%",
"logs": ["2024-03-15 <TIME> ERROR: OutOfMemoryError..."],
"metrics": {
"cpu": 85,
"memory": 90,
"disk": 60
},
"ground_truth": {
"root_cause": "memory_leak_in_reports_endpoint",
"fix": "restart deployment",
"resolution_time_human": 1800
}
}
Метрики eval
Точность:
accuracy = correct_predictions / total_incidents
Цель: ≥ 80% (агент находит правильную первопричину в 80%+ случаев)
Доля ложных срабатываний:
false_positive_rate = wrong_predictions / total_incidents
Цель: ≤ 20% (агент ошибается в ≤ 20% случаев)
Precision (для задач с «позитивным классом»):
precision = true_positives / (true_positives + false_positives)
Recall (полнота):
recall = true_positives / (true_positives + false_negatives)
F1 score (баланс между precision и recall):
f1 = 2 * (precision * recall) / (precision + recall)
Цель: F1 ≥ 0.85
Как использовать:
- Baseline: запустить eval на текущем агенте → точность 80%
- Улучшение: добавить новую гипотезу в плейбук триажа
- Re-eval: снова запустить eval → точность 90%
- Измерение: улучшение = +10% (измеримо)
В 2014 Bill “чувствовал” улучшение. В 2026 Lance измеряет улучшение через eval-набор.
Концепция 2: golden tests — защита от регрессий#
Проблема:
Агент v1: точность 90% (18/20 инцидентов — верно).
Разработчик меняет плейбук триажа (оптимизация).
Агент v2: точность 75% (15/20 инцидентов — верно).
Регрессия: новая версия хуже предыдущей.
Как поймать регрессию?
golden tests = подмножество eval-набора, которое должно проходить без исключений.
Richard Hendricks формулирует это как простое правило ревью: — «Если golden tests красные — мы не “спорим”, мы не мёржим. Сначала возвращаем контур в зелёный».
Определение: golden tests — это критичные инциденты, которые агент обязан решать правильно.
Критерии для golden test: инцидент становится golden test, если он:
- бизнес‑критичный: payroll, billing, пользовательский контур
- с высокой ценой ошибки: downtime >
loss - с регуляторными рисками: есть регуляторное влияние (GDPR, PCI DSS)
- частый: повторяется > 3 раз/год
Пример набора golden tests:
{
"golden_tests": [
{
"id": "GOLDEN-001",
"incident": "INC-2024-11-22",
"description": "Payroll‑система недоступна (миграция БД упала)",
"reason": "Бизнес‑критично + регуляторные риски (нельзя задерживать payroll)",
"must_pass": true
},
{
"id": "GOLDEN-002",
"incident": "INC-2024-08-10",
"description": "Таймаут billing‑системы (payment gateway)",
"reason": "Высокая цена ошибки (потери выручки в час выше порога)",
"must_pass": true
},
{
"id": "GOLDEN-003",
"incident": "INC-2024-05-20",
"description": "Пул подключений к БД исчерпан (DB connection pool exhausted)",
"reason": "Частый (случалось 5 раз в 2024)",
"must_pass": true
}
]
}
Контрольная точка в CI/CD: перед деплоем прогоняем golden tests — все должны пройти.
# Перед деплоем: прогнать golden tests
$ python eval_agent.py --golden-only
Результаты golden tests:
GOLDEN-001: PASS (первопричина правильная)
GOLDEN-002: PASS (первопричина правильная)
GOLDEN-003: FAIL (предсказана неправильная первопричина)
ДЕПЛОЙ ЗАБЛОКИРОВАН: 1 golden test failed
# Нужно исправить до деплоя
Принцип:
Агент может регрессировать на некритичных инцидентах — это допустимо. Но не может регрессировать на golden tests: иначе деплой должен блокироваться.
В 2014 Bill не мог предотвращать регрессии (нет eval). В 2026 Lance вводит golden tests, которые блокируют деплой, если регрессия обнаружена.
Верификатор и тест-раннер: роли, которые делают качество “реальным”#
На практике проблема не только в том, что “нет тестов”. Часто тесты/чеки есть, но:
- кто-то заявляет, что всё готово (“починил, должно работать”), а реально — нет;
- тесты “должны запускаться”, но их не запускают стабильно или результаты никто не читает.
Два полезных паттерна для этого контура:
- Верификатор — независимый “скептик”, который проверяет, что заявленное “готово” действительно работает: запускает релевантные проверки, ищет пропуски и краевые случаи, возвращает отчёт “что прошло / что сломано / что не проверено”.
- Тест-раннер — исполнитель, который проактивно прогоняет нужные тесты/проверки (в т.ч.
golden tests) при изменениях и доводит до зелёного состояния, не переписывая ожидания тестов под “как получилось” и не ломая их исходный смысл.
Важно: это не обязательно “отдельные модели” — это может быть отдельная роль в вашей мультиагентной системе или просто формализованный шаг в CI/CD. Ценность — в разделении ответственности: исполнитель пишет/меняет, верификатор доказывает, тест‑раннер прогоняет и фиксирует результат.
Пример реализации (как это выглядит в инструменте): многие среды позволяют настраивать специализированных исполнителей для “верификации”, “дебага” и “запуска тестов”. Например, см. раздел про эти роли в Cursor Subagents (как один из примеров реализации концепта).
Дополнение: чтобы этот контур был устойчивым, удобно упаковать “верификацию” и “прогон тестов” как Agent Skills (папки с SKILL.md): с чётким описанием “когда применять”, DoD/форматом отчёта и ссылками на команды/скрипты. Тогда проверка становится переносимой процедурой, а не разовой просьбой в чате.1
Концепция 3: Цикл улучшений — систематическое обучение#
Проблема в 2014:
Bill решил 20 инцидентов → “стало лучше” → но не знает что конкретно улучшить.
Решение в 2026: цикл улучшений
Цикл улучшений#
Шаг 1: запуск eval#
Запусти eval на текущем агенте → измерь метрики (пример):
- Точность: 80% (16/20 correct)
- Доля ложных срабатываний: 15% (3/20 wrong)
- Средний TTRC: <TTRC_SECONDS>
Шаг 2: анализ провалов#
Для каждого проваленного инцидента:
- Почему агент не нашёл первопричину?
- Какая гипотеза пропущена?
- Какие диагностические команды не выполнены?
Пример:
{
"failed_incident": "INC-2024-12-30",
"ground_truth": "нет индекса в БД",
"predicted": "легитимная высокая нагрузка",
"analysis": {
"missing_hypothesis": "Проверить длительность запросов к БД + план выполнения запроса",
"missing_diagnostics": "EXPLAIN для запроса (проверить, что используется индекс)",
"root_cause": "Плейбук триажа не проверяет индексы БД"
}
}
Шаг 3: внедрение исправления#
Добавь недостающую гипотезу в плейбук триажа:
Пример правки (новая гипотеза):
- Гипотеза 4: отсутствует индекс в БД (вероятность: средняя)
- Диагностика:
ssh db-prod-01 'sudo -u postgres psql -c "EXPLAIN ANALYZE <SLOW_QUERY>"'
- Критерий успеха: запрос использует индекс (нет
Seq Scan) - Если обнаружен
Seq Scan:- первопричина: отсутствует индекс
- исправление: создать индекс
- остановка: завершить триаж
Шаг 4: повторный запуск eval#
Запусти eval на улучшенном агенте → измерь метрики (пример):
- Точность: 90% (18/20 correct) — +10% улучшение
- Доля ложных срабатываний: 10% (2/20 wrong) — -5% улучшение
- Средний TTRC: <TTRC_SECONDS> — улучшение относительно базового уровня
Шаг 5: деплой улучшенного агента#
Если улучшение измерено → деплой в продакшен.
Шаг 6: мониторинг в продакшене#
Собирай новые инциденты → добавляй в eval-набор → возвращайся к шагу 1.
Результат: цикл непрерывных улучшений.
Метрика улучшений:
- В 2014 Bill: нет измерений (не знал, что улучшилось)
- В 2026 цикл улучшений у Lance: точность 80% → 90% (измеримо +10%)
Концепция 4: покрытие тестами — happy path и edge cases#
Проблема:
Eval-набор из 20 инцидентов, но все инциденты — рутинные (например, high CPU, disk full).
Агент проходит eval (точность 90%) → деплой в продакшен → падает на краевом случае (например, разрыв сети network partition или редкий дедлок в БД DB deadlock).
Решение: матрица покрытия тестами
Матрица покрытия тестами
Категории покрытия
Рутинные сценарии — happy path:
- Высокая загрузка CPU (утечка памяти)
- Диск заполнен (не работает ротация логов)
- Пул подключений к БД исчерпан
- Таймаут API из‑за медленного запроса к БД
Цель покрытия: 80% инцидентов в продакшене
Краевые случаи — edge cases: редкие, но критичные
- Разрыв сети —
network partition/split-brain - Дедлок в БД —
DB deadlock - Каскадный отказ —
service A → B → C - Инцидент безопасности —
security breach
Цель покрытия: 15% инцидентов в продакшене
Неизвестное — unknown: никогда не встречалось
- Новый тип инцидента
- Агент должен эскалировать (не может обработать)
Цель покрытия: 5% инцидентов в продакшене
Состав eval-набора
Рекомендуемая пропорция:
{
"eval_dataset": {
"total": 20,
"happy_path": 16, // 80%
"edge_cases": 3, // 15%
"unknown": 1 // 5%
}
}
Примеры краевых случаев — edge cases:
Разрыв сети —
network partition:- Симптомы: service A не может достучаться до service B, но оба сервиса выглядят healthy
- Первопричина: неверно настроенные правила сети/egress на межсетевом экране
- Агент должен: обнаружить сетевую проблему и эскалировать к сетевой команде
Дедлок в БД —
DB deadlock:- Симптомы: таймауты запросов, CPU БД в норме, периодические блокировки
- Первопричина: circular dependency в транзакциях
- Агент должен: распознать паттерн deadlock и предложить retry‑логику для транзакций
Каскадный отказ —
cascading failure:- Симптомы: несколько сервисов «падают» одновременно
- Первопричина: цепочка зависимостей (A зависит от B, B зависит от C, C упал)
- Агент должен: построить граф зависимостей и определить корневой сервис
Критерии успеха:
happy path: точность ≥ 95%edge cases: точность ≥ 70%unknown: доля эскалаций = 100%
В 2014 Bill тестировал только happy path — рутинные инциденты. В 2026 покрытие тестами включает edge cases → агент становится устойчивее.
Концепция 5: continuous eval (непрерывный eval) — мониторинг качества в продакшене#
Проблема:
Eval на стейджинге: точность 90%.
Продакшен: точность 70% (хуже).
Почему?
Стейджинг ≠ продакшен:
- Разное распределение данных (staging synthetic, production real): на стейджинге синтетика, в продакшене — реальные данные
- Разная нагрузка (staging low traffic, production high): низкий трафик на стейджинге, высокий в продакшене
- Разные режимы отказов (staging controlled, production chaotic): на стейджинге всё контролируемо, в продакшене — хаотично
Решение: continuous eval (непрерывный eval) в продакшене
Как это работает:
- Агент решает инцидент в продакшене.
- После инцидента человек делает ревью решения агента:
- первопричина корректна? (да/нет)
- исправление корректно? (да/нет)
- TTRC приемлем? (да/нет)
- Инцидент добавляется в eval-набор:
{
"incident_id": "INC-PROD-2026-01-17",
"timestamp": "2026-01-17T02:17:00Z",
"agent_prediction": "memory_leak",
"human_review": {
"root_cause_correct": true,
"fix_appropriate": true,
"ttrc_seconds": 180,
"comments": "Агент корректно определил утечку памяти. Исправление сработало."
},
"added_to_eval": true
}
- Раз в неделю перезапускать eval (eval-набор растёт со временем).
Дашборд метрик#
Метрики eval в продакшене: в реальном времени
Точность (accuracy) агента (последние 30 дней): 87%
Доля ложных срабатываний (false positive rate): 8%
Средний TTRC: 6.5 минут
Доля эскалаций: 12%
Тренд: +3% (по сравнению с прошлым месяцем)
Триггеры действий:
- Если точность < 80% в течение 7 дней → расследовать регрессию
- Если доля ложных срабатываний > 15% → пересмотреть плейбук триажа
- Если TTRC > 10 минут → оптимизировать диагностические команды
В 2014 Bill не мог измерять качество в продакшене (нет eval-контурa). В 2026 Lance добавляет continuous eval → мониторинг качества в реальном времени.
Практика: создание eval-набора из 20 прошлых инцидентов#
Задача#
Создать eval-набор из 20 инцидентов (2024–2025) и запустить eval агента.
Шаг 1: собрать инциденты#
Источник: логи инцидентов в продакшене (2024–2025)
Примечание: ниже — пример/псевдокод. Не запускайте команды в продакшене «как есть»: адаптируйте под вашу систему инцидентов и доступы (read‑only по умолчанию, разрешённый список команд).
# Экспортировать инциденты из системы управления инцидентами
$ sudo journalctl -u incident-tracker --since="365 days ago" > incidents_2024_2025.log
# Разобрать инциденты (извлечь incident_id, timestamp, logs, metrics, resolution)
$ python parse_incidents.py incidents_2024_2025.log > eval_dataset.json
Eval-набор (20 инцидентов):
{
"eval_dataset": [
{
"incident_id": "INC-2024-01-15",
"timestamp": "2024-01-15T03:20:00Z",
"service": "api-gateway",
"alert": "Высокая загрузка CPU",
"logs": ["ERROR: OutOfMemoryError..."],
"metrics": {"cpu": 85, "memory": 92},
"ground_truth": {
"root_cause": "memory_leak_reports_endpoint",
"fix": "restart_deployment",
"resolution_time_human_seconds": 1800
}
},
// ... 19 more incidents
]
}
Шаг 2: запустить eval#
Eval script:
# eval_agent.py
import json
import time
def run_eval(agent, eval_dataset):
results = []
for incident in eval_dataset:
print(f"Проверяем {incident['incident_id']}...")
# Запустить triage агента
start_time = time.time()
prediction = agent.triage(
logs=incident['logs'],
metrics=incident['metrics']
)
ttrc = time.time() - start_time
# Сравни с эталоном
correct = (prediction['root_cause'] == incident['ground_truth']['root_cause'])
results.append({
'incident_id': incident['incident_id'],
'ground_truth': incident['ground_truth']['root_cause'],
'predicted': prediction['root_cause'],
'correct': correct,
'ttrc_seconds': ttrc
})
# Посчитать метрики
accuracy = sum(r['correct'] for r in results) / len(results)
avg_ttrc = sum(r['ttrc_seconds'] for r in results) / len(results)
return {
'results': results,
'metrics': {
'accuracy': accuracy,
'average_ttrc_seconds': avg_ttrc
}
}
# Запустить eval
with open('eval_dataset.json') as f:
dataset = json.load(f)['eval_dataset']
eval_results = run_eval(agent, dataset)
print(f"Точность: {eval_results['metrics']['accuracy']:.2%}")
print(f"Средний TTRC: {eval_results['metrics']['average_ttrc_seconds']:.1f}s")
Вывод (пример):
Проверяем INC-2024-01-15... OK (верно, <TTRC_SECONDS>)
Проверяем INC-2024-02-10... OK (верно, <TTRC_SECONDS>)
Проверяем INC-2024-03-15... OK (верно, <TTRC_SECONDS>)
Проверяем INC-2024-04-20... FAIL (неверно, <TTRC_SECONDS>)
...
Проверяем INC-2025-12-30... OK (верно, <TTRC_SECONDS>)
Результаты:
Точность: 90% (18/20 верно)
Доля ложных срабатываний (false positive rate): 10% (2/20 неверно)
Средний TTRC: <TTRC_SECONDS>
Шаг 3: анализ провалов#
2 проваленных инцидента:
{
"failures": [
{
"incident_id": "INC-2024-04-20",
"ground_truth": "network_partition_between_services",
"predicted": "service_down",
"analysis": {
"reason": "Агент не проверил сетевую связность между сервисами",
"missing_diagnostic": "ping/curl между сервисами",
"fix": "Добавить гипотезу: network partition"
}
},
{
"incident_id": "INC-2024-08-12",
"ground_truth": "db_deadlock",
"predicted": "db_slow_query",
"analysis": {
"reason": "Агент не распознал паттерн deadlock в логах БД",
"missing_diagnostic": "парсинг логов БД по 'deadlock detected'",
"fix": "Добавить regex-паттерн для детектирования deadlock"
}
}
]
}
Шаг 4: внедрить исправления#
Исправление 1: добавить гипотезу разрыва сети (network partition)
+### Гипотеза 5: разрыв сети — `network partition`
+
+**Диагностика:**
+```bash
+ssh service-a-01 "curl -s http://service-b/health"
+```
+
+**IF timeout:**
+ - Первопричина: network partition
+ - ESCALATE к сетевой команде
Исправление 2: добавить детектирование deadlock
+# Проверить логи БД на паттерн deadlock
+if "deadlock detected" in db_logs:
+ root_cause = "db_deadlock"
+ fix = "restart transactions + review transaction isolation"
Шаг 5: повторный запуск eval#
Точность: 95% (19/20 верно) — +5% улучшение
Средний TTRC: <TTRC_SECONDS> — улучшение относительно базового уровня
Оставшийся провал: INC-2024-11-05 (unknown edge case)
Шаг 6: создать golden tests#
Выбери 5 критичных инцидентов как golden tests:
{
"golden_tests": [
"INC-2024-01-15", // High CPU (часто)
"INC-2024-03-20", // Payroll down (business-critical)
"INC-2024-05-10", // Billing timeout (high cost)
"INC-2024-07-22", // DB connection pool (часто)
"INC-2024-09-15" // Disk full (часто)
]
}
Контрольная точка в CI/CD:
# Перед деплоем
$ python eval_agent.py --golden-only
Результаты golden tests:
Все 5 golden tests PASSED
ДЕПЛОЙ РАЗРЕШЁН
Время выполнения:
- В 2014 Bill: нет eval setup (не измерял качество)
- В 2026 настройка eval у Lance: 2 часа (собрать инциденты, написать eval script) → переиспользуемо для всех будущих прогонов
Типовые ошибки#
Ошибка 1: Eval только на happy path → агент падает на edge cases#
Сценарий:
Eval-набор из 20 инцидентов — все рутинные (например, high CPU, disk full).
Точность агента 95% → деплой в продакшен → падает на network partition (не было в eval).
Проблема: eval-набор не репрезентативен (нет edge cases).
Вывод:
В 2014 Parts Unlimited тестировали Phoenix Project на стейджинге только на рутинных сценариях. Продакшен выявил edge cases → серия сбоев.
В 2026 Lance фиксирует правило: eval-набор должен включать edge cases:
Состав eval-набора (рекомендуемая пропорция):
happy path: 80% (например, high CPU, disk full)edge cases: 15% (например, network partition, deadlock, cascading failure)unknown: 5% — агент должен эскалировать
Примеры краевых случаев (edge cases), которые стоит включить:
- Network partition (2 incidents)
- DB deadlock (1 incident)
- Cascading failure (1 incident)
Проверка: точность агента на edge cases ≥ 70% + доля эскалаций по unknown = 100%.
Как избежать:
Чеклист eval-набора:
- 80% —
happy path - 15% —
edge cases - 5% —
unknown(эскалация) - Репрезентативность распределению инцидентов в продакшене
Ошибка 2: golden tests не обновляются → регрессия не ловится#
Сценарий:
golden tests создали в 2024 (5 инцидентов).
В 2025 появился новый критичный тип инцидентов (например, падение хоста/юнита systemd или проблема с BGP‑анонсом VIP).
Агент v2 задеплоили → падает на “VIP не анонсируется / агент недоступен” → этого не было в golden tests.
Проблема: golden tests статичны, а продакшен меняется.
Вывод:
В 2014 Parts Unlimited CAB checklist был статичным и не обновлялся годами (создан в 2012). В 2014 началась миграция в облако → появились новые режимы отказов → checklist устарел.
В 2026 Lance фиксирует правило: golden tests должны эволюционировать:
Поддержка golden tests#
Квартальный обзор (каждые 3 месяца):
- Проанализировать инциденты в продакшене за последние 3 месяца
- Найти новые критичные типы инцидентов
- Добавить в golden tests, если:
- бизнес‑критично, или
- высокая цена ошибки (>
), или - часто (> 3 раза за квартал)
Пример:
Q1 2025: 3 инцидента “VIP не анонсируется / хост умер” — критично → добавить в golden tests Q2 2025: 5 проблем с инвалидацией Redis‑кэша — часто → добавить в golden tests
Результат: golden tests растут со временем: 5 → 7 → 10 (репрезентативно текущему продакшену).
Как избежать:
Чеклист поддержки golden tests:
- Квартальный обзор запланирован
- Новые критичные инциденты выявлены
- golden tests обновлены: добавлены новые, удалены устаревшие
- Контрольная точка в CI/CD включает обновлённые golden tests
Ошибка 3: Eval не запускается перед deployment → регрессия уезжает в продакшен#
Сценарий:
Разработчик меняет плейбук триажа → коммитит → деплоит без eval → в продакшене точность агента падает 90% → 75%.
Проблема: нет CI/CD gate для eval.
Вывод:
В 2014 Wes Davis деплоил без тестирования (Cowboy change) → авария в продакшене.
В 2026 Lance закрепляет: eval обязателен в CI/CD:
# .github/workflows/deploy.yml
name: Deploy Agent
on:
push:
branches: [main]
jobs:
eval:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
# Если у вас есть зависимости:
# - name: Install dependencies
# run: pip install -r requirements.txt
- name: Run Eval
run: |
python eval_agent.py --full-dataset
- name: Check Metrics
run: |
python - <<'PY'
import json
with open("eval_results.json", "r", encoding="utf-8") as f:
data = json.load(f)
accuracy = float(data["metrics"]["accuracy"])
threshold = 0.80
if accuracy < threshold:
raise SystemExit(f"Eval FAILED: accuracy {accuracy:.4f} < {threshold:.2%}")
print(f"Eval PASSED: accuracy {accuracy:.4f} >= {threshold:.2%}")
PY
- name: Golden Tests
run: |
python eval_agent.py --golden-only
# All golden tests must pass (exit 0)
deploy:
needs: eval # Deploy only if eval passed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Ansible
run: |
python -m pip install --upgrade pip
pip install "ansible-core>=2.16"
# В реальном деплое здесь понадобятся секреты/ключи/known_hosts и окружение.
- name: Dry-run Deploy (required)
run: |
ansible-playbook -i inventories/production playbooks/agent.yml \
--tags deploy \
--check --diff \
--extra-vars "agent_version=v2"
- name: Deploy to Production
run: |
ansible-playbook -i inventories/production playbooks/agent.yml \
--tags deploy \
--extra-vars "agent_version=v2"
Как избежать:
CI/CD gate checklist:
- Eval запускается автоматически на каждый коммит
- Деплой блокируется, если точность ниже порога
- golden tests должны проходить без исключений
- Метрики логируются для отслеживания динамики
Резюме#
Что мы сделали#
Создали системный способ измерять качество агента:
- Eval-набор: 20 прошлых инцидентов (логи + метрики + эталон)
- Метрики: точность, доля ложных срабатываний, средний TTRC
- golden tests: 5 критичных инцидентов, которые должны проходить (защита от регрессий)
- Цикл улучшений: измеряем → разбираем провалы → исправляем → измеряем снова
- Непрерывный eval: инциденты из продакшена добавляются в eval-набор (он растёт со временем)
Артефакты#
- Шаблон eval-набора (структура записи инцидента)
- Скрипт для eval (посчитать метрики: точность, доля ложных срабатываний, TTRC)
- Определение golden tests (критерии + контрольная точка в CI/CD)
- Процесс цикла улучшений (измеряем → анализируем → исправляем → измеряем снова)
- Матрица покрытия тестами:
happy path80%,edge cases15%,unknown5%
Ключевые принципы#
В 2014: Bill Palmer «чувствовал», что стало лучше. Нет метрик → нет доказательства и нет системного улучшения.
В 2026: eval-набор делает качество измеримым. Точность 80% → улучшения → 90% → 95%. Каждое улучшение можно проверить.
Главное:
- Eval-набор = эталон (известные первопричины)
- Метрики = измеримое качество (не “чувствуем”)
- Цикл улучшений = системное обучение (не случайная «проба‑ошибка»)
Метрики успеха:
- Bill Palmer (2014): измерение качества субъективно, отслеживания нет, защиты от регрессий нет
- С eval-набором (2026): точность 90%, TTRC <TTRC_SECONDS>; отслеживание улучшений есть; golden tests блокируют деплой при регрессии
Критерии приёмки главы#
Вы успешно освоили материал, если можете:
Уровень 1: Понимание
- Объяснить, что такое eval-набор и зачем он нужен
- Объяснить разницу между точностью и долей ложных срабатываний
- Перечислить 3 типа инцидентов в eval-наборе:
happy path,edge cases,unknown
Уровень 2: Применение
- Создать eval-набор из 5–10 прошлых инцидентов
- Написать скрипт для eval (запуск агента на eval-наборе + расчёт метрик)
- Определить golden tests (3–5 критичных инцидентов)
Уровень 3: Воспроизводимость
- Eval успешно запущен (метрики посчитаны)
- Провалы проанализированы (первопричина определена)
- Улучшения внесены, повторный eval показывает улучшение
Уровень 4: Интеграция в продакшен
- Eval интегрирован в CI/CD (запускается перед деплоем)
- golden tests блокируют деплой, если не пройдены
- Continuous eval в продакшене (реальные инциденты добавляются в eval-набор)
- Цикл улучшений работает (точность растёт со временем)
Следующие шаги#
Глава 9: Команда агентов + управление практикой — как масштабировать от 1 агента к команде агентов: Analyst/Triage/SRE/Orchestrator.
Связь с Главой 8: Eval измеряет качество 1 агента. Но что если задача требует координации нескольких агентов? Глава 9 покажет, как организовать команду.
Открытый формат “Agent Skills”: skills как переносимые пакеты знаний и принцип progressive disclosure: Agent Skills Overview. ↩︎