Capstone: trace detective
Diagnosing a failing production agent from raw traces: aggregates, reading a sample, root-cause evidence, and an RCA report with eval cases against recurrence.
Lesson content is currently available in Russian.
What you will learn
- →Вести расследование по сырым трейсам: от агрегатов и таймлайна к чтению деревьев и доказательствам.
- →Опознавать в сырых данных циклы, распухший контекст, сломанные инструменты и тихую смену модели.
- →Оформлять RCA-отчёт с trace-id-доказательствами, фиксами первопричин и регрессионными кейсами.
Дано: зелёный uptime, красные отзывы
Сценарий капстоуна. Агент поддержки интернет-магазина работает в проде полгода: инструменты search_orders, get_policy, create_ticket, retrieval по базе знаний, модель за алиасом провайдера. Две недели назад всё было спокойно; сейчас поддержка завалена жалобами «бот отвечает не то и подвисает», доля 👎 выросла втрое. При этом дашборд доступности безмятежно зелёный: 200 OK, error rate у API в норме. Знакомая по уроку 5 картина — значит, копать надо в качество и трейсы.
Вам выдают выгрузку: ~500 трейсов за 14 дней в JSONL — по спану на строку, с trace_id, parent_span_id, таймстемпами, статусами, атрибутами gen_ai.* у генераций, аргументами и результатами tool-спанов, скорами фидбэка на трейсах. Никакого UI — только сырые данные, скрипты и метод. Это намеренно: платформа наблюдаемости может смениться, а навык читать сырые трейсы остаётся.
Задача из трёх частей: найти первопричины деградации (спойлер сценария: их больше одной — в реальных инцидентах дефекты любят накладываться); доказать каждую конкретными trace_id и полями, а не впечатлениями; предложить фиксы и регрессионные кейсы, закрывающие рецидив.
Правила детектива, выстраданные предыдущими уроками: сначала агрегаты, потом чтение отдельных трейсов — иначе утонете; гипотезы записываются до проверки, чтобы данные не подгонялись под первое впечатление; вывод без доказательства — не вывод, а версия.
Шаг 1: агрегаты и таймлайн
Расследование начинается с цифр по дням — они сужают область поиска с 500 трейсов до нескольких подозреваемых сегментов. Минимальный набор: число трейсов, p50/p95 длительности, среднее и максимальное число спанов на трейс, распределение finish_reasons, error rate по каждому имени инструмента, суммарные input_tokens, доля 👎.
import json, collections
by_day = collections.defaultdict(lambda: collections.Counter())
spans_per_trace = collections.Counter()
for line in open("traces.jsonl"):
s = json.loads(line)
day = s["start_time"][:10]
spans_per_trace[s["trace_id"]] += 1
attrs = s.get("attributes", {})
for fr in attrs.get("gen_ai.response.finish_reasons", []):
by_day[day]["finish:" + fr] += 1
if s.get("kind") == "tool" and s.get("status") == "ERROR":
by_day[day]["tool_error:" + s["name"]] += 1
Дальше — таймлайн и точки перелома. Ищете день, когда метрика сломала тренд, и синхронные изменения: «с 9-го числа среднее число спанов выросло с 6 до 19, p95 — с 8 до 40 секунд» — гипотеза о циклах; «с 11-го доля finish_reason = length подскочила с 1% до 15%, суммарные input_tokens удвоились» — гипотеза о распухшем контексте; «error rate search_orders с 12-го держится на 30%» — гипотеза о сломанном инструменте.
Итог шага — таблица «дата перелома → аномалия → гипотеза», где гипотез обычно две-четыре. Обратите внимание: разные даты переломов почти наверняка означают разные независимые первопричины — не пытайтесь объяснить всё одной.
Шаг 2: чтение трейсов и сбор доказательств
Из каждого аномального сегмента возьмите 5–10 трейсов и восстановите деревья (сортировка спанов по parent_span_id и таймстемпам). Вот как типовые находки выглядят в сырых данных:
- Цикл: подряд пять tool-спанов
search_ordersс одинаковым аргументом{"order_id": "ORD-000000"}— модель выдумала несуществующий номер и долбит поиск; после пятого повтора — капитуляция «не могу найти заказ». Доказательство: trace_id + последовательность идентичных вызовов; - Сломанный инструмент: с 12-го числа все спаны
search_ordersсо status = ERROR и одинаковым текстом исключения (смена схемы ответа внешнего API). Коварная часть — трейсы завершаются OK: агент отвечает про заказы «по памяти», из общих соображений. Классическая проглоченная ошибка из урока 4; - Распухший контекст: в длинных сессиях input_tokens генераций растут по шагам — 3k, 18k, 60k, 115k — затем finish_reason = length; сопоставив с датой деплоя, находите релиз, где сломали обрезку истории;
- Тихая смена модели: с 9-го числа
gen_ai.response.modelотличается от привычного при неизменномgen_ai.request.model— провайдер переключил алиас, и стиль ответов «поплыл», что видно по скорам фидбэка именно на этой модели.
Форма доказательства всегда одна: конкретные trace_id, конкретные поля, конкретные числа. «Кажется, агент зацикливается» — версия; «в 41 трейсе после 9-го числа ≥4 идентичных вызова search_orders подряд, примеры: trace abc123, def456» — доказательство. Держите для каждой гипотезы и контрпример: если контекст распухал и до 11-го числа, гипотеза о дате деплоя неверна.
Шаг 3: RCA-отчёт и закрытие петли
Финальный артефакт — RCA-отчёт (root cause analysis), по которому команда чинит систему, а не спорит о впечатлениях. Структура:
Формат отчёта
- Симптом — что видел бизнес: метрика фидбэка, график с датой перелома;
- Находки — по одной на первопричину: механизм (как именно дефект приводит к плохим ответам), масштаб (доля затронутых трейсов), доказательства (trace_id, поля, числа), дата и триггер (деплой, смена алиаса, изменение внешнего API);
- Фиксы — на каждую находку короткий (остановить кровь: откат, лимит итераций) и системный (устранить класс: детект повторов, проброс ошибок инструментов в контекст, бюджет контекста, пиннинг версии модели);
- Регрессионные кейсы — какие кейсы уходят в eval-сет по каждой находке;
- Алёрты — какие сигналы из урока 5 поймали бы это на сутки раньше (расхождение response/request model, доля length, error rate инструмента, рост спанов на трейс).
Критерии качества: каждый вывод воспроизводим — читатель с той же выгрузкой приходит к тем же числам; фиксы адресуют первопричины, а не симптомы («увеличить таймаут» не лечит цикл); последние два раздела превращают разовое расследование в постоянную защиту — это и есть петля из урока 6, замкнутая на реальном инциденте.
Если отчёт написан хорошо, следующий такой инцидент не потребует детектива: его поймает алёрт, объяснит сегментированный дашборд, а регрессию заблокирует CI-гейт. В этом и есть смысл курса — превратить отладку чёрного ящика из искусства в конвейер.
Practice
Расследование от начала до конца
Соберите датасет для расследования: либо экспортируйте 200+ трейсов своего агента, подложив в него два дефекта (например, сломайте обрезку истории и «уроните» один инструмент), либо сгенерируйте синтетическую выгрузку скриптом. Передайте выгрузку напарнику (или пройдите сами «вслепую» через неделю): агрегаты по дням, таймлайн переломов, чтение выборки, доказательства, RCA-отчёт по формату урока.
Deliverable
RCA-отчёт: все заложенные первопричины найдены и доказаны trace_id и полями, по каждой — короткий и системный фикс, минимум 8 регрессионных eval-кейсов и 3 алёрта, которые поймали бы инцидент раньше.
Checkpoint
Защитите свой RCA-отчёт: проведите слушателя от симптома через доказательства к фиксам и покажите, почему инцидент не повторится молча.
- ✓ Порядок расследования соблюдён: агрегаты и таймлайн до чтения отдельных трейсов, гипотезы зафиксированы до проверки.
- ✓ Каждая первопричина доказана конкретными trace_id и полями (finish_reasons, статусы tool-спанов, response.model, input_tokens), найдены все независимые дефекты.
- ✓ Отчёт закрывает петлю: фиксы первопричин, регрессионные кейсы в eval-сете и алёрты на раннее обнаружение.
Check yourself
Sources