Skip to content

Стабильность длинных сессий: Контекстное сжатие, кеширование подписей и сжатие результатов инструментов

Когда вы используете Claude Code / Cherry Studio и другие клиенты для запуска длинных сессий, самое раздражающее не в том, что модель недостаточно умна, а в том, что диалог внезапно начинает выдавать ошибки: Prompt is too long, ошибки подписи 400, прерывается цепочка вызовов инструментов, или инструментальный цикл становится всё медленнее.

В этом уроке будут подробно разъяснены три вещи, которые Antigravity Tools делает для решения этих проблем: контекстное сжатие (постепенное вмешательство на трёх уровнях), кеширование подписей (сохранение цепочки подписей Thinking) и сжатие результатов инструментов (чтобы результаты инструментов не переполнили контекст).

Что вы сможете сделать после изучения

  • Понять, что делает трёхуровневое прогрессивное сжатие контекста и каковы издержки каждого уровня
  • Знать, что хранится в кеше подписей (три уровня: Tool/Family/Session) и влияние TTL в 2 часа
  • Понять правила сжатия результатов инструментов: когда будут отброшены base64-изображения, когда снимки браузера будут преобразованы в сводку head+tail
  • При необходимости отрегулировать пороговое значение срабатывания сжатия через настройки порога proxy.experimental

Ваша текущая проблема

  • После длинного диалога внезапно начинают возникать 400: похоже на сбой подписи, но вы не знаете, откуда подпись, и где она теряется
  • Вызовов инструментов становится всё больше, исторические tool_result накапливаются до прямого отказа вышестоящего провайдера (или становятся крайне медленными)
  • Вы хотите использовать сжатие для спасения, но беспокоитесь, что это нарушит Prompt Cache, повлияет на согласованность или заставит модель потерять информацию

Когда использовать этот подход

  • Вы выполняете задачи с длинными цепочками инструментов (поиск/чтение файлов/снимки браузера/циклы инструментов)
  • Вы используете Thinking-модели для сложных рассуждений, и сессии часто превышают десятки раундов
  • Вы расследуете проблемы стабильности, которые клиент может воспроизвести, но вы не можете ясно объяснить

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

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

Как рассчитывается давление контекста?

Процессор Claude выполняет лёгкую оценку с помощью ContextManager::estimate_token_usage() и калибрует её с помощью estimation_calibrator, затем получает процент давления через usage_ratio = estimated_usage / context_limit (в журнале будут выводиться значения raw/calibrated).

🎒 Подготовка перед началом

  • Вы уже запустили локальный прокси, и клиент действительно использует путь /v1/messages (см. запуск локального обратного прокси и подключение первого клиента)
  • Вы можете просматривать журналы прокси (отладка разработчика или локальные файлы журналов). План тестирования в репозитории даёт пример пути к файлу журнала и способа grep (см. docs/testing/context_compression_test_plan.md)

Совместное использование с Proxy Monitor для лучшего позиционирования

Если вы хотите сопоставить срабатывание сжатия с определённым типом запроса/учётной записью/раундом вызова инструмента, рекомендуется одновременно открывать Proxy Monitor.

Основная идея

Этот дизайн стабильности не заключается в простом удалении всей истории, а в пошаговом вмешательстве от низкой к высокой цене:

УровеньТочка срабатывания (настраивается)Что делаетЦена/побочный эффект
Уровень 1proxy.experimental.context_compression_threshold_l1 (по умолчанию 0.4)Идентифицирует раунды инструментов, сохраняет только последние N раундов (в коде это 5), удаляет более старые пары tool_use/tool_resultНе изменяет содержимое оставшихся сообщений, более дружественно для Prompt Cache
Уровень 2proxy.experimental.context_compression_threshold_l2 (по умолчанию 0.55)Сжимает старые тексты Thinking в "...", но сохраняет signature, защищает последние 4 сообщенияБудет изменять историческое содержимое, в комментариях явно указано, что это нарушит cache, но может сохранить цепочку подписей
Уровень 3proxy.experimental.context_compression_threshold_l3 (по умолчанию 0.7)Вызывает фоновую модель для генерации XML-сводки, затем разветвляет новую последовательность сообщений для продолжения диалогаЗависит от вызова фоновой модели; при сбое вернёт 400 (с дружелюбным напоминанием)

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

Уровень 1: Обрезка раундов инструментов (Trim Tool Messages)

