Учебный гайд: Прикладная часть 9. Маршрутизация моделей и бюджет токенов

Урок 3 из 5 в модуле «Прикладная часть 9. Маршрутизация моделей и бюджет токенов»
Вы просматриваете урок без входа. Войдите, чтобы сохранять прогресс и проходить тесты.

Тема: Прикладная часть 9. Маршрутизация моделей и бюджет токенов

Уровень сложности: Средний

Расчётное время изучения: 4-6 часов (теория + практика), дополнительно 2 часа на полный трек с калибровкой порогов

Предварительные требования: Знакомство с SDD-циклом (сбор сигнала, детект, диагностика из первого тома)

Часть 15 первого тома: заменяемость агента

Часть 14 первого тома: проектные навыки и хуки Qwen Code

Базовое владение Python и командной строкой

Понимание концепций MTTR, SLA, эскалации инцидентов

Цели обучения: Смоделировать и проверить сценарий отказа дешёвого яруса моделей, обеспечив пропуск только критичных задач на дорогой ярус с сохранением token_health_min ≥ 0.5

Построить распределение токенов по фазам инцидент-менеджмента (triage, classification, diagnosis, plan, remediation, postmortem) с пропорцией 90/10 между local-coder и frontier-reviewer

Сформулировать и применить правило anti-Goodhart для валидации бюджетной оптимизации, связывая MTTR с четырьмя сторожевыми метриками

Определить условия активации аварийного режима (red button) и обосновать, когда ручной режим безопаснее продолжения автоматизации

Создать артефакт budget-note.md для capstone-проекта, фиксирующий риск отказа, эффект, guard-порог и решение

Обзор: Эта глава превращает суточный бюджет токенов из статического лимита в управляемую таблицу маршрутизации SDD-конвейера. Ярусные бюджеты (tier-budgeting) распределяют токены между уровнями моделей по фазам работы: дешёвая модель local-coder обрабатывает рутину (triage, классификация, черновая диагностика), дорогая frontier-reviewer включается только на критические ревью, спорные решения и пост-анализ. Ключевой навык — моделирование отказа: при падении дешёвого яруса система не должна автоматически перенаправлять всю очередь на дорогой ярус, иначе квота исчерпается за минуты, а настоящие P0/P1 останутся без ресурсов. Глава включает runnable-примеры (compile.py, simulate.py, inspect.py), сценарии отказа на 15 и 45 минут, а также интеграцию с anti-Goodhart-валидацией для предотвращения искажения метрик.

Ключевые концепции: Ярус (tier): Уровень модели в иерархии обработки. local-coder — базовый ярус для массовой рутины, frontier-reviewer — верхний ярус для спорных и высокорисковых случаев. Роли, а не имена моделей: в разных проектах могут быть разные реализации.

Token health: Сводный показатель здоровья бюджета токенов, отслеживающий соотношение потраченных и оставшихся токенов к плану. Минимальное значение token_health_min используется как guard-порог для блокировки автоматического переключения.

Failover to frontier: План переключения нагрузки при отказе яруса. Ранжированное переключение: только задачи с высоким severity и возрастом уходят в frontier-reviewer, остальные — в degraded queue или ручной канал.

Degraded queue: Очередь деградации — задачи, которые не могут быть обработаны в штатном режиме при отказе дешёвого яруса, но ещё не требуют немедленной эскалации на дорогой ярус.

Manual queue after 120s: Ручной канал, открывающийся после тайм-аута 120 секунд для задач, которые не были обработаны автоматически. Не откат к хаосу: наследует тот же протокол доказательств и проверки PostToolUse.

Control reserve: Страховочный слой бюджета, активируемый только при росте риска, очереди или неопределённости. Не «остаток на всё подряд».

Red button (аварийный режим): Защищённый режим управления, активируемый при формальных условиях: два окна роста риска token_health, очередь выше лимита, превышение SLA по критичным severity или падение local-coder. Ограничивает новую очередь, запрещает массовые автоматические ремедиации, сохраняет frontier-reviewer для P0/P1.

