Контекст: окно, компакция и что можно терять без ущерба
В модели исполнения мы разобрали цикл «наблюдение — действие»: агент вызывает инструмент, получает результат, дописывает его в контекст, решает, что делать дальше. Эта глава — про то, что происходит с самим контекстом, когда цикл прокручивается сто раз подряд.
Тезис, вокруг которого всё построено, стоит проговорить сразу, потому что он контринтуитивен:
Контекст — это кэш, а не база данных. Всё, что попало в окно и не имеет источника за его пределами, при первом же сжатии исчезает окончательно. Не «забывается» и не «уходит в долговременную память» — исчезает.
Из этого тезиса выводятся все практические правила ниже: почему выгоднее держать в окне адреса, а не содержимое; почему после компакции нельзя доверять фразе «как мы выяснили выше»; и почему перезапуск сессии часто дешевле героической борьбы за место в окне.
Базовое устройство токенов и окна разобрано в главе «Токены, контекстное окно и память диалога» трека основ ИИ. Здесь мы это не повторяем, а берём как данность и смотрим, что меняется, когда окно заполняет не человек своими репликами, а агент — выводом pytest.
Что физически лежит в окне
Первое, что стоит сделать в новом харнессе, — понять, из чего складывается ваш контекст. Не «примерно», а по слоям.
Разберём слои по порядку — они очень по-разному ведут себя и очень по-разному управляемы.
Системный промпт харнесса. Инструкции самого инструмента: как оформлять правки, когда спрашивать разрешение, как звать инструменты. Вы его обычно не видите и не редактируете. Он есть у Claude Code, у Cursor, у Codex — у всех разный, и от версии к версии он меняется. Это первая причина, по которой «одинаковый промпт» в двух инструментах даёт разный результат: промпт-то одинаковый, а контекст вокруг него — нет.
Описания инструментов. Каждый инструмент — это имя, описание и JSON-схема параметров. Подключили MCP-сервер с сорока методами — все сорок схем поехали в окно, и поедут заново на каждом ходу. Про цену этого решения подробно в главе про инструменты и MCP; здесь достаточно запомнить, что «подключить на всякий случай» — это не бесплатно.
Проектный контракт. CLAUDE.md, AGENTS.md, правила репозитория. Единственный слой стабильного префикса, который вы пишете сами. Он маленький по объёму и огромный по влиянию — подробнее в главе «Промпт как спецификация».
История диалога. Ваши реплики, ответы модели, иногда — её рассуждения (зависит от того, сохраняет ли их харнесс между ходами).
Выводы инструментов. Вот здесь живёт основной объём. Содержимое прочитанных файлов, вывод тестов, стектрейсы, дифы, дерево репозитория, результаты grep. В типичной сессии рефакторинга это больше половины окна, и это единственный слой, где решения принимаете вы — формулировкой задачи и выбором стратегии чтения.
Резерв под ответ. Модель должна куда-то писать ответ и, если включено расширенное рассуждение, ещё и думать. Этот бюджет отнимается от того же окна. Если резерв не оставить, ответ обрывается на середине — и вы платите за обрыв полную цену.
Почему окно не резиновое: три независимых ограничения
Люди обычно называют одну причину — «модель не влезет». На самом деле ограничений три, и они сходятся в разных точках.
Первое: техническое. Внимание трансформера при обработке промпта квадратично по длине последовательности — вдвое более длинный промпт обрабатывается заметно дольше, чем вдвое дольше. При генерации токенов работает KV-кэш, и стоимость одного нового токена растёт линейно по длине контекста, а память под кэш — тоже линейно. Отсюда практическое следствие, которое чувствуется руками: длинная сессия не просто дороже, она ещё и заметно медленнее на каждом ходу. Механику удобно освежить в главе «Как работает LLM».
Второе: экономическое. API не хранит вашу сессию. Каждый ход — это новый запрос, в котором вся история отправляется заново и оплачивается заново как входные токены. Если в сессии N ходов и каждый добавляет примерно одинаковый объём, суммарное количество оплаченных входных токенов растёт как N², а не как N. Двадцатиходовая сессия стоит не в два раза дороже десятиходовой, а примерно в четыре. Это ровно та арифметика, из-за которой «поболтать с агентом ещё немного» — не безобидное решение. Кэширование префикса частично лечит эту квадратичность (см. ниже), но только частично и только при аккуратной работе.
Третье: качественное. Заявленный размер окна и размер, на котором модель работает хорошо, — разные величины. Об этом стоит поговорить отдельно.
Заявленное окно и полезное окно
Производители публикуют размеры окон в характеристиках моделей — сегодня это сотни тысяч и миллионы токенов (список моделей и окон у Anthropic). Числа меняются каждые несколько месяцев, поэтому запоминать их бессмысленно: сверяйтесь с документацией своего провайдера в день работы.
Полезнее запомнить два эмпирических факта, которые держатся уже несколько поколений моделей.
Факт первый: позиция в контексте влияет на то, будет ли информация использована. Классическая работа Lost in the Middle: How Language Models Use Long Contexts (Liu et al., 2023) показала U-образную кривую: модели лучше всего используют то, что стоит в начале и в конце контекста, и хуже всего — то, что закопано в середине. Работа сделана на моделях 2023 года, и честно будет сказать, что современные модели держатся заметно ровнее — но эффект не исчез, и на длинных сессиях он проявляется.
Факт второй: тесты вида «найди иголку в стоге сена» переоценивают возможности. Популярный формат проверки — спрятать в длинном тексте одну фразу и попросить её найти. Модели проходят такой тест на всю длину окна, и производители любят этот график. Проблема в том, что задача поиска одного факта — самая простая из возможных. Бенчмарк RULER (Hsieh et al., 2024) добавил задачи, требующие агрегации, отслеживания нескольких сущностей и рассуждения по разбросанным по контексту фактам, — и показал, что на них «эффективная» длина контекста у моделей оказывается существенно меньше заявленной.
Что из этого следует практически:
- Забить окно «на всякий случай» — не бесплатная, а вредная стратегия. Мусор в контексте не игнорируется, он конкурирует за внимание.
- Инструкция, поданная в начале трёхсоттысячной сессии, к концу может перестать соблюдаться. Это не «агент вас не слушает», это свойство механизма.
- Важное следует повторять ближе к текущему ходу, а не рассчитывать, что «я же сказал в начале».
Обратная сторона, которую тоже надо назвать: рассуждения про «эффективный контекст» легко превратить в суеверие. Утверждение «после 50% окна модель тупеет» — не проверяемое утверждение, а фольклор, пока вы не показали прогон на своей задаче. Правильная позиция: относиться к длине контекста как к параметру, влияние которого на вашу задачу нужно измерить, а не угадать по чужому графику.
Что именно съедает окно в агентской сессии
Здесь полезно перейти от общих слов к типологии. Вот источники расхода, отсортированные по тому, как часто они убивают сессии на практике.
| Источник | Почему дорого | Что делать |
|---|---|---|
| Чтение файлов целиком | Файл на 2000 строк — это десятки тысяч токенов, и они останутся в окне до конца сессии | Просить читать по диапазону строк; сначала grep, потом чтение найденного фрагмента |
| Вывод тестов и сборки | Один прогон падающего пакета даёт сотни строк, из которых значимы пять | Прогонять точечно, фильтровать вывод, просить --maxfail=1 или аналог |
| Дерево репозитория | find по большому монорепо — тысячи строк, полезных из которых десяток |
Ограничивать глубину и каталог, использовать rg --files с шаблоном |
| Дифы больших правок | Диф на 500 строк, который агент сам же и породил, лежит в окне и мешает | После проверки правки — фиксировать в коммит и не тащить диф дальше |
| Схемы неиспользуемых инструментов | Постоянный налог на каждом ходу | Отключать MCP-серверы, которые не нужны в этой задаче |
| Повторное чтение одного и того же | Агент читает файл, потом «на всякий случай» перечитывает | Явно указывать в контракте: не перечитывать без причины |
| Длинные рассуждения модели | Расширенное рассуждение съедает бюджет вывода | Регулировать уровень усилия, если харнесс это позволяет |
Обратите внимание на асимметрию: почти всё в этой таблице — не про «модель плохая», а про то, как сформулирована задача и какой инструмент выбран. Это и есть основная точка приложения инженерных усилий.
Измерять, а не гадать
Единственный честный способ понять свой расход — посчитать. Не оценить на глаз, не поделить символы на четыре, а посчитать тем же токенизатором, который использует модель.
# Сколько токенов стоит проектный контракт — считаем токенизатором провайдера,
# а не приблизительной эвристикой "символы делить на четыре".
from anthropic import Anthropic
client = Anthropic()
with open("CLAUDE.md", encoding="utf-8") as f:
contract = f.read()
result = client.messages.count_tokens(
model="claude-opus-5",
messages=[{"role": "user", "content": contract}],
)
print(result.input_tokens)
Две оговорки, без которых пример вредит:
- Токенизатор привязан к модели. Счётчик от одного провайдера не годится для модели другого, и даже соседние поколения одной линейки могут токенизировать текст по-разному. Считайте той моделью, которой будете работать.
tiktoken— это токенизатор OpenAI. Использовать его для оценки Claude-моделей некорректно; оценка будет систематически смещена. У каждого провайдера есть свой способ подсчёта — документация Anthropic по подсчёту токенов, аналогичные эндпоинты у остальных.
Второй источник фактов — поле usage в ответе API: сколько токенов ушло на вход, сколько записано в кэш, сколько прочитано из кэша, сколько сгенерировано. Если ваш харнесс показывает эти числа — смотрите на них регулярно; если не показывает, это повод посмотреть, есть ли режим отладки. Оценка занятости контекста в интерфейсе (индикатор, команда вроде /context — набор команд зависит от инструмента и версии, сверяйтесь с документацией своей) — грубее, но лучше, чем ничего.
Жизненный цикл окна в одной сессии
Практически любая длинная сессия проходит один и тот же путь.
Интересна здесь не сама схема, а два перехода.
Переход Risk → Fresh — осознанный перезапуск — почти всегда дешевле и предсказуемее, чем Risk → Compact. Он стоит вам одного акта дисциплины: записать текущее состояние во внешний артефакт и начать заново.
Переход Compact → Degraded — самая коварная точка всей главы. Он не сопровождается ошибкой. Агент продолжает уверенно работать, ссылаться на «то, что мы выяснили», и выдавать правдоподобные утверждения — просто основания под ними испарились.
Компакция: что это и что она отнимает
Компакция — автоматическое сжатие истории, когда контекст подходит к пределу. Реализации разные: часть харнессов делает это на своей стороне, у API есть серверная компакция (документация Anthropic), есть также отдельный механизм «редактирования контекста», который не сжимает, а вычищает старые результаты инструментов (context editing). Разница между двумя подходами существенна.
Суммаризация — модель пишет конспект прошлой части диалога, конспект занимает место истории. Сохраняются выводы, теряются формулировки и точные значения.
Вычистка — старые выводы инструментов просто удаляются, структура диалога остаётся. Сохраняется ход разговора, теряется фактура.
Обе операции необратимы для сессии. И обе теряют одно и то же — улики.
Это ключевое различие, которое стоит держать в голове:
| Что это | Переживает компакцию | Почему |
|---|---|---|
Вывод «функция parse не обрабатывает пустой ввод» |
Обычно да | Это короткое утверждение, конспект его сохранит |
| Стектрейс, из которого этот вывод получен | Нет | Он длинный и выглядит «уже отработанным» |
| Точный номер строки и версия файла | Часто нет | Детали — первое, что теряет пересказ |
| «Подход через кэширование мы отвергли, потому что ломается инвалидация» | Ненадёжно | Отрицательное знание пересказывается хуже положительного |
| Формулировка задачи от человека | Обычно да | Она в начале и короткая |
Отсюда правило, которое и отвечает на вопрос в заголовке главы.
Терять без ущерба можно то, что дёшево восстановить прогоном. Содержимое файла, вывод тестов, диф — всё это воспроизводится одной командой. Терять нельзя то, что было получено дорого и нигде не записано: отвергнутые гипотезы, причины решений, найденные неочевидные связи.
И следствие: если что-то дорогое всё-таки должно пережить сессию — оно должно быть записано наружу до того, как начнётся компакция. Не в контекст, а в файл, в комментарий к PR, в заметку. Про это следующая глава трека, «Память агента», и это же — предмет нашего собственного пакета products/workbench/templates/memory/: протокол памяти требует, чтобы у каждого утверждения об окружающем мире был адрес источника, а каждая опровергнутая гипотеза записывалась отдельной заметкой. Смысл требования ровно в этом: утверждение с адресом переживает компакцию, потому что адрес короткий и проверяемый, а утверждение без адреса после компакции превращается в слух.
Что держать в окне, а что вынести
Полезная система координат: насколько часто информация нужна и насколько дорого её восстановить.
Правый нижний угол — самый опасный: информация нужна не постоянно, поэтому конспект её выбрасывает, а восстановить её дорого, потому что она добыта рассуждением, а не командой. Именно оттуда берутся ситуации «агент второй раз предлагает подход, который мы час назад признали нерабочим».
Три стратегии борьбы за место
Стратегия 1. Не класть
Самая дешёвая и самая недооценённая. Формулировка задачи определяет, сколько мусора попадёт в окно.
# Дорого: агент читает весь файл, чтобы найти одно определение.
# 1800 строк уедут в контекст и останутся там до конца сессии.
# Дёшево: сначала адрес, потом фрагмент.
rg -n "def parse_config" src/ # находим строку
sed -n '120,180p' src/config.py # читаем только окрестность
# Дорого: полный вывод падающего пакета тестов.
pytest tests/
# Дёшево: остановиться на первом падении, без лишнего шума.
pytest tests/ -x -q --no-header
Это ровно то, что стоит записать в проектный контракт как правило поведения агента, а не повторять голосом каждую сессию.
Стратегия 2. Вынести и заземлиться заново
Приём, который лучше всего окупается на длинных задачах: агент по ходу работы пишет краткие выводы во внешний файл, а после сжатия контекста перечитывает его и продолжает от записанного, а не от «того, что помнит».
Ключевая деталь — предпоследний шаг. Заметка не является доказательством: она была верна на момент записи. Файл мог измениться, тест мог начать падать по другой причине. Поэтому после восстановления из заметок один-два ключевых факта нужно перепроверить прогоном. Это дёшево и снимает целый класс ошибок; подробно — в главе «Проверяемость».
Стратегия 3. Перезапустить
Самая простая и чаще всего правильная. Если задача сменилась — сессию менять. Отладка бага и последующий рефакторинг — это две задачи, и тащить контекст первой во вторую невыгодно: старый стектрейс не помогает, а место занимает и внимание отвлекает.
Практическое правило: одна сессия — одна задача с одним критерием готовности. Как только критерий выполнен, сессия закрывается, а всё, что должно жить дальше, лежит в коммите, PR или заметке.
Контекст и цена: кэш префикса
Есть механизм, который частично снимает квадратичный рост стоимости, — кэширование префикса. Идея простая: провайдер запоминает обработанное начало запроса, и при следующем запросе с тем же началом не считает его заново. Экономия существенная: чтение из кэша стоит порядка десятой части обычной цены входного токена, запись в кэш — примерно на четверть дороже обычной (документация Anthropic по кэшированию; у других провайдеров механизм и условия отличаются).
Здесь важно одно инженерное свойство, из которого следует всё остальное:
Кэш работает по совпадению префикса байт в байт. Изменение одного символа в начале запроса обесценивает кэш всего, что идёт после него.
Отсюда правило раскладки: стабильное — вперёд, изменчивое — назад. И типичные способы случайно сломать себе кэш:
- подставить текущую дату или время в системный промпт — префикс меняется на каждом запросе;
- подключить или отключить MCP-сервер посреди сессии — схемы инструментов идут в самом начале, кэш обнуляется целиком;
- сериализовать что-то в JSON без стабильного порядка ключей;
- переключить модель посреди работы — кэш привязан к модели.
Есть и порог: слишком короткий префикс не кэшируется вовсе, и величина порога зависит от модели. Тихий отказ здесь опаснее ошибки: вы думаете, что экономите, а поля кэша в usage показывают нули.
Практический вывод для работы с агентом: длинная сессия с неизменным набором инструментов и стабильным контрактом дешевле, чем та же работа, разбитая перезапусками с переподключением серверов. Это единственный весомый аргумент против частых перезапусков — и его надо взвешивать против качественной деградации на длинном контексте. Универсального ответа нет; для вашей задачи он находится измерением, а не спором.
Где агент врёт про контекст
Отдельный разговор — про то, как отказы, связанные с окном, выглядят снаружи. Общая типология отказов — в главе «Где агенты врут»; здесь только контекстные, потому что они самые незаметные.
1. Ложная непрерывность. После компакции агент говорит «как мы установили выше» или «согласно найденному ранее» — а установленного «выше» в окне уже нет, есть его пересказ. Формулировка звучит одинаково уверенно в обоих случаях.
Как ловить: спросите адрес. «В каком файле, на какой строке?» Если в ответ приходит уверенное описание без конкретики или с конкретикой, которой в репозитории нет, — вы поймали пересказ пересказа.
2. Мнимое прочтение. «Я изучил модуль аутентификации» может означать, что прочитаны первые 200 строк одного файла из шести. Агент не врёт намеренно — он обобщает свою активность.
Как ловить: попросите перечислить, что именно было прочитано, и сверьте с реальной структурой каталога. В большинстве харнессов есть журнал вызовов инструментов — он надёжнее самоотчёта.
3. Устаревший снимок. Файл прочитан на десятом ходу, изменён на двадцатом (агентом или вами в редакторе), а на тридцатом агент рассуждает по версии из окна. Формально всё честно: он видит то, что видит.
Как ловить: перед значимой правкой — перечитать файл. Хорошие реализации инструмента редактирования это делают принудительно, отказываясь править файл, изменившийся с момента чтения. Проверьте, есть ли такая защита в вашем инструменте.
4. Потеря отрицательного знания. Час назад подход был проверен и отвергнут; после сжатия истории агент предлагает его снова, с той же аргументацией.
Как ловить: только записью наружу. Никакая формулировка промпта не спасёт информацию, которой в окне уже нет. Отвергнутые варианты — самое ценное, что стоит писать в заметки, потому что они дороже всего добыты и хуже всего переживают пересказ.
5. Дрейф инструкции. Правило, заданное в начале сессии («не трогай legacy/», «не добавляй зависимости»), к сотому ходу перестаёт соблюдаться.
Как ловить: по факту нарушения в дифе — и лечить переносом правила в проектный контракт, который едет в каждом запросе, а не в реплику, которая осталась где-то в сжатой истории.
Общее у всех пяти: утверждение агента о состоянии кода или о ходе работы не является свидетельством. Свидетельство — это прогон, диф, журнал вызовов. Об этом весь трек, и глава про контекст — просто ещё одно место, где это правило кусается.
Дерево решений: контекст кончается, что делать
почти закончена?"} B -->|да| C["Довести до конца
и зафиксировать результат"] B -->|нет| D{"Ценное записано
наружу?"} D -->|нет| E["Записать выводы, адреса,
отвергнутые варианты в файл"] E --> F{"Задача та же,
что в начале сессии?"} D -->|да| F F -->|нет| G["Новая сессия под новую задачу"] F -->|да| H{"В окне много
отработанных выводов?"} H -->|да| I["Вычистить старые результаты
инструментов, сохранив ход работы"] H -->|нет| J["Новая сессия с заземлением
по заметкам и перепроверкой"] C --> K["Зафиксировать в коммит или PR"] G --> K I --> K J --> K
Обратите внимание, что «положиться на автоматическую компакцию» в этом дереве отсутствует как отдельная ветка. Она случится и без вас — вопрос лишь в том, успели ли вы записать наружу то, что нельзя терять. Автокомпакция — это страховка от обрыва, а не стратегия работы.
Цена вопроса и когда дешевле руками
Гигиена контекста — это работа. Она стоит вашего внимания: сформулировать задачу узко, проверить, что агент читает не весь файл, записать выводы, перепроверить факт после перезапуска. Считать эту работу бесплатной — та же ошибка, что считать бесплатными токены.
Честная арифметика выглядит так. Если задача — поправить константу в известном файле, то полный цикл «объяснить агенту → он прочитает файл → предложит правку → вы проверите диф» дороже, чем открыть файл и поправить. Не в токенах даже, а в вашем времени на ревью. Порог окупаемости агента лежит там, где задача требует поиска, множественных согласованных правок или прогонов, которые вы всё равно делали бы руками.
Три признака, что вы вкладываетесь в контекст напрасно:
- Вы третий раз объясняете одно и то же в одной сессии. Значит, объяснение не доехало до префикса — его место в проектном контракте, а не в реплике.
- Вы больше времени тратите на управление контекстом, чем на задачу. Значит, задача была сформулирована слишком широко; её надо разрезать — про это глава «Планирование и декомпозиция».
- Каждый ход добавляет тысячи токенов вывода и ноль продвижения. Значит, агент ходит по кругу; спасать сессию бессмысленно, надо остановиться и переформулировать.
Детальный разбор экономики — в главе «Цена работы с агентом», а модель стоимости на стороне API — в главе «Продакшн и стоимость» трека ИИ-инженерии.
Типичные ошибки
Считать окно памятью. «Он же помнит, я говорил ему» — нет. В окне лежит текст последнего запроса, и всё, чего в этом тексте нет, для модели не существует. Проверяется в одну секунду: спросите то, что было сказано двести ходов назад.
Заливать в контекст всё подряд «для полноты картины». Лишний текст конкурирует за внимание и удорожает каждый последующий ход. Полнота картины достигается адресами, а не копиями.
Верить конспекту. После компакции конспект выглядит как знание, но это пересказ. Ключевые факты после сжатия перепроверяются прогоном — всегда.
Держать одну бесконечную сессию. Она дешевле по кэшу и дороже по качеству и по вашему вниманию. Разрезайте по границам задач.
Оптимизировать контекст вместо задачи. Самая частая ловушка у увлечённых. Если задача решается руками за десять минут — гигиена контекста в ней не нужна, потому что не нужен агент.
Оценивать токены на глаз. «Символы делить на четыре» — эвристика для английского текста; для русского и для кода она врёт, и врёт в разные стороны. Считайте счётчиком провайдера.
Мини-итог
- Окно контекста — это бюджет на один запрос, а не память. История пересылается заново каждый ход и оплачивается заново.
- В окне лежат шесть слоёв, и основной объём — выводы инструментов. Это единственный слой, которым вы управляете формулировкой задачи.
- Ограничений три: техническое, экономическое (квадратичный рост суммарных входных токенов) и качественное (полезное окно меньше заявленного).
- Компакция сохраняет выводы и теряет улики. Утверждение без адреса источника после сжатия превращается в слух.
- Терять без ущерба можно всё, что восстанавливается одной командой. Нельзя терять то, что добыто рассуждением: отвергнутые гипотезы, причины решений, неочевидные связи. Их нужно записывать наружу заранее.
- Пять контекстных отказов — ложная непрерывность, мнимое прочтение, устаревший снимок, потеря отрицательного знания, дрейф инструкции — не сопровождаются ошибками и ловятся только требованием адреса и прогона.
- Кэш префикса даёт реальную экономию, но ломается от любого изменения в начале запроса. Стабильное — вперёд, изменчивое — назад.
- Всё вышеперечисленное — работа. Если задача дешевле руками, делайте руками.
Что дальше
Мы разобрали, что помещается в окно и что из него уходит. Следующий вопрос — откуда в окне вообще берутся выводы инструментов: как устроен вызов функций, что такое MCP, сколько стоит каждый подключённый сервер и когда свою интеграцию писать выгоднее, чем брать готовую.
Инструменты и протоколы: вызов функций, MCP, свои интеграции
Источники
- Lost in the Middle: How Language Models Use Long Contexts — Liu et al., 2023. Про позиционную зависимость использования контекста.
- RULER: What’s the Real Context Size of Your Long-Context Language Models? — Hsieh et al., 2024. Про разрыв между заявленной и эффективной длиной контекста.
- Prompt caching — механика кэширования префикса и условия экономии.
- Compaction и Context editing — два разных способа освободить место, с разными потерями.
- Token counting — как считать токены корректно, а не эвристикой.
- Effective context engineering for AI agents — инженерный разбор от Anthropic; читать с поправкой на то, что это текст производителя.
products/workbench/templates/memory/— наш пакет протокола памяти: требование адреса у каждого утверждения и отдельные заметки для опровергнутых гипотез существуют ровно затем, чтобы знание переживало сжатие контекста.