← Context engineering: beyond the prompt
02 / 07 · 50 min

The context window as a budget

Tokens, input pricing, KV-cache, and lost-in-the-middle: learn to allocate the window across budget lines and protect a stable prefix.

Lesson content is currently available in Russian.

What you will learn

  • →Считать стоимость контекста в деньгах и понимать квадратичный рост расходов в диалоге.
  • →Строить cache-friendly раскладку запроса: стабильный префикс, append-only история.
  • →Задавать явный токен-бюджет по статьям и триггер компакции.

Окно, токены и цена ввода

Начнём с цифр. Типичные окна: 128 тысяч токенов у GPT-4o, 200 тысяч у моделей Claude (с расширением до миллиона в бета-режиме), больше миллиона у Gemini. Цена ввода для модели класса Claude Sonnet — порядка 3 долларов за миллион токенов, вывод — 15 долларов за миллион. Один вызов с контекстом в 150 тысяч токенов стоит около 45 центов только за ввод. Агент, делающий 50 шагов за сессию с таким контекстом, без оптимизаций сожжёт больше 20 долларов за одну задачу.

Главная ловушка — квадратичный рост в multi-turn. История отправляется заново на каждом ходу, поэтому суммарный расход токенов за диалог растёт примерно как n²/2 от числа ходов: сотый ход диалога оплачивает все девяносто девять предыдущих. Ровно поэтому окно нужно воспринимать не как бесплатное хранилище, а как арендуемую площадь с почасовой оплатой.

Вторая валюта, кроме денег, — внимание. Каждый токен в окне конкурирует за ограниченный «бюджет внимания» модели, и лишние токены оплачиваются дважды: сначала деньгами, потом деградацией качества. Хороший ориентир: рабочее заполнение окна в 40–60 процентов почти всегда даёт лучшие результаты, чем 90 процентов, — и оставляет запас под вывод и непредвиденно длинные результаты инструментов.

KV-cache: почему префикс должен быть стабильным

При инференсе модель вычисляет для каждого токена префикса пары «ключ-значение» (KV). Если начало запроса байт в байт совпадает с предыдущим, провайдер может переиспользовать уже вычисленный KV-cache вместо пересчёта. Это и есть prompt caching: у Anthropic запись в кэш стоит ×1,25 базовой цены, а чтение — ×0,1 (для Sonnet: 3 доллара за миллион превращаются в 30 центов), TTL — 5 минут с продлением при каждом попадании, опционально до часа. OpenAI кэширует автоматически префиксы от 1024 токенов со скидкой на кэшированную часть.

Ключевое правило: кэш инвалидируется с первого изменённого токена. Один timestamp в начале системного промпта — и весь кэш мёртв на каждом запросе. Отсюда каноническая раскладка:

1. системный промпт (стабильный)          — кэшируется
2. определения инструментов (стабильные)  — кэшируются
3. память и справка проекта (меняются редко)
4. история диалога (append-only, только дописываем)
5. текущий запрос и свежие данные (меняются всегда)

Практические следствия: не перестраивайте и не пересортировывайте список инструментов между запросами; не редактируйте старые сообщения истории — только дописывайте новые; всё динамическое (время, флаги, свежий retrieval) кладите как можно ниже. Разница между 10-процентной и 90-процентной долей кэш-попаданий на длинных агентных сессиях — это буквально порядок в счёте за API.

Lost in the middle и раскладка окна

Работа Liu et al. «Lost in the Middle» измерила точность модели в зависимости от позиции релевантного документа среди двадцати переданных. Кривая получилась U-образной: модель отлично использует информацию в начале и в конце окна и заметно проседает, когда ответ спрятан в середине. В экспериментах падение достигало десятков процентных пунктов — при том, что документ физически находился в контексте.

Из этого следуют конкретные правила упаковки. Первое: длинные материалы (документы, выгрузки, код) размещайте в верхней части запроса, а инструкцию и сам вопрос — в конце, после данных; на длинных входах это устойчиво улучшает качество, и это официальная рекомендация Anthropic для длинного контекста. Второе: критические инварианты («не трогай ветку main», «отвечай только по документам») дублируйте у нижнего края окна — это зона свежего внимания. Третье: порядок извлечённых чанков имеет значение — самые релевантные ставьте первыми или последними, а не в середину пачки.

И помните про взаимодействие с кэшем: правила раскладки применяются внутри динамической части запроса. Стабильный префикс не трогаем ради позиционных трюков — экономика кэша почти всегда важнее, чем идеальная позиция одного фрагмента.

Бюджет в явном виде

Пока бюджет существует «в голове», он не соблюдается. Зафиксируйте его конфигом и проверяйте кодом перед каждым запросом:

{
  "window": 200000,
  "reserved_output": 8000,
  "budget": {
    "system": 2000,
    "tools": 12000,
    "memory": 6000,
    "retrieval": 40000,
    "history": 90000
  },
  "compact_at": 0.8
}

Считать токены можно локально токенизатором (tiktoken для моделей OpenAI, count_tokens API у Anthropic) или брать фактический usage из ответа API и сверять с планом. При превышении статьи действуйте по приоритету: сначала режется retrieval (берём меньше чанков), затем чистятся старые результаты инструментов, затем компактится история; системный промпт и инварианты не режутся никогда.

Поле reserved_output — обязательный резерв: если заполнить окно под завязку, модели негде писать ответ, и вы получите обрезанный вывод в самый неподходящий момент. Порог compact_at в 80 процентов запускает компакцию заранее, а не в момент переполнения, когда уже поздно выбирать, что терять. Такой конфиг превращает расплывчатое «следим за контекстом» в проверяемый инвариант системы — и одновременно даёт метрики: доля каждой статьи в реальных запросах покажет, где бюджет расходится с планом.

Practice

Токен-бюджет для своего агента

Составьте конфиг бюджета для реального агента и внедрите проверку перед каждым запросом: подсчёт токенов по статьям, предупреждение при превышении, порог компакции 80%. Прогоните одну длинную сессию до и после.

Deliverable

Конфиг бюджета, код проверки и сравнение двух сессий: суммарные токены, стоимость, доля кэш-попаданий до и после внедрения бюджета.

Checkpoint

Спроектируйте раскладку запроса для агента поддержки с 15 инструментами и объясните, какие блоки кэшируются и почему история должна быть append-only.

  • ✓ Стабильные блоки (системный промпт, инструменты) стоят первыми, динамика — в конце.
  • ✓ Объяснено, что кэш инвалидируется с первого изменённого токена, поэтому старые сообщения не редактируются.
  • ✓ Назван резерв под вывод и порог компакции до фактического переполнения.

Check yourself

Во сколько обходится чтение из кэша у Anthropic относительно базовой цены ввода?

01Во сколько обходится чтение из кэша у Anthropic относительно базовой цены ввода?

Что инвалидирует prompt cache?

02Что инвалидирует prompt cache?

Где, согласно «Lost in the Middle», модель хуже всего использует информацию?

03Где, согласно «Lost in the Middle», модель хуже всего использует информацию?

Почему суммарный расход токенов в multi-turn диалоге растёт квадратично?

04Почему суммарный расход токенов в multi-turn диалоге растёт квадратично?

Что должно происходить при достижении порога compact_at = 0.8?

05Что должно происходить при достижении порога compact_at = 0.8?

Sources

The context window as a budget · Context engineering: beyond the prompt · VORCL