Anti-goodhart-валидация: Правило, запрещающее считать релиз удачным, если одна метрика выросла за счёт деградации других. MTTR валидируется вместе с escalation_share, silent_p0, unresolved_manual_ratio, postmortem_gap и token_health_min.

Budget-keeper (хранитель бюджета): Служба контроля бюджета токенов, ежеминутно пересчитывающая spent[p], queue[p], quota[p], возраст инцидента, blast radius и confidence-gap для принятия решений о маршрутизации.

Budget-drill: Ежедневный учебный прогон: вчерашний поток оповещений проигрывается через текущий budget_network.yaml с искусственным отключением local-coder на 15/30/45 минут для калибровки чувствительности системы.

Практические упражнения: Название: Компиляция бюджетного плана и проверка пропорций

Проблема: В каталоге book2/examples/budget-keeper скомпилируйте бюджетный план из specs/budget_network.yaml. Проверьте, что daily_budget_tokens равен 10 000 000, сумма квот local-яруса составляет 9 000 000, а frontier-яруса — 1 000 000. Сравните результат с эталоном outputs/budget_plan.example.json.

Решение: 1. cd book2/examples/budget-keeper

  1. python3 scripts/compile.py --budget-spec specs/budget_network.yaml --out out/budget_plan.json
  2. Проверьте поле daily_budget_tokens: 10000000
  3. Подсчитайте сумму local-coder: 3000000 + 2000000 + 1500000 + 800000 + 700000 + 300000 + 700000 = 9000000
  4. Подсчитайте сумму frontier-reviewer: 120000 + 140000 + 180000 + 120000 + 200000 + 240000 + 0 = 1000000
  5. diff out/budget_plan.json outputs/budget_plan.example.json — расхождений быть не должно (или только в комментариях)

Сложность: beginner

Название: Симуляция 45-минутного отказа и комплексная инспекция

Проблема: Смоделируйте отказ local-coder на 45 минут с 20 инцидентами в очереди и ручным тайм-аутом 120 секунд. Проверьте четыре условия одновременно: failover_to_frontier == 5, degraded_queue == 15, manual_queue_after_120s == 15, token_health_min >= 0.5. Объясните, почему нельзя проверять метрики по отдельности.

Решение: 1. python3 scripts/simulate.py --plan out/budget_plan.json --scenario scenarios/fail_local_45m.json --out out/fail_result.json

  1. python3 scripts/inspect.py --result out/fail_result.json --query "failover_to_frontier==5 && degraded_queue==15 && manual_queue_after_120s==15 && token_health_min>=0.5"
  2. Ожидаемый код возврата: 0 (все условия выполнены)
  3. Почему нельзя по отдельности: проверка только failover_to_frontier==5 не гарантирует, что остальные 15 задач не ушли в frontier через другой механизм; проверка только token_health не показывает распределение очереди; комплексное условие в && гарантирует целостную картину — отказ хотя бы одной метрики ломает прогон и требует разбора

Сложность: intermediate

Название: Сравнительный анализ 15-минутного и 45-минутного отказа

Проблема: Смоделируйте короткий отказ local-coder на 15 минут. Проверьте token_health_min >= 0.7. Объясните, почему короткий отказ менее агрессивно жжёт frontier-ярус, и как это влияет на выбор guard-порога для production.

Решение: 1. python3 scripts/simulate.py --plan out/budget_plan.json --scenario scenarios/fail_local_15m.json --out out/fail_15m_result.json

  1. python3 scripts/inspect.py --result out/fail_15m_result.json --query "token_health_min>=0.7"
  2. Код возврата: 0
  3. Объяснение: при 15-минутном отказе меньше задач накапливается в очереди, меньше требуется эскалаций на frontier-reviewer, меньше расходуется резервный бюджет. При 45-минутном отказе очередь растёт, давление на frontier-ярус увеличивается, token_health просаживается сильнее.
  4. Вывод для production: guard-порог 0.60 (ниже наблюдаемого дна 0.5 при 45-минутном отказе, но с запасом) блокирует автоматическое переключение при прогнозируемых сбоях; 45-минутный отказ пробивает сторож и требует ручного решения

Сложность: intermediate

Название: Формулировка риска для capstone-проекта

