Содержание
- Reasoning effort: три рычага и четыре режима
- Кривая overthinking: три региона
- Пятислойная защита: бюджет — это не экономия, это стабильность
- AI-метрики: что мерить вместо RPS
- Каскадный роутинг и budget-aware эскалация
- Architect/Editor split: архитектура экономии
- Контекст как переменная стоимости
- Итог
- FAQ
- Источники
Один и тот же агент отвечает на три запроса. На первом он делает единственный вызов модели и обходится в шесть центов. На втором разворачивает цепочку рассуждений, дёргает пару инструментов и стоит уже несколько долларов. На третьем упирается в ошибку инструмента, уходит в повторы и набирает больше полутора сотен долларов за один запрос. Код между этими тремя случаями не менялся ни строкой, а цена разъехалась в две с половиной тысячи раз.
Разъезжаются три настройки: какая модель отвечает, насколько глубоко ей разрешено думать и сколько шагов позволено сделать. Со второй из них произошла показательная история. Ещё пару лет назад глубину рассуждения выпрашивали словами — «думай шаг за шагом», «разбери по пунктам», — а в 2026 году это параметр API с четырьмя-пятью уровнями, и выставляется он одной строчкой в конфиге. Удобство обернулось привычкой: раз параметр допускает больше, поставим больше, качество ведь важнее. Вот только думает модель не бесплатно. Рассуждение она пишет отдельным куском текста, который вам не показывают, а токены этого куска выставляют в счёт целиком, даже если в ответ из них не ушло ни слова.
И это ещё полбеды. Кривая «больше думаешь — точнее отвечаешь» немонотонна. После некоторого бюджета точность перестаёт расти, а дальше начинает падать. Посмотрим, где проходят обе границы, как померить своё положение на этой кривой и чем ограничить расход, пока он не всплыл в отчёте за квартал.
Дневник курса, урок 2. Пригодится разобранное в соседних постах: что считать агентом и как выбирают модель (урок 1) — откуда в счёте берётся множитель, которого нет у обычного сервиса; схема как контракт вместо просьбы в промпте (урок 4) — так дешёвая модель возвращает свою уверенность в машиночитаемом виде; разбор счёта за модели по слоям — во что описанные здесь приёмы обходятся в деньгах. Пост читается отдельно: все термины вводятся заново.
1. Reasoning effort: три рычага и четыре режима
Прототип ассистента поддержки собирается за неделю, и на этапе «пусть отвечает хорошо» в конфиг попадает максимальная глубина рассуждения. Через месяц выясняется, что половина обращений выглядит как «где мой заказ», и на каждое такое обращение модель сначала пишет полстраницы внутренних размышлений о том, что пользователь, вероятно, интересуется статусом доставки. Ответ при этом ничем не отличается от того, который получился бы без размышлений вовсе.
Управляемая глубина мышления модели называется reasoning effort (усилие рассуждения). Вопрос при настройке звучит не «какая модель умнее», а «какое усилие нужно вот на этой конкретной задаче». Мышление — ресурс наравне с памятью и квотой запросов, и держать его на дефолте примерно так же осмотрительно, как не трогать размер пула соединений.
По глубине задачи раскладываются на четыре режима, и каждая ступень обходится в 2–5 раз дороже предыдущей. Кратность берётся не из тарифа. Цена токена та же самая, просто на каждой следующей ступени скрытое рассуждение длиннее. С сотен токенов на второй ступени оно уходит на тысячи и десятки тысяч на четвёртой, а платите вы ровно за них.
- Reflexive — прямой ответ без рассуждения: «Как тебя зовут?»
- Standard — промпт и один вызов, без extended thinking (расширенное обдумывание — отдельная фаза, в которой модель пишет рассуждение до видимого ответа).
- Deliberate — Chain-of-Thought (цепочка рассуждений) до пяти шагов: разобрать условие, сравнить варианты, выбрать.
- Exhaustive — много итераций с reflection (перечитать собственный вывод) и self-correction (переписать найденную у себя ошибку): сложный код, многошаговый reasoning.
Шаг между ступенями важнее самих названий. Поднять задачу на ступень выше — это не «немного дороже», это другой порядок счёта, и на трафике в десятки тысяч запросов разрыв между второй ступенью и четвёртой перестаёт быть строчкой в отчёте.
Эмпирика при этом невесёлая для тех, кто выкрутил всё вверх. Высокое усилие оправдано только на меньшей части задач — оценочно на одной из пяти. Пропорцию стоит держать в голове как ориентир, а не как измеренную константу, потому что зависит она от того, чем именно занят ваш агент. На остальных четырёх глубокий reasoning жжёт бюджет и latency, ничего не добавляя к точности.
Усилие регулируется тремя независимыми рычагами, и путают их постоянно:
- Модель. Линейку каждого вендора удобно разложить на ценовые тиры: Tier 1 — младшие быстрые модели (mini, Haiku), Tier 3 — флагманы (Opus, GPT-5), между ними средний класс. Разница цены между крайними тирами — около 5× по актуальным прайсам обоих вендоров. Кратность в 15× встречается в старых разборах, но она была верна для Opus 4.1, который в следующих версиях подешевел.
- Глубина reasoning — параметр API:
reasoning_effortу OpenAI,budget_tokensилиeffortу Anthropic,thinkingLevel/thinkingBudgetу Gemini, Dual Mode у DeepSeek. - Число шагов —
max_iterationsв петле плюс early stopping (ранняя остановка) при достижении цели.
Рычаги независимы, поэтому и крутить их надо по отдельности. Дорогая модель на минимальном усилии и дешёвая на максимальном — это две разные точки, а не одна и та же «средняя настройка». Упираются они в разное. Первую ограничивает цена токена, вторую их количество.
Одна привычка из эпохи GPT-3.5 при этом умерла. Фразу «думай шаг за шагом» в промпт писать больше незачем. Делиберация встроена в сэмплер модели и включается параметром, а слова в запросе дублируют её текстом и занимают контекстное окно, за которое вы платите.
Текущая раскладка API на флагманах:
| Provider | API-параметр | Уровни | Default |
|---|---|---|---|
| OpenAI | reasoning_effort |
none / low / medium / high | none (GPT-5.1) |
| Anthropic | budget_tokens, effort |
low / medium / high / xhigh / max | off (Opus 4.7, требует явной активации) |
thinkingLevel, thinkingBudget |
токены бюджета, уровни задержки | встроенное (рекоменд. =0 для чата) | |
| DeepSeek | Streamed Trace, Dual Mode | Non-Think / High / Max | thinking on |
Обратите внимание на колонку значений по умолчанию. Провайдеры расходятся принципиально. У OpenAI и Anthropic глубокое мышление нужно включить руками, а у Gemini и DeepSeek оно работает, пока его не выключили. Переносить конфиг между провайдерами «как есть» из-за этого нельзя, ведь один и тот же код на двух API даст разный счёт.
Минимальный пример активации extended thinking у Anthropic:
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-7",
max_tokens=8192,
thinking={"type": "enabled", "budget_tokens": 4096},
messages=[{"role": "user", "content": "..."}],
)
Смысл здесь в budget_tokens. Он ограничивает скрытый reasoning-трейс отдельно от итогового ответа, и эти токены вам выставят в счёт, даже если в ответ не попало ни слова из размышлений. Поднимают его под конкретный профиль задачи, а не по принципу «раз параметр допускает больше, поставим больше».
2. Кривая overthinking: три региона
Интуиция подсказывает, что зависимость точности от объёма test-time compute (вычислений на этапе вывода) монотонна. Дал модели больше подумать — получил ответ не хуже прежнего. Замеры эту интуицию не подтверждают. На кривой три характерных региона, и третий устроен так, что прибавка бюджета делает результат хуже.
accuracy
▲
│ ╭─────╮
│ ╱ ╲ ◄── inversion: точность падает
│ ╱ ╲ (overthinking, доменно-специфично)
│ ╱ ╲
│ ╱
│ ╱ ◄── token-burning: точность ровно,
│ ╱ цена и latency растут
│╱
│ ◄── high-yield: +5–10% качества окупают токены
│
└─────────────────────────────────────► thinking budgetHigh-yield — участок, ради которого глубокое мышление и придумали: сложный код уровня SWE-bench, аудит многопоточного, оптимизация SQL, доказательство теорем, ветвящиеся планы с жёсткими ограничениями. Общее у этих задач одно — решение нужно вывести, а не вспомнить, и промежуточные шаги реально сокращают пространство перебора. Здесь effort: high или максимальный budget_tokens окупают деньги приростом в 5–10%.
Token-burning — извлечение JSON-сущностей, классификация интента, заполнение шаблонов, саммаризация. Выводить тут нечего, ведь ответ содержится во входных данных и модели остаётся его достать. Глубокое мышление на такой задаче генерирует сотни пустых рассуждений. Счёт-фактура порождает абзац о том, считать ли «Итого» суммой с НДС, после чего в поле уходит ровно то число, которое ушло бы и без абзаца. Точность та же, счёт выше.
Inversion — режим, описанный в «When More Thinking Hurts» (см. обзор эффекта): при чрезмерном бюджете модель начинает сомневаться в очевидном, ломает синтаксически верные конструкции, уходит в избыточное усложнение. На зафиксированных тестах точность падала с 49.6% до 48.1%, стоимость росла на 56%, latency — критически.
Разворот кривой перестаёт выглядеть парадоксом, если посмотреть, куда девается написанное в трейсе. Рассуждение — это те же токены, и каждый следующий генерируется с оглядкой на все предыдущие. Сомнение, однажды записанное в трейс, дальше неотличимо от обоснованного соображения. Модель не помнит, что усомнилась она от избытка бюджета, а не от найденной проблемы. Чем длиннее трейс, тем больше в нём шансов записать неудачный поворот и тем на большем объёме собственных догадок строится финальный ответ. Работающий запрос переписывается «для надёжности», корректная конструкция признаётся подозрительной, простое решение уступает разветвлённому.
Вывод получается контринтуитивный. На простой задаче глубокий reasoning вредит, и вред тут не сводится к счёту. Платите вы токенами и вероятностью испортить ответ, который на минимальном усилии вышел бы верным. Граница между регионами доменно-специфична, так что своё положение порога придётся мерить на своих задачах.
По той же причине осторожнее с self-reflection. Самокоррекция полезна ровно настолько, насколько модель умеет отличить свою ошибку от своей же удачной догадки; у слабых моделей это различение работает плохо, и рефлексия нередко усугубляет ошибку вместо того, чтобы её убрать. Включать осознанно, как и любой глубокий режим.
3. Пятислойная защита: бюджет — это не экономия, это стабильность
В понедельник у провайдера тихо поменялось имя поля в ответе API. Парсер агента ждёт прежнее, получает исключение, агент честно пробует исправиться и вызывает инструмент заново — с полной историей предыдущих попыток в контексте. Через сорок минут в счёте двухсоткратный расход токенов, а на дашборде ничего. CPU и RAM в норме, процесс жив, HTTP отвечает.
Runaway agent (зацикленный агент) в подавляющем большинстве случаев рождается вот так, из обычного бага, а не из атаки. Классический Prometheus такое не ловит по устройству. Он измеряет здоровье процесса, а больной здесь не процесс, а его поведение.
Насколько крупными бывают такие счета? Возьмём три случая разного масштаба:
- Развёртывание Claude Code в Uber: 95% инженеров подхватили инструмент, индивидуальные счета $500–2000 в месяц на разработчика. Годовой бюджет на AI-ассистентов исчерпан за 4 месяца.
- В малом сегменте — case из LangChain-комьюнити: отсутствие
max_iterationsв цикле ресерча → бесконечные проходы валидации → более $150 за решение одной задачи через o1-preview. - В корпоративе — несколько тысяч долларов за выходные из-за рекурсивной обработки ошибок в фоновом воркере.
Два крайних кейса стоит развести. Uber — не авария. Инструмент оказался полезен, люди им пользовались, деньги ушли на работу. Второй случай — именно авария, и обошлась она в сумму, которую увидели сразу. Опаснее для бюджета всё-таки первый сценарий, потому что аварию чинят в тот же день, а планомерный перерасход обнаруживают в конце квартала.
Ограничители ставят в пять независимых слоёв. Нужны все одновременно, потому что каждый ловит то, что пропустил предыдущий. На схеме второй слой привязан к ReAct, базовой петле агента, где рассуждение и действие чередуются. Модель пишет мысль, вызывает инструмент, читает результат, пишет следующую мысль. Итерации в такой петле есть где считать, ведь каждый оборот виден рантайму.
запрос
│
▼
┌──────────────────┐ agentic-сессия живёт 5–20 минут;
│ 1. Timeout │ NGINX/ALB/Ingress режут на 30–300 сек.
└────────┬─────────┘ Лечение: async queue, background worker,
│ hard-limit времени у планировщика.
▼
┌──────────────────┐ max_iterations = 10–15 в ReAct;
│ 2. Anti-loop │ max 3 попытки исправить одну ошибку;
└────────┬─────────┘ стоп-условие "No Progress" наряду с лимитами.
│
▼
┌──────────────────┐ Шлюз (Portkey, LiteLLM, MLflow Gateway)
│ 3. Cost Circuit │ считает $ в реальном времени.
│ Breaker │ Пороги: $50 warning / $100 halt,
└────────┬─────────┘ per-task ≈ $5.
│
▼
┌──────────────────┐ Никаких алиасов gpt-4o или claude-3-5-sonnet —
│ 4. Model │ только фиксированные версии (gpt-4o-2024-05-13).
│ Pinning │ Тихое обновление модели у провайдера
└────────┬─────────┘ ломает парсеры → бесконечный цикл валидации.
│
▼
┌──────────────────┐ OpenTelemetry-атрибуты:
│ 5. Audit Log │ gen_ai.usage.input_tokens,
└──────────────────┘ gen_ai.usage.output_tokens, session_id.Слои выглядят избыточными ровно до первого разбора инцидента. Пройдём по ним с той же поломкой парсера. Первый слой её не поймает вовсе. Агентская сессия живёт 5–20 минут, синхронный HTTP её не держит, поэтому выполнение и так вынесено в фоновый воркер, а у воркера дедлайн свой и обычно щедрый. Срабатывает первым второй. Три попытки исправить одну и ту же ошибку, и агент останавливается принудительно, что бы ни думала об этом модель. Если петля устроена хитрее и каждый проход формально считается новой ошибкой, счётчик итераций молчит. Тогда включается третий слой, который считает не события, а деньги, и ему всё равно, как называется цикл. Четвёртый слой относится к причине. Тихое обновление модели за алиасом gpt-4o меняет формат генерации, и парсер ломается ровно так же, как от смены поля в чужом API. Пятый ничего не останавливает, зато без него вы узнаете о случившемся из счёта, а не из трейса, и не сможете сказать, какая именно сессия его набрала.
У второго слоя роль шире, чем обычно думают. max_iterations выглядит страховкой от зависания, а работает ещё и ограничителем расхода. Каждый следующий оборот петли отправляет в модель всю накопленную историю целиком, поэтому десятый шаг обходится не как первый, а в разы дороже — счёт растёт быстрее, чем число шагов. Насколько быстрее и что с этим делают, разберём дальше, в разделе про контекст как переменную стоимости.
Бюджетные уровни как стартовые: задача ~$0.50 / сессия ~$2 / день ~$10. Дальше калибровать по своему профилю нагрузки.
Есть и неприятная новость про сами ограничители. В Issue #7554 у LangGraph в RetryPolicy jitter (случайная добавка к паузе, чтобы повторы клиентов не сходились в один момент) прибавлялся после ограничителя max_interval, и фактическое ожидание уходило выше декларированного лимита. Баг мелкий, зато вывод общий. Backoff-логика (отступы между повторами) — это код, и тестировать её надо как код, а не считать частью фреймворка, которая работает по определению.
4. AI-метрики: что мерить вместо RPS
Дежурный смотрит на дашборд: RPS ровный, p99 в норме, пятисоток нет. Агент при этом третий день ходит по одному и тому же кругу и тратит на средний запрос втрое больше, чем неделю назад. Классический мониторинг stateless. Он видит отдельные HTTP-вызовы, а прикладная задача агента размазана по десяткам разнородных обращений к разным моделям и в его картину мира не помещается.
Нам понадобится другой набор показателей, и снимать его лучше на шлюзе:
tokens_per_task— суммарные токены на одну прикладную задачу, включая скрытые токены reasoning.cost_per_completion— итоговая стоимость сессии:(I × P_in + O × P_out) / 1_000_000, гдеIиO— число входных и выходных токенов, аP_inиP_out— их цены за миллион. Считать вход и выход раздельно обязательно, потому что тарифы на них отличаются кратно и усреднённая «цена токена» врёт тем сильнее, чем болтливее агент.loop_iterations— число итераций цикла. Рост при неизменной точности = деградация планирования.retry_overhead_tokens— токены, сожжённые на повторные вызовы при ошибках парсинга и валидации. Прокси к качеству системного промпта и стабильности парсеров.
Пары метрик здесь работают лучше, чем каждая по отдельности. loop_iterations сам по себе ни о чём не говорит — сложная задача честно требует больше шагов. А вот рост итераций при неизменной доле успешно закрытых задач означает, что планирование поехало. Агент делает больше работы за тот же результат. Так же читается и retry_overhead_tokens. Его рост почти всегда указывает не на модель, а на промпт или парсер, которые перестали договариваться между собой.
Алерт — при 2× от baseline по любой из метрик, не по абсолюту. Абсолютный порог придётся переписывать после каждого релиза, а кратность к собственной норме переживает и смену модели, и рост трафика.
Собирать телеметрию удобнее на шлюзе (Portkey, LiteLLM, MLflow Gateway), а не внутри агента, и причина не в удобстве. Шлюз видит все вызовы — включая ретраи и переключения на резервную модель, которых код агента о себе не знает, — и аннотирует их одним session_id. Атрибуты OpenTelemetry gen_ai.usage.input_tokens и gen_ai.usage.output_tokens вместе с этим идентификатором дают сквозную трассировку одной агентской задачи поверх десятков гетерогенных LLM-вызовов.
Есть и побочная выгода. Когда retry-логика переезжает на шлюз, сетевые сбои перестают смешиваться с логикой агента. Без такой развязки сбой одного терминального узла-исполнителя вызывает веерные повторы у всех вышестоящих оркестраторов — каскадный retry-шторм, при котором retry_overhead_tokens растёт взрывообразно, а исходная поломка тонет среди сотен производных.
При достижении критических лимитов агент должен делать early stopping, а не hard error (жёсткое падение). Разница здесь не стилистическая. Контролируемая остановка сохраняет историю сессии, и оператор смотрит, где всё пошло не так, правит промпт и продолжает с последнего валидного шага. Жёсткое падение уничтожает прогресс, а заодно провоцирует ту же самую retry-петлю, только теперь снаружи, где её ограничивать уже нечем.
5. Каскадный роутинг и budget-aware эскалация
Выбор модели обычно обсуждают как разовое решение. Сравнили по бенчмаркам, взяли лучшую, поехали. Дальше «который час?» и «напиши алгоритм упаковки» уходят в один и тот же дорогой эндпоинт и стоят одинаково, притом что на первом запросе флагман не может быть точнее дешёвой модели, ведь потолок задан самой задачей.
Отсюда и превосходство роутинга над выбором одной модели. Одна модель — это одна точка на кривой «цена/качество», и платите вы по самому сложному запросу из потока, хотя сложность в потоке распределена крайне неравномерно. Роутер превращает разовое решение в поштучное. Он оценивает сложность запроса и подбирает исполнителя под неё. На правильно настроенном каскаде основная часть трафика уходит на дешёвую модель, а качество держится близко к флагману.
запрос
│
▼
┌──────────────────┐ hit → ответ из кэша, cost = 0
│ 1. Семантический │ miss ↓
│ кэш (<5 мс) │
└────────┬─────────┘
│
▼
┌──────────────────┐ simple → cheap-модель сразу
│ 2. Классификатор │ (Haiku 4.5, GPT-4o-mini)
│ интента ~0.5B,│ complex → дорогая модель reasoning
│ vLLM (<5 мс) │ ambiguous ↓
└────────┬─────────┘
│
▼
┌──────────────────┐ confidence ≥ порога (≈ 0.85) → отдать
│ 3. Cheap-модель +│ confidence < порога → escalation
│ confidence │
│ score │
└──────────────────┘Пройдём по этажам каскада. Выстроены они по возрастанию цены ошибки, и первые два стоят почти ничего. Семантический кэш и классификатор на 0.5B параметров укладываются в единицы миллисекунд каждый, то есть дешевле сетевого round-trip до провайдера. Третий этаж интереснее. Дешёвая модель отвечает и вместе с ответом возвращает собственную уверенность, и уже эта цифра решает, отдавать результат или поднимать запрос выше.
Порог confidence (старт ≈ 0.85) калибруется на 100–200 реальных запросах. Саму уверенность получают через structured output — модель обязана вернуть {answer, confidence, reason}, а не приписку в свободной форме. «На глаз» порог не ставят. Слишком высокий отправляет наверх всё подряд и убивает экономию, слишком низкий пропускает плохие ответы к пользователю. Оценивают либо LLM-judge, либо ручной разметкой.
Ручная разметка при этом дорога и стареет вместе с трафиком. Есть альтернатива. Суррогатный классификатор обучают на traces работы флагмана, и приём этот называется tracer-based routing. Активируют его через parity gate: суррогат пускают в прод только тогда, когда его согласие с моделью-учителем на тестовой выборке превышает порог α. Логика здесь та же, что у канареечного релиза. Новый компонент получает трафик не по решению автора, а по измеренному совпадению со старым. На опубликованных результатах — до 85% рутинного трафика уходит на дешёвые локальные модели при сохранении 95% качества и общем снижении затрат на 70% (разбор LLM-routing).
Здесь каскад разбирается как способ не переплачивать за глубину рассуждения там, где хватает младшей модели. Вопрос «сколько он экономит на самом деле» отдельный, и ответ на него неприятный. Проценты вроде этих семидесяти посчитаны по цене одного вызова, а дешёвая модель на трудной задаче отвечает не одним вызовом, а пятью-семью. Она ошибается в аргументах инструмента, читает ошибку, переписывает план, и каждый виток заново тащит на вход весь накопленный контекст. Полная цена каскада вместе с этими повторами считается в уроке 15.
Роутеров в проде обычно два, и это разные оси, которые часто путают. Первый — экономический каскад по confidence, тот самый, что на схеме. Дешёвая модель отвечает, при низкой уверенности запрос эскалируется. Он про деньги. Второй — Intent / Task Router. Он классифицирует тип запроса («объясни термин», «дай план», «сделай отчёт», «найди в документах») и выбирает сценарий, шаблон и источник контекста, а не модель. Он про поведение. Заодно этот же роутер работает как guardrail (защитный фильтр) и отсекает вредные запросы вместе с prompt injection (инъекция в промпт — попытка подменить инструкции агента через пользовательский ввод) до того, как они дойдут до «мозга». Фильтровать на входе дешевле, чем разбирать последствия на выходе.
Поверх обоих ложится Budget-Aware Agentic Routing (BAAR) — маршрутизация под бюджет, рассматриваемая как последовательная задача принятия решений, где ошибки на ранних шагах лавинообразно накапливаются. Формулировка звучит академично, зато следствие вполне осязаемо. Решение «взять модель подороже» на первом шаге отнимает бюджет у всех последующих, а сколько их будет, заранее неизвестно. На практике это выражается в двух порогах:
- остаток бюджета <30% — шлюз форсит cheap-модель и перестраивает план декомпозиции в сторону минимизации шагов;
- остаток <10% — пропускаются только simple-запросы, остальное — controlled stop.
Второй порог интереснее первого. На исходе бюджета агент отказывается от работы, которую не сможет доделать, вместо того чтобы потратить остаток на половину сложной задачи и встать посередине.
Здесь три механизма сходятся в одну схему. Глубина рассуждения, лимиты и роутинг по отдельности дают проценты; вместе — управляемую цену запроса.
┌───────────────────────────────────┐
┌──▶ │ SIMPLE │──┐
│ │ дешёвая модель · effort = low │ │
│ │ max_iterations = 3 · бюджет $0.05 │ │
запрос ─▶ РОУТЕР └───────────────────────────────────┘ ├─▶ БЮДЖЕТ-МОНИТОР ─▶ ответ
оценка ┌───────────────────────────────────┐ │ circuit breaker
сложности│ COMPLEX │ │
└──▶ │ дорогая модель · effort = high │──┘
│ max_iterations = 10 · бюджет $0.50│
└───────────────────────────────────┘effort: low, лимит в 3 итерации, бюджет $0.05; сложный — дорогая модель, effort: high, 10 итераций, бюджет $0.50. Обе ветки сходятся на бюджет-мониторе с circuit breaker, и только после него ответ уходит пользователю.Смотреть тут надо на то, что именно выставляет роутер. Он выставляет весь профиль исполнения сразу: модель, глубину рассуждения, потолок итераций и денежный лимит одним пакетом. Выбор модели здесь только один пункт из четырёх, и держать эти четыре ручки порознь бессмысленно. Дешёвая модель с effort: high и десятью итерациями обойдётся дороже дорогой модели с одним проходом; дорогая модель с лимитом в три шага не доведёт до конца задачу, ради которой её и позвали. Смысл появляется у сочетаний, и сочетаний ровно столько, сколько у вас классов запросов.
Circuit breaker при этом стоит не внутри веток, а поверх обеих. Причина простая: ошибиться классификацией роутер может в любую сторону, и профиль, выбранный неверно, — это ровно тот случай, когда лимиты внутри профиля не сработают. Простой запрос, ушедший по сложной ветке, честно выберет свои десять итераций и свои полдоллара, ни разу не превысив ни одного лимита. Заметит это только счётчик, который смотрит на деньги поверх маршрута.
6. Architect/Editor split: архитектура экономии
Настройка effort и порогов даёт проценты. Кратную экономию даёт другой ход. Роли разносят по моделям разного класса: планирование отдельно, исполнение отдельно.
В уроке 1 это разделение отвечало на вопрос «какую модель брать». Модели подбирают на роли, а не на всю систему целиком. Здесь вопрос другой. Сколько именно приносит разнос ролей и за счёт какой механики, если не ограничиваться формулой «дорогая думает, дешёвая печатает»?
┌──────────────────┐ short JSON ┌──────────────────┐
│ Architect │ ─── plan ───▶ │ Editor │
│ дорогая «умная» │ │ дешёвая быстрая │
│ (Opus, GPT-5.1) │ │ (Haiku, mini) │
│ │ │ │
│ ► один раз │ │ ► каждый шаг, │
│ ► разворачивает │ │ свежее окно │
│ план в JSON │ │ ► читает прогресс│
│ ► passes: false │ │ ► пишет passes: │
│ для подзадач │ │ true в Git │
└──────────────────┘ └──────────────────┘Посмотрим, как это разложено в исследованиях Anthropic. Профилей два:
- Initializer Agent (агент-инициализатор) запускается один раз: разворачивает окружение, создаёт
claude-progress.txt,init.sh, формирует JSON-файл требований, где каждой атомарной подзадаче проставлен флаг"passes": false. - Coding Agent (агент-исполнитель) запускается на каждом шаге в свежем контекстном окне: читает прогресс, выбирает подзадачу с
false, выполняет, тестирует, переключает вtrue, коммитит в Git.
Выбор JSON вместо markdown — не вкусовщина. Модели работают со схемами точнее и реже случайно перезаписывают смежные ветки, а список задач в свободной форме легко превращается под правкой в список, где две соседние строки описывают одно и то же. Флаг "passes" при этом делает состояние работы внешним по отношению к модели. Исполнителю не нужно помнить, что сделано, он это читает. Поэтому каждый его запуск и умещается в свежее окно, а история сессии не тащится за ним из шага в шаг.
Экономия — 50–80% бюджета, причём качество часто выше, потому что «редактор» не отвлекается на архитектуру. Дорогая модель тратится один раз на то, что действительно требует глубины, дешёвая делает много мелкой работы, каждая единица которой умещается в одну ясную инструкцию.
7. Контекст как переменная стоимости
Первые шаги агента идут быстро и дёшево, а к двадцатому каждый ответ приходит заметно медленнее и обходится заметно дороже, хотя делает агент ровно то же самое. Причина в том, что каждый шаг передаёт в модель всю накопленную историю сессии: свежий запрос плюс все прежние сообщения вместе с результатами вызванных инструментов. Стоимость от этого растёт квадратично относительно числа итераций, и борьба с контекстом становится борьбой с бюджетом.
Чем же резать контекст? Три стратегии динамического урезания, расставленные по риску потери информации:
| Стратегия | Механика | Применять когда | Риск |
|---|---|---|---|
| Compaction (саммаризация) | Саммаризация транскрипта, рестарт сессии с summary | Длинные аналитические сессии, обсуждения архитектуры | Потеря информации по дизайну: важная деталь может потеряться |
| Tool-Result Clearing (очистка результатов инструментов) | Хирургическое удаление содержимого tool_result, запись tool_use остаётся |
Частое чтение больших файлов, тяжёлые API | Практически безопасна — модель просто вызовет инструмент повторно |
| Structured Notes (внешние заметки) | Запись фактов во внешние файлы (claude-progress.txt) вне контекста |
Сверхдлинные сессии, распределённые по времени | Нужен бэкенд, инструменты чтения/записи |
Tool-Result Clearing — средний путь между compaction с её неизбежными потерями и полным сбросом контекста, и в разборах context engineering этот рычаг регулярно пропускают. Безопасен он благодаря одной детали. Удаляется содержимое результата, а запись о самом вызове остаётся. Модель видит, что файл был прочитан, и если содержимое понадобится снова, просто прочитает его заново. Compaction такой возможности не оставляет, ведь стёртая при саммаризации деталь не восстанавливается ничем. У правила «удалять безопаснее, чем пересказывать» с тех пор нашлась измеренная граница: для части задач сводка укладывается в строго меньший бюджет, чем любой отбор сообщений, и разбирается это в посте про сборку контекста (урок 14).
Третья строка таблицы — вход в отдельную тему. Внешние заметки это частный случай общего приёма: держать в контексте не сами данные, а короткий идентификатор, по которому их можно достать, и подтягивать содержимое только тогда, когда оно понадобилось. Разница бывает нелепо большой. В разборе агента-химика, который перебирал молекулы через специализированные научные базы, наивная передача полного контекста на каждом шаге дала 20 миллионов токенов на одну задачу; тот же агент, хранивший указатели вместо данных, уложился в 1 234 токена. Шестнадцать тысяч раз разницы дал простой отказ таскать за собой то, на что уже посмотрели. Как из этого вырастают полноценные типы памяти агента и чем эпизодическая память отличается от долговременной, разбирается в посте про команды агентов и их память (урок 8).
А сколько такие приёмы живут? Архитектурное правило звучит так: программная обвязка кодирует предположения о недостатках текущей модели, которые быстро устаревают по мере обновления моделей. Наглядный случай — Claude Sonnet 4.5 с «контекстной тревожностью». При приближении к лимиту окна модель начинала преждевременно сворачивать задачи и объявлять успех, ничего не протестировав. Под это в harness (программная обвязка вокруг модели: петля, инструменты, управление контекстом) добавили жёсткую логику context reset. С переходом на Opus 4.5/4.6 поведение исчезло на уровне весов, а логика сбросов осталась в коде и превратилась в технический долг, который теперь ещё и мешает.
Под масштабирование долгоживущих агентов в 2026 закрепилась трёхслойная архитектура Managed Agents, которая разводит эти вопросы по разным слоям:
- Brain — stateless LLM. Не хранит истории; восстанавливает контекст через
wake(sessionId)из внешней БД и выбирает нужный срез событий черезgetEvents(start, end). Отсюда и «стабильная утилизация prompt-кэша»: неизменная часть промпта остаётся неизменной, потому что историю в него больше не подмешивают целиком. - Hands — одноразовые песочницы (Docker, Python-интерпретатор) с минимальным интерфейсом
execute(name, input) → string. Сбой контейнера превращается в обычную ошибку инструмента, и оркестратор его переживает. - Session — персистентный append-only лог событий вне контекстного окна.
Метрики эффекта на проде: −60% по медианному TTFT (time to first token — время от запроса до первого токена ответа, то есть задержка, которую пользователь видит как «зависло») и более −90% по хвосту задержки. Обозначения p50 и p95 читаются как «половина запросов уложилась в это время» и «уложились 95%», и вторая величина как раз описывает те самые худшие случаи, на которые жалуются.
Эффект даёт ленивая инициализация песочниц. Тяжёлый контейнер поднимается в момент первого реального вызова инструмента, а не при старте сессии, поэтому хвост распределения проседает сильнее медианы: именно в хвосте и сидели сессии, ждавшие контейнер, который потом не понадобился. Паттерн уже воспроизведён вне лаборатории — те же три слоя ложатся на стек Azure AI Foundry, где Foundry Agent Service работает мозгом, Container Apps Dynamic Sessions руками, а Cosmos DB хранит лог сессии.
Итог
- Глубина reasoning — управляемый ресурс, а не «больше always better»: кривая немонотонна, и после порога начинается overthinking вплоть до inversion, где точность падает, а счёт растёт.
- Высокое усилие окупается примерно на одной задаче из пяти. На остальном —
effortминимальный, иначе токены и latency тратятся впустую. - Бюджет — это не про экономию, а про стабильность: runaway-агент возникает от обычного бага, и ловят его пятью независимыми слоями одновременно (timeout, anti-loop, cost circuit breaker, model pinning, audit log).
- Мерить нужно не RPS, а
tokens_per_task,cost_per_completion,loop_iterations,retry_overhead_tokensна шлюзе, с алертом на2×от baseline. Экономика держится на каскадном роутинге и разнесении ролей по моделям (Architect/Editor). - По отдельности три механизма дают проценты. Вместе они дают профиль исполнения — модель,
effort,max_iterationsи бюджет одним пакетом на класс запроса, — а circuit breaker считает деньги поверх обеих веток.
Вернёмся к трём запросам из начала. Шесть центов, несколько долларов и полторы сотни — это по-прежнему один и тот же код. Изменилось то, что каждая из трёх цифр больше не случается с вами, а назначается. Первую задаёт простой профиль, вторую — сложный, а третья попросту невозможна: на её пути стоят пять слоёв ограничителей и счётчик денег, которому всё равно, какой веткой пошёл запрос. Цена перестаёт быть свойством трафика и становится настройкой — той самой, которую до этого держали на дефолте.
FAQ
Когда повышать reasoning effort, а когда держать минимальным?
Высокое усилие окупается примерно на одной задаче из пяти, там, где есть верифицируемая глубина: сложный код, аудит многопоточного, оптимизация SQL, доказательства, ветвящиеся планы с жёсткими ограничениями. На извлечении сущностей, классификации, шаблонах и саммаризации глубокий reasoning жжёт токены и latency без прироста точности, а в режиме inversion даже снижает его.
Что такое overthinking и как его поймать?
Overthinking — это участок кривой, где рост test-time compute не помогает или вредит, потому что модель начинает сомневаться в очевидном и переусложнять. Ловится он по метрикам, когда tokens_per_task и loop_iterations растут при неизменной точности. Лечат его снижением budget_tokens и effort под профиль задачи, а ещё не включают self-reflection у слабых моделей, где она чаще усугубляет ошибку, чем исправляет.
Как защититься от runaway-агента?
Пятью независимыми слоями одновременно. Это timeout (async queue вместо синхронного запроса), anti-loop (max_iterations 10–15 плюс стоп «No Progress»), cost circuit breaker на шлюзе ($50 warning / $100 halt), model pinning (фиксированные версии вместо алиасов) и audit log (OpenTelemetry gen_ai.usage.* + session_id). Каждый слой ловит то, что пропустил предыдущий.
Какие метрики мерить у агента вместо RPS?
Классический stateless-мониторинг (RPS, latency, HTTP-ошибки) не видит распределённую транзакцию агента. Собирайте на шлюзе tokens_per_task (с учётом скрытого reasoning), cost_per_completion, loop_iterations и retry_overhead_tokens. Алертьте при 2× от baseline по любой из них, а не по абсолютному порогу.
Как связать роутинг, reasoning effort и бюджетные лимиты между собой?
Через профиль исполнения. Роутер выставляет не модель, а весь пакет сразу: модель, effort, max_iterations и денежный лимит. Рабочая стартовая раскладка — два профиля: простой (дешёвая модель, effort: low, 3 итерации, ~$0.05 на запрос) и сложный (дорогая модель, effort: high, 10 итераций, ~$0.50). Порознь эти ручки бессмысленны: дешёвая модель с высоким усилием и десятью итерациями выходит дороже дорогой модели с одним проходом. Circuit breaker ставится поверх обеих веток, потому что неверно выбранный профиль отработает все свои лимиты, ни одного не превысив.
Сколько закладывать в бюджет на задачу, сессию и день?
Стартовые порядки величины: задача ~$0.50, сессия ~$2, день ~$10; на уровне cost circuit breaker — $50 warning / $100 halt, per-task ≈ $5. Это калибровочные ориентиры, а не универсальные значения — подстраивайте под свой профиль нагрузки и набор моделей.
Источники
- Anthropic — Managed Agents: трёхслойная архитектура Brain/Hands/Session и метрики latency.
- LangGraph Issue #7554 — jitter поверх
max_intervalвRetryPolicy. - Кейсы runaway-стоимости: Uber — бюджет за 4 месяца, $150 за задачу на o1-preview.
- LLM routing: cut costs by 70% without losing quality — экономика каскадного роутинга.
- Turn the thinking knob off most of the time — обзор эффекта overthinking.
- Agent costs with MLflow Gateway — сбор token/cost-метрик на шлюзе.
Числовые ориентиры из текста (разница цены между tiers, 49.6%→48.1% при росте стоимости на 56%, бюджеты $0.5/$2/$10, −60% p50 / −90% p95) — это порядки величины и значения из конкретных кейсов; на вашем профиле нагрузки они будут другими.