Ключевой момент Уровня 1 заключается в удалении только целых раундов взаимодействия инструментов, чтобы избежать несогласованности контекста из-за частичного удаления.

  • Правило идентификации раунда инструментов находится в identify_tool_rounds(): когда в assistant появляется tool_use, начинается новый раунд, последующий tool_result в user всё ещё считается этим же раундом, пока не встретится обычный текст user для окончания этого раунда.
  • Фактическое выполнение обрезки выполняется в ContextManager::trim_tool_messages(&mut messages, 5): когда исторические раунды инструментов превышают 5 раундов, удаляются сообщения, связанные с более ранними раундами.

Уровень 2: Сжатие Thinking, но сохранение подписей

Многие проблемы 400 вызваны не слишком длинными Thinking, а тем, что цепочка подписей Thinking разорвана. Стратегия Уровня 2:

  • Обрабатывает только ContentBlock::Thinking { thinking, signature, .. } в сообщениях assistant
  • Сжимает только когда signature.is_some() и thinking.len() > 10, меняя thinking напрямую на "..."
  • Последние protected_last_n = 4 сообщения не сжимаются (примерно последние 2 раунда user/assistant)

Таким образом можно сэкономить большое количество токенов, но signature остаётся в истории, чтобы при восстановлении цепочки инструментов было откуда восстановить.

Уровень 3: Разветвление + XML-сводка (последний резерв)

Когда давление продолжает расти, процессор Claude попытается перезапустить сессию, не потеряв ключевую информацию:

  1. Извлекает последнюю действительную подпись Thinking из исходных сообщений (ContextManager::extract_last_valid_signature())
  2. Собирает всю историю + CONTEXT_SUMMARY_PROMPT в запрос на генерацию XML-сводки, модель фиксируется как BACKGROUND_MODEL_LITE (в текущем коде это gemini-2.5-flash)
  3. В сводке требуется включить <latest_thinking_signature>, используемый для продолжения цепочки подписей
  4. Разветвляет новую последовательность сообщений:
    • User: Context has been compressed... + XML summary
    • Assistant: I have reviewed...
    • Затем прикрепляет последнее сообщение user исходного запроса (если это не только что инструкция сводки)

Если разветвление + сводка не удастся, напрямую вернётся StatusCode::BAD_REQUEST, с предложением использовать /compact или /clear и другие способы ручной обработки (см. JSON ошибки, возвращаемый процессором).

Обходной путь 1: Трёхуровневое кеширование подписей (Tool / Family / Session)

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

  • TTL: SIGNATURE_TTL = 2 * 60 * 60 (2 часа)
  • Уровень 1: tool_use_id -> signature (восстановление цепочки инструментов)
  • Уровень 2: signature -> model family (проверка совместимости между моделями, чтобы избежать переноса подписей Claude на модели семейства Gemini)
  • Уровень 3: session_id -> latest signature (изоляция на уровне сессии, чтобы избежать загрязнения разных диалогов)

Эти три уровня кеша будут записаны/прочитаны при SSE-поточном анализе и преобразовании запроса Claude:

  • При потоковом анализе подпись thinking будет записана в Session Cache (а также кешируется family)
  • При потоковом анализе подпись tool_use будет записана в Tool Cache + Session Cache
  • При преобразовании вызова инструмента Claude в functionCall Gemini приоритет отдаётся восстановлению подписи из Session Cache или Tool Cache

Обходной путь 2: Сжатие результатов инструментов (Tool Result Compressor)

Результаты инструментов легче переполняют контекст, чем текст чата, поэтому на этапе преобразования запросов выполняется предсказуемое уменьшение tool_result.

Основные правила (все в tool_result_compressor.rs):

  • Верхний предел общего количества символов: MAX_TOOL_RESULT_CHARS = 200_000
  • Блоки base64-изображений напрямую удаляются (добавляется текст подсказки)
  • Если обнаружено, что вывод сохранён в файл, извлекается ключевая информация и используется заполнитель [tool_result omitted ...]
  • Если обнаружен снимок браузера (содержит page snapshot / ref= и другие характеристики), изменяется на сводку head + tail и отмечено, сколько символов пропущено
  • Если ввод похож на HTML, сначала удаляются <style>/<script>/фрагменты base64, затем выполняется усечение

Следуйте за мной

Шаг 1: Подтвердите пороги сжатия (и значения по умолчанию)

Почему Точки срабатывания сжатия не жёстко заданы, они берутся из proxy.experimental.*. Вам нужно сначала знать текущий порог, чтобы судить, почему он так рано/так поздно вмешивается.

Значения по умолчанию (с стороны Rust ExperimentalConfig::default()):