Проблема: На основе результатов симуляций сформулируйте запись в capstone/budget-note.md для своего основного кейса (например, high_memory_usage). Запишите риск, эффект, simulated_floor, alert_threshold и decision. Объясните разницу между simulated_floor и alert_threshold.

Решение: Минимальный фрагмент:

risk: "local-coder недоступен 45m"
effect: "5 задач уходят в frontier-reviewer, 15 остаются degraded/manual"
simulated_floor: "token_health_min == 0.5 (просадка при 45m)"
alert_threshold: "token_health_min < 0.60 (сторож из anti-Goodhart-таблицы)"
decision: "не переводить всю очередь на дорогой ярус"

Разница: simulated_floor (0.5) — наблюдаемое дно симуляции, фактический минимум при тестовом сценарии. alert_threshold (0.60) — линия, ниже которой сторож блокирует автоматическое переключение в production. Между 0.5 и 0.60 — зона предупреждения, где система ещё работает, но требует внимания оператора.

Сложность: intermediate

Название: Калибровка сжатого бюджета (5M)

Проблема: Используйте specs/budget_network_5m.yaml для калибровочного варианта на 5M токенов. Проверьте сохранение пропорций 90/10. Смоделируйте тот же 45-минутный отказ и проанализируйте, как сокращение общего бюджета вдвое влияет на поведение системы и приемлемость guard-порогов.

Решение: 1. python3 scripts/compile.py --budget-spec specs/budget_network_5m.yaml --out out/budget_plan_5m.json

  1. Проверьте: daily_budget_tokens == 5000000, local-сумма == 4500000, frontier-сумма == 500000
  2. python3 scripts/simulate.py --plan out/budget_plan_5m.json --scenario scenarios/fail_local_45m.json --out out/fail_result_5m.json
  3. python3 scripts/inspect.py --result out/fail_result_5m.json --query "token_health_min>=0.5"
  4. Анализ: при сокращении бюджета вдвое абсолютные квоты уменьшаются, но относительное давление на систему возрастает — тот же поток 20 инцидентов потребляет большую долю резерва. token_health_min может просесть ниже 0.5 или guard-порог 0.60 станет недостижимым. Вывод: при масштабировании бюджета пропорционально потоку сохраняйте запас в control_reserve; при несоразмерном потоке пересмотрите guard-порог или увеличьте долю frontier-яруса до 15-20%

Сложность: advanced

Название: Проверка anti-Goodhart-шлюза

Проблема: Сформулируйте YAML-фрагмент validation.md для бюджетного шлюза. Условие: если MTTR P95 < 5 минут И доля эскалаций < 8%, то провалить проверку при silent_p0 > 2%, unresolved_manual_ratio > 5%, postmortem_gap > 10% или token_health_min < 0.60. Объясните, почему именно такая парная проверка.

Решение: Фрагмент validation.md:

checks:
  - id: anti_goodhart_budget
    if:
      all:
        - mttr_p95 < "5m"
        - escalation_ratio < 0.08
    then:
      fail_if:
        - silent_p0 > 0.02
        - unresolved_manual_ratio > 0.05
        - postmortem_gap > 0.10
        - token_health_min < 0.60

Почему парная проверка: без неё система могла бы оптимизировать MTTR за счёт занижения эскалаций (тихие P0), вытеснения сложных задач в ручной канал без пост-мортема или исчерпания бюджета frontier-яруса. Улучшение одной метрики при деградации других — классическое искажение Гудхарта. Шлюз блокирует такую «экономию».

Сложность: advanced

Кейсы: Название: Отказ local-coder в production: инцидент autoscale_200pct

Сценарий: Production-система appointments-api, утренний пик нагрузки. В 11:00 локальная конечная точка дешёвой модели local-coder становится недоступной на 45 минут (сетевой сбой в кластере). В очередь падают 20 инцидентов, связанных с автомасштабированием на 200% нагрузки. Ручной тайм-аут установлен в 120 секунд. Суточный бюджет: 10M токенов с распределением 9M/1M между local-coder и frontier-reviewer.

