Контекстное окно Управление токенами Оптимизация стоимости Responses API LLM API

Управление контекстным окном LLM для длинных бесед

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

AveMujica API 9 мин чтения

Растущая беседа ломается двумя разными способами, и путаница между ними ведёт к неправильному решению. Громкий сбой — это переполнение: промпт плюс запрошенный вывод превышают контекстное окно модели, и запрос отклоняется сразу. Тихий сбой — это стоимость: всё, что вы держите в контексте, повторно оплачивается на каждом ходу, так что чат, который никогда не переполняется, всё равно может дорожать линейно по мере накопления истории. Управлять контекстным окном означает защищаться от обоих — держать число токенов под жёстким пределом и держать его достаточно малым, чтобы вы не платили за пересылку одной и той же истории бесконечно. Эта статья охватывает то, как измерять бюджет, стратегии обрезки и суммирования, которые держат его под контролем, и кеширование с серверной компакцией, которые снижают то, сколько стоит длинная беседа.

Один бюджет, разделяемый входом, выводом и рассуждением

Контекстное окно — это единый бюджет токенов, из которого черпает весь запрос. Это не «входные токены до предела, а затем вывод сверху» — входные токены, токены, которые вы просите модель сгенерировать, и (на рассуждающих моделях) скрытые токены рассуждения все конкурируют за один и тот же потолок. Из этого немедленно следуют два следствия. Во-первых, длинный промпт сжимает место, оставшееся под ответ, так что переполненный контекст может вынудить обрезанный или пустой ответ даже без жёсткой ошибки переполнения. Во-вторых, на рассуждающих моделях невидимые токены рассуждения тоже вгрызаются в этот потолок, вот почему параметры API рассуждающих моделей подчёркивают резервирование запаса под вывод. Бюджетируйте окно как целое: решите заранее, сколько токенов вы позволите занять истории, сколько резервируете под рассуждение и сколько гарантируете под видимый ответ.

По умолчанию превышение окна — жёсткая ошибка: при отключённом усечении провайдеры возвращают ошибку длины контекста, а не молча отбрасывают токены, поэтому переполнение обычно должны предотвращать вы, а не поглощать модель. Есть одно намеренное исключение: Responses API принимает truncation: auto, позволяя провайдеру удалить элементы из середины входа, чтобы слишком большой запрос поместился, вместо его отклонения. Так чистая ошибка превращается в незаметную потерю контента, которую вы не выбирали, поэтому включайте режим осознанно и логируйте его срабатывания; автоматическое усечение и набор удаляемых элементов зависят от провайдера. В любом случае надёжная защита одна: знать число токенов до отправки.

Измеряйте перед отправкой

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

Подсчёт также должен быть честным насчёт того, что видит модель. Определения инструментов, JSON-схемы для структурированных выводов и изображения — все потребляют токены, и их легко забыть, потому что они не выглядят как «беседа». Большой каталог инструментов может тихо занимать заметный ломоть окна на каждом вызове. Как только у вас есть надёжный подсчёт, стратегии ниже — просто политики удержания этого числа там, где вы хотите.

Стратегии обрезки, от грубых до умных

Есть четыре распространённых способа держать историю под бюджетом, и реальные системы комбинируют их.

Обрезайте самые старые ходы. Простейшая политика: держите системный промпт плюс самые недавние N ходов и отбросьте остальное. Это дёшево и предсказуемо, и это правильное значение по умолчанию для чатов в стиле поддержки, где старый контекст редко важен. Её слабость — амнезия: модель забывает факты, установленные в начале длинной сессии.

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

Извлекайте вместо удержания. Для знаний, которые живут в документах, а не в диалоге, не носите их в контексте вообще. Храните их снаружи и на каждом ходу извлекайте только отрывки, релевантные текущему вопросу, и вставляйте их. Извлечение держит окно малым и постоянным независимо от того, сколько исходного материала существует, — разница между оплатой целого руководства каждый ход и оплатой тех двух абзацев, что важны.

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

Большинство долговечных чат-систем наслаивают их: фиксированный системный префикс, скользящая сводка середины, последние несколько дословных ходов и извлечение для всего фактического. Точная смесь зависит от того, приоритет ли ваш — припоминание, задержка или стоимость.

Кешируйте префикс, который вы не можете не пересылать

Некоторый контекст действительно должен присутствовать каждый ход — подробный системный промпт, фиксированный набор инструментов, обсуждаемый документ. Вы не можете обрезать его, не сломав задачу, но вы можете перестать платить полную цену за его переобработку, и именно это делает кеширование промптов. Когда стабильный префикс закеширован, провайдер переиспользует его и выставляет счёт за эти токены с крутой скидкой вместо полной ставки за вход. Управленческий ход — устроить беседу так, чтобы кешируемая область была максимальной и байт-стабильной — никаких меток времени или переупорядоченных инструментов внутри неё — и позволить изменчивому хвосту упасть после границы кеша. Механика по провайдерам — в кешировании промптов в OpenAI, Claude и Gemini; суть здесь в том, что кеширование и управление контекстом — одна и та же дисциплина, рассматриваемая под двумя углами. Обрезка снижает то, сколько токенов вы отправляете; кеширование снижает то, сколько стоят неизбежные токены.