json
{
  "proxy": {
    "experimental": {
      "enable_signature_cache": true,
      "enable_tool_loop_recovery": true,
      "enable_cross_model_checks": true,
      "enable_usage_scaling": true,
      "context_compression_threshold_l1": 0.4,
      "context_compression_threshold_l2": 0.55,
      "context_compression_threshold_l3": 0.7
    }
  }
}

Вы должны увидеть: в вашей конфигурации существует proxy.experimental (имя поля совпадает с указанным выше), а пороги имеют значения типа 0.x (процентное значение).

Местоположение файла конфигурации в этом уроке не повторяется

Место сохранения файла конфигурации и то, нужно ли перезапускать после изменения, относятся к категории управления конфигурацией. Согласно этой системе руководств, в первую очередь ориентируйтесь на Полное описание конфигурации: AppConfig/ProxyConfig, место сохранения на диск и семантика горячего обновления.

Шаг 2: Подтвердите с помощью журналов, сработали ли Уровень 1/2/3

Почему Эти три уровня являются внутренними поведениями прокси, самый надёжный способ проверки — увидеть, появляются ли в журнале [Layer-1] / [Layer-2] / [Layer-3].

План тестирования в репозитории даёт пример команды (отрегулируйте по необходимости на фактический путь к журналу на вашем компьютере):

bash
tail -f ~/Library/Application\ Support/com.antigravity.tools/logs/antigravity.log | grep -E "Layer-[123]"

Вы должны увидеть: когда давление растёт, в журнале появляются записи, подобные Tool trimming triggered, Thinking compression triggered, Fork successful (конкретные поля берутся из оригинала журнала).

Шаг 3: Поймите разницу между очисткой и сжатием (не путайте ожидания)

Почему Некоторые проблемы (например, принудительное понижение до моделей, не поддерживающих Thinking) требуют очистки, а не сжатия. Очистка напрямую удалит блок Thinking; сжатие сохранит цепочку подписей.

В процессоре Claude, понижение фоновой задачи пойдёт по пути ContextManager::purify_history(..., PurificationStrategy::Aggressive), которое напрямую удалит исторические блоки Thinking.

Вы должны увидеть: вы можете различать два типа поведения:

  • Очистка — это удаление блока Thinking
  • Сжатие Уровня 2 — это замена старого текста Thinking на "...", но подпись всё ещё существует

Шаг 4: Когда вы встречаете ошибку подписи 400, сначала посмотрите, попала ли Session Cache

Почему Корневая причина многих 400 не в отсутствии подписи, а в том, что подпись не идёт вместе с сообщением. При преобразовании запроса приоритет отдаётся восстановлению подписи из Session Cache.

Ключи (журналы на этапе преобразования запроса будут указывать на восстановление подписи из кеша SESSION/TOOL):

  • [Claude-Request] Recovered signature from SESSION cache ...
  • [Claude-Request] Recovered signature from TOOL cache ...

Вы должны увидеть: когда клиент теряет подпись, но кеш прокси всё ещё существует, в журнале появляются записи о восстановлении подписи из ... cache.

Шаг 5: Поймите, что будет потеряно при сжатии результатов инструментов

Почему Если вы позволите инструменту возвращать большие куски HTML / снимки браузера / base64-изображения обратно в диалог, прокси активно сократит их. Вам нужно заранее знать, какое содержимое будет заменено заполнителем, чтобы не ошибочно думать, что модель не увидела.

Запомните три важных момента:

  1. base64-изображения будут удалены (заменены текстом подсказки)
  2. Снимки браузера станут сводкой head/tail (с указанием количества пропущенных символов)
  3. Свыше 200 000 символов будет усечено и добавлено подсказка ...[truncated ...]

Вы должны увидеть: в tool_result_compressor.rs эти правила имеют явные константы и ветвления, это не удаление на основе опыта.

Контрольная точка

  • Вы можете ясно сказать, что точки срабатывания L1/L2/L3 берутся из proxy.experimental.context_compression_threshold_*, по умолчанию это 0.4/0.55/0.7
  • Вы можете объяснить, почему Уровень 2 нарушит cache: потому что он изменяет содержимое исторического текста thinking
  • Вы можете объяснить, почему Уровень 3 называется разветвлением: он превращает диалог в новую последовательность из сводки XML + подтверждение + последнее сообщение user
  • Вы можете объяснить, что сжатие результатов инструментов удалит base64-изображения и превратит снимки браузера в сводку head/tail

Напоминания о возможных ошибках