Задача: Классическая ловушка: при отказе дешёвого яруса автоматически перенаправить весь трафик на дорогой ярус. Это приведёт к исчерпанию 1M квоты frontier-reviewer за минуты, после чего настоящие P0/P1-инциденты останутся без ресурсов. Альтернативная ловушка: оставить все задачи в очереди деградации, что увеличит MTTR и может нарушить SLA для критичных случаев. Третья ловушка: не отслеживать token_health, не заметить просадку до опасного уровня.

Решение: Применена ранжированная политика failover: только 5 задач с максимальным blast radius (радиусом последствий) и возрастом > 90 секунд уходят в frontier-reviewer. 15 задач остаются в degraded queue. Через 120 секунд открывается ручной канал manual_queue_after_120s для задач, не обработанных автоматически. Хранитель бюджета ежеминутно пересчитывает token_health, spent[p], queue[p], quota[p]. При token_health_min < 0.60 (guard-порог) автоматическое переключение блокируется, требуется ручное решение. В данном сценарии token_health_min достигает 0.5 — пробивает guard, активируется red_button review.

Результат: Все 4 условия инспекции выполнены одновременно: failover_to_frontier == 5, degraded_queue == 15, manual_queue_after_120s == 15, token_health_min >= 0.5. Дорогой ярус сохранён для настоящих P0/P1. MTTR для критичных задач не пострадал. Ручной канал наследовал протокол доказательств, что позволило после восстановления local-coder провести аудит всех решений. Ступенчатый откат: сначала 30% квоты local-coder для triage/classification, затем diagnosis/plan после трёх стабильных окон, полный возврат только после аудита PostToolUse.

Извлечённые уроки: Нельзя проверять метрики отказа по отдельности — только комплексное условие в && гарантирует целостность

Между simulated_floor (0.5) и alert_threshold (0.60) нужен запас для предупреждения, а не только аварийной реакции

Ручной режим — не откат к хаосу, а контролируемая деградация с сохранением доказательной цепочки

Ступенчатый откат после стабилизации предотвращает второй каскад ошибок от преждевременного восстановления

Связанные концепции: failover_to_frontier

token_health_min

degraded_queue

manual_queue_after_120s

red_button

anti-Goodhart-валидация

budget-drill

Название: Ежедневный budget-drill в команде платёжного шлюза

Сценарий: Команда обработки инцидентов платёжного шлюза внедрила ярусную маршрутизацию с бюджетом 50M токенов в сутки (пропорция 85/15 из-за высокой сложности задач). Ежедневно в 9:00 запускается budget-drill: вчерашний поток из ~800 оповещений проигрывается через budget_network.yaml с искусственным отключением local-coder на 15, 30 и 45 минут.

Задача: При росте потока с 200 до 800 инцидентов пропорция 90/10, наследованная из учебного примера, оказалась недостаточной: frontier-ярус перегружался даже при 15-минутном отказе. Команда не могла отличить «нормальное давление» от «требующего пересмотра политики». Silent_p0 начал расти — сложные инциденты закрывались без эскалации из-за нехватки frontier-ресурса.

Решение: Данные drill-прогонов показали: при 15-минутном отказе token_health_min падал до 0.55 (ниже guard-порога 0.60), при 30-минутном — до 0.35. Команда пересмотрела пропорцию до 80/20, увеличила control_reserve с 700K до 2M, ввела промежуточный ярус mid-coder для diagnosis/plan (модель средней стоимости). Guard-порог token_health_min скорректирован до 0.65 с учётом новой чувствительности. Anti-Goodhart-шлюз дополнен метрикой mid_tier_saturation.

Результат: После калибровки 15-минутный отказ держит token_health_min >= 0.70, 30-минутный — >= 0.50. Silent_p0 снизился с 4.2% до 1.1%. MTTR P95 стабилизировался на 3.2 минуты без роста unresolved_manual_ratio. Команда зафиксировала правило: пересмотр пропорций при изменении потока более чем на 25% или при drill-показателе token_health_min < 0.60 на двух последовательных прогонах.

Извлечённые уроки: Учебная пропорция 90/10 — отправная точка, не догма; масштабирование требует пересмотра

Budget-drill выявляет проблемы до production-инцидента, но только если результаты читает команда, а не только CI

Промежуточный ярус может быть эффективнее простого увеличения доли frontier-яруса

Метрики drill должны влиять на operational policy, а не только на YAML-конфигурацию

Связанные концепции: budget-drill

tier-budgeting

control_reserve

anti-Goodhart-валидация

token_health_trend_5m

Советы по изучению: Проходите материал последовательно: сначала compile (понимание структуры), затем simulate 45m (отказ), затем simulate 15m (сравнение), затем inspect с комплексным условием. Пропуск шага ломает понимание чувствительности

Ведите рабочую тетрадь с двумя колонками: слева — команда и вывод скрипта, справа — интерпретация («что это значит для моего проекта»). Это превращает runnable-примеры в проектные решения

Используйте diff между out/budget_plan.json и outputs/budget_plan.example.json как диагностический инструмент, а не только как проверку правильности. Любое отклонение — повод разобраться в логике compile.py

Для визуалеров: нарисуйте диаграмму потока из 6 фаз с двумя ярусами и тремя выходами (frontier, degraded, manual). Отметьте, где именно применяются SLA-пороги и где находится guard token_health_min

Для аудиалов: проговорите вслух комплексное условие inspect с четырьмя метриками, объясняя каждое &&. Если не можете объяснить, почему именно 5 задач в frontier — вернитесь к разделу «ранжированное переключение»

Для кинестетиков: модифицируйте сценарий fail_local_45m.json — измените queue с 20 до 40, увеличьте duration до 60 минут, уменьшите manual_timeout_sec до 60. Предскажите результат, затем проверьте simulate + inspect. Неправильный прогноз — ценный сигнал для уточнения понимания

Фиксируйте в capstone/budget-note.md сразу после каждого успешного прогона, пока контекст свеж. Откладывание записи приводит к потере нюансов между simulated_floor и alert_threshold

Проводите «парную проверку» с коллегой: один объясняет, почему нельзя пускать всю очередь в frontier, другой — придумывает контрпример, когда это кажется разумным. Спор уточняет границы применимости политики

Дополнительные ресурсы: Examples/budget-keeper/readme.md: Локальный runnable-пример с полными скриптами compile.py, simulate.py, inspect.py и сценариями отказа

Book/part-04-environment.md: Выбор одной модели в учебном AgentClinic — контраст с ярусной маршрутизацией production

Book/part-14-build-your-own-workflow.md: Проектные навыки и хуки — куда удобно ложится маршрутизация

Book/part-15-agent-replaceability.md: Заменяемость агента — предпосылка для переключения между ярусами

Appendix-d-threshold-calibration.md#d3-ярусные-бюджеты-глава-9: Полный трек калибровки: таблица «Низкий / По умолчанию / Высокий» для бюджета, пропорций и manual_timeout_sec

Examples/goodhart-validator/scripts/run validation.py: Запускаемый аналог anti-Goodhart-проверок из главы 10

Book2/examples/budget-keeper/specs/budget network 5m.yaml: Калибровочный вариант для упражнения со сжатым бюджетом

Резюме: Маршрутизация моделей и бюджет токенов превращает статический лимит в управляемый контур: фазы SDD → ярусирование моделей → SLA-пороги → ранжированное переключение при отказе → anti-Goodhart-валидация. Дешёвый local-coder обрабатывает рутину, дорогой frontier-reviewer защищает спорные и критичные случаи. При отказе дешёвого яруса ключевое правило: не пускать всю очередь автоматически на дорогой ярус. Runnable-примеры (compile, simulate, inspect) позволяют проверить это правило на сценариях 15 и 45 минут, зафиксировать результаты в budget-note.md и связать с capstone-проектом. Успешное прохождение: четыре условия inspect выполнены одновременно, token_health_min выше порога, guard-сторож готов к production, anti-Goodhart-шлюз блокирует искажение метрик.

Мои заметки
0 / 10000

Заметки сохраняются в этом браузере. На другом устройстве они не появятся.

Меню курса

Курс

Production SDD для Qwen Code CLI. Часть 2
Прогресс 0 / 100