Серверное состояние не делает историю бесплатной

Responses API позволяет продолжить нить через previous_response_id вместо пересылки всей истории, что реальный эргономический выигрыш — вы отправляете только новый ход, а сервер сшивает его с сохранённым контекстом. Соблазнительно прочитать это как «более ранний контекст теперь бесплатен». Это не так. Все предыдущие входные токены в цепочке всё равно выставляются как входные токены на каждом продолжении; цепочечность избавляет вас от отправки байтов по проводу, а не от оплаты контекста, который модель всё равно обрабатывает. Так что серверное состояние беседы меняет кто держит историю, а не платите ли вы за неё. Вам всё равно нужны обрезка и кеширование выше, чтобы контролировать стоимость; previous_response_id ортогонален этому.

Компакция: сжатие беседы на сервере

Когда беседа растёт достаточно длинной, что даже суммирование на вашей стороне становится неудобным, некоторые рабочие процессы в стиле Responses предоставляют серверный шаг компакции, который конденсирует текущий контекст в меньшее представление, от которого вы можете продолжить. Этот шлюз всплывает это как выделенный эндпоинт POST /v1/responses/compact, который релеит запрос компакции вышестоящей стороне, которая его поддерживает. Запрос несёт беседу для конденсации — model, input, instructions и опционально previous_response_id, tools и объект reasoning, — а ответ возвращает компактный output плюс объект usage с входными и выходными токенами, которые сама компакция израсходовала.

curl https://your-gateway.example.com/v1/responses/compact \
  -H "Authorization: Bearer AVE_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6",
    "previous_response_id": "resp_abc123",
    "instructions": "Condense the conversation so far, preserving decisions and open tasks."
  }'

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

Резервируйте место под ответ

Какую бы смесь вы ни выбрали, всегда оставляйте видимому ответу достаточно места. Задайте явный предел вывода и убедитесь, что context_used + reserved_output остаётся комфортно под окном, помня, что на рассуждающих моделях резерв должен также покрывать скрытые токены рассуждения. Пропустите это — и вы получите досадный сбой, где запрос успешен, выставляет вам счёт за большой вход и возвращает обрезанный ответ, потому что не осталось места для завершения. Применяйте тот же принцип к тайм-аутам: намеренно оставляйте запас.

Собираем всё вместе

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

FAQ

Что происходит, когда запрос превышает контекстное окно?

По умолчанию провайдер отклоняет запрос с ошибкой длины контекста и не обрезает промпт молча, поэтому вы должны предотвращать переполнение, считая токены до отправки. Исключение — явно включённое в Responses truncation: auto, которое удаляет элементы из середины входа, чтобы вместить слишком большой запрос. Это удобно, но означает незаметную потерю контента, поэтому включайте режим осознанно, а не как страховочную сетку. Поскольку входные, выходные токены и токены рассуждения разделяют один бюджет, слишком длинный промпт может также вызвать обрезанный ответ даже ниже жёсткого предела, если для генерации осталось слишком мало места.

Снижает ли использование previous_response_id мой счёт за токены?

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

Суммировать историю или обрезать её — что мне использовать?

Обрезка (держать последние N ходов) проще всего и подходит, когда старый контекст редко важен, но она забывает ранние факты. Суммирование сжимает старые ходы в компактную заметку, сохраняя суть по дополнительной стоимости на сжатие. Длинные ассистенты, которые должны помнить более ранние решения, обычно запускают оба: дословные недавние ходы плюс скользящая сводка более старой середины, с извлечением для всего фактического.

Что делает эндпоинт /v1/responses/compact?

Он релеит запрос компакции вышестоящей стороне, которая поддерживает конденсацию беседы Responses в меньшее представление, от которого вы можете продолжить. Вы передаёте беседу (через input/instructions и опционально previous_response_id), и он возвращает компактный output и счётчик usage для токенов, которые компакция израсходовала. Это возможность проброса — доступна только когда вышестоящая сторона её реализует, — и это серверная версия «суммируй-и-заменяй».

Постройте кривую, затем выровняйте её

Оснастите одну долго работающую беседу логированием общего числа токенов на каждом ходу, затем постройте кривую. Если она растёт устойчиво, добавьте скользящую сводку или шаг компакции на заданном пороге и наблюдайте, как кривая выравнивается в журналах использования. Затем пометьте системный префикс как кешируемый и подтвердите снижение платы за вход на каждом ходу. Эти две кривые «до/после» — число токенов и стоимость входа — показывают, действительно ли ваша политика контекста работает на вашем трафике, а не только в теории.

Ссылки