Как сжатие контекста работает в Pi

· 1 мин чтения
context-management context-engineering tokens harness ai-agents
Как сжатие контекста работает в Pi

Как сжатие контекста работает в Pi

Если вы долго работали в кодинг-агенте — в Pi, Claude Code или Codex — вы наверняка сталкивались со сжатием контекста. В этот момент агент перестаёт отправлять всю историю диалога и передаёт сжатое резюме. Разберёмся, как это устроено и когда Pi прибегает к сжатию.

Из чего состоит запрос к LLM

У больших языковых моделей есть ограничение — контекстное окно. Это количество текста, которое модель «видит», пока готовит ответ. Ограничение приходит из архитектуры трансформера, на которой построены LLM.

В кодинг-агент каждый запрос к модели содержит: системный промпт, загруженные файлы вроде AGENTS.md, определения инструментов и всю историю диалога. История растёт с каждым шагом. Как только она перестаёт помещаться в контекстное окно, модель отклоняет запрос.

Вот как выглядит первый запрос:

request 1:
[system][tools][user]

Это начало одного шага работы. Модель может сначала вернуть сообщение с вызовами инструментов. Программа агента выполняет их и отправляет новый запрос, в котором вся переписка уже дополнена результатами. Ответ приходит, и шаг заканчивается, когда модель дописала свой ответ.

after request 1:
[system][tools][user][assistant: tool call][tool result][assistant]
                     <------------------->     ^        <--------->
                     returned by LLM           |        returned by LLM
                                               |
                                     produced by the agent

Мы продолжаем работать и отправляем следующее сообщение:

request 2:
[system][tools][user][assistant: tool call][tool result][assistant][user]
                                                                     ^
                                                               new user message

Каждый шаг раздувает историю. В какой-то момент она перестаёт помещаться, и следующий запрос возвращает ошибку вида Request exceeds the maximum size.

[system][tools][user][assistant][....][tool result][user]
                                                      ^
                                             exceeds context window

Что делать, когда контекст кончился

Когда продолжить диалог как есть нельзя, есть два пути.

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

Что такое сжатие

Теоретически способов много. Например, можно написать обычную функцию, которая оставит часть переписки, а остальное выбросит. На практике сжатие делают запросом к LLM: модель сама пересказывает историю.

Сжатие заменяет часть истории сжатым представлением и освобождает место для новых сообщений и вызовов инструментов.

[system][tools][compaction result][user]
                                    ^
                               new message

Как это сделано в Pi

Посмотрим, как именно это устроено в Pi. Когда диалог становится слишком длинным, Pi сжимает старое содержимое и сохраняет свежую работу. Сжатие срабатывает, когда размер контекста приближается к пределу окна. Его можно запустить и вручную — командой /compact.

Pi проверяет автосжатие после того, как шаг завершился. До этого момента каждый запрос продолжает уже накопленный промпт, и Pi может использовать его закэшированную часть. Если Pi ловит ошибку о переполнении контекста, он может сжать контекст прямо посреди шага.

При сжатии Pi оставляет несколько последних сообщений без изменений.

before compaction:
[system + tools][older turns][recent retained messages]

Число оставленных сообщений каждый раз разное. Его задаёт бюджет токенов, который можно настроить. Сейчас по умолчанию стоит 20 тысяч токенов, это примерно от 5 до 20 шагов. Все сообщения до этой границы извлекаются, превращаются в текст и уходят модели на пересказ.

Промпт для сжатия

Хорошее резюме для кодинг-агента должно звучать как передача дел от одной смены к другой. Промпт сжатия в Pi исходит из того, что в текущем контексте много уже ненужного. Оставлять нужно только то, что ещё важно для следующего запроса к модели.

Поэтому для сжатия Pi отправляет отдельный запрос, отличный от обычного запроса в диалоге.

  1. Другой системный промпт. Вместо «you are an expert coding assistant» модели сообщают «you are a context summarization assistant».
  2. Другое пользовательское сообщение. Оно просит «a structured summary of this conversation branch for context when returning later». В промпте заданы разделы: цель, прогресс и ключевые решения.
  3. Запрос идёт отдельно. Он не использует существующую историю диалога, поэтому его можно отдать другой модели и не платить лишнего.

Результат сжатия добавляется в сессию Pi как отдельная запись, и работа продолжается. После запроса контекст сжат.

after compaction:
[system][tools][summary][recent turns][new user message]

Теперь в контексте снова помещается много новых сообщений.

Pi хранит резюме обычным текстом прямо в сессии. Так сжатый контекст остаётся читаемым и его можно унести с собой: в Pi можно переключить модель и продолжить работу с тем же резюме.

Сжатие и кеширование промпта

Кеширование промпта — механизм провайдеров LLM, который делает повторные запросы в одном диалоге дешевле. Во время активной сессии мы меньше платим за контекст, который модель уже обработала. Кеш требует точного совпадения префикса, поэтому сжатие ломает его.

cached before compaction:
[system][tools][older history][recent retained turns]
<-------------------- cached prefix -------------------->

first request after compaction:
[system][tools][summary][recent retained turns][new user message]
<-- reusable -->^
                |
        first changed token
                |
                +-- everything after this point must be recomputed

Оставленные последние шаги содержат те же токены, но теперь следуют за другим префиксом. Их прежнее кешированное состояние использовать уже нельзя. Все запросы после сжатия снова смогут использовать кеш.

Своё сжатие вместо встроенного

Pi построен так, что его можно менять под себя. Чтобы проверить другой механизм сжатия, достаточно попросить Pi собрать расширение со своим промптом для сжатия.

Источник: https://earendil.com/posts/compaction-in-pi/