ЯвлениеВозможная причинаЧто вы можете сделать
После срабатывания Уровня 2 кажется, что контекст стал менее стабильнымУровень 2 изменяет историческое содержимое, в комментариях явно указано, что это нарушит cacheЕсли вы полагаетесь на согласованность Prompt Cache, постарайтесь, чтобы Уровень 1 сначала решил проблему, или повышайте порог Уровня 2
После срабатывания Уровня 3 сразу возвращается 400Разветвление + сводка вызвали фоновую модель неуспешно (сеть/учётная запись/ошибка вышестоящего провайдера и т. д.)Сначала используйте /compact или /clear согласно рекомендации в JSON ошибки; одновременно проверьте цепочку вызова фоновой модели
Изображения/большое содержимое в выводе инструментов исчезлиtool_result удалит base64-изображения, усечёт сверхдлинный выводВажно поместить важное содержимое в локальный файл/ссылку, затем сослаться на него; не рассчитывайте на то, что можно напрямую вставить 100 000 строк текста обратно в диалог
Понятно используется модель Gemini, но с подписью Claude возникает ошибкаПодписи несовместимы между моделями (в коде есть проверка family)Подтвердите источник подписи; при необходимости позвольте прокси удалять историческую подпись в сценариях retry (см. логику преобразования запроса)

Краткое содержание урока

  • Суть трёхуровневого сжатия — классификация по цене: сначала удаление старых раундов инструментов, затем сжатие старых Thinking, и только потом разветвление + XML-сводка
  • Кеширование подписей — ключ к сохранению цепочки инструментов: три уровня Session/Tool/Family каждый управляет одним типом проблемы, TTL — 2 часа
  • Сжатие результатов инструментов — жёсткий предел, позволяющий избежать переполнения контекста выводом инструментов: верхний предел 200 000 символов + специализация снимков/больших файлов

Предварительный просмотр следующего урока

Следующий урок мы поговорим о системных возможностях: мультиязычность/темы/обновления/автозапуск/HTTP API Server.


Приложение: Ссылка на исходный код

Нажмите, чтобы развернуть и просмотреть местоположение исходного кода

Дата обновления: 2026-01-23

ФункцияПуть к файлуНомер строки
Экспериментальная конфигурация: пороги сжатия и переключатели по умолчаниюsrc-tauri/src/proxy/config.rs119-168
Оценка контекста: оценка мультиязычных символов + запас 15%src-tauri/src/proxy/mappers/context_manager.rs9-37
Оценка потребления токенов: обход system/messages/tools/thinkingsrc-tauri/src/proxy/mappers/context_manager.rs103-198
Уровень 1: идентификация раундов инструментов + обрезка старых раундовsrc-tauri/src/proxy/mappers/context_manager.rs311-439
Уровень 2: сжатие Thinking, но сохранение подписей (защита последних N)src-tauri/src/proxy/mappers/context_manager.rs200-271
Уровень 3 вспомогательный: извлечение последней действительной подписиsrc-tauri/src/proxy/mappers/context_manager.rs73-109
Понижение фоновой задачи: Aggressive очистка блоков Thinkingsrc-tauri/src/proxy/handlers/claude.rs540-583
Основной процесс трёхуровневого сжатия: оценка, калибровка, срабатывание L1/L2/L3 по порогуsrc-tauri/src/proxy/handlers/claude.rs379-731
Уровень 3: реализация разветвления + сводка XMLsrc-tauri/src/proxy/handlers/claude.rs1560-1687
Кеширование подписей: TTL/структура трёхуровневого кеша (Tool/Family/Session)src-tauri/src/proxy/signature_cache.rs5-88
Кеширование подписей: запись/чтение подписей сессииsrc-tauri/src/proxy/signature_cache.rs141-223
SSE потоковый анализ: кеширование подписей thinking/tool в Session/Tool cachesrc-tauri/src/proxy/mappers/claude/streaming.rs766-776
---------
Преобразование запроса: tool_use приоритетно восстанавливает подпись из Session/Tool cachesrc-tauri/src/proxy/mappers/claude/request.rs1045-1142
Преобразование запроса: tool_result вызывает сжатие результатов инструментовsrc-tauri/src/proxy/mappers/claude/request.rs1159-1225
Сжатие результатов инструментов: вход compact_tool_result_text()src-tauri/src/proxy/mappers/tool_result_compressor.rs28-69
Сжатие результатов инструментов: сводка head/tail снимков браузераsrc-tauri/src/proxy/mappers/tool_result_compressor.rs123-178
---------
План тестирования: срабатывание трёхуровневого сжатия и проверка журналовdocs/testing/context_compression_test_plan.md1-116