Почему ваш контекст стоит как чугунный мост
У каждого, кто хоть раз выкатывал LLM в продакшен, была минута откровения: вы смотрите на счёт за API и чувствуете, как кровь отливает от лица. Токены утекают рекой, а вы даже не знаете, какие именно куски промпта реально нужны модели. Я проработал с десятками команд, и почти везде одно и то же — в контекст пихают всё подряд: историю чата, результаты RAG-поиска, системные промпты на три страницы. Потом удивляются, почему ответы тормозят, а счёт в AWS или OpenAI растёт.
В 2026 году на рынке появился новый класс инструментов, которые я называю контекстными профилировщиками. Это не просто мониторинг токенов — это хирургический скальпель для вашего контекста. Они показывают, какие именно последовательности токенов модель действительно использует при генерации ответа, а какие висят мёртвым грузом. И да, есть открытая библиотека ContextProfiler (v2.1 на июнь 2026), которую мы и разберём.
Но прежде — короткая анатомия пустых трат. Вы знали, что до 40% токенов в промпте часто не участвуют в формировании ответа? Особенно это заметно в RAG-системах, где мы подмешиваем десять документов, а модель смотрит только в два из них. Я писал об этом в статье Почему RAG-система извлекает правильные данные, но даёт неверный ответ — там как раз про то, что найденные документы часто нерелевантны для конкретного запроса, и модель путается. Профилировщик решает эту проблему на корню: он скажет, какие чанки документа реально сработали.
Типичная боль: вы передаёте в промпт 20 страниц логов системы, чтобы модель проанализировала ошибку, но она использует только последние 10 строк. Остальные 19.5 страниц — деньги на ветер. Профилировщик показывает это чёрным по белому.
Как работает контекстный профилировщик (и почему это не очередная игрушка)
Идея проста до безобразия: мы перехватываем запрос к LLM, прогоняем его через модель анализа (обычно лёгкую, типа специально обученного кодировщика) и сопоставляем входные токены с выходными. Технически это делается через attention-карты: профилировщик смотрит, на какие входные токены модель обращала внимание при генерации каждого выходного токена. Суммируем по слоям — получаем веса важности каждого входного токена. Токены с весом ниже порога — кандидаты на удаление.
В ContextProfiler этот процесс называется context saliency analysis. Он не требует доступа к весам модели — работает через логпробс и хиты кэша. Да, точность не 100%, но на практике хватает, чтобы сократить контекст на 30-60% без потери качества.
Звучит логично, но есть нюанс: профилировщик не умеет предсказывать, что понадобится модели в будущем. Он только анализирует уже сделанные запросы. Значит, мы должны сначала запустить его на репрезентативной выборке, собрать статистику, а потом применить оптимизацию. Это цикл: измерь → вырежи → проверь → повтори.
Ставим ContextProfiler — три строчки, и ты в игре
Установка через pip:
pip install context-profiler
Библиотека поддерживает все популярные провайдеры: OpenAI, Anthropic, локальные модели через vLLM или llamacpp. Для интеграции с существующим кодом достаточно обернуть вызов LLM в профилировщик.
Вот как НЕ надо делать (типичная ошибка новичков):
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(model="gpt-4o", messages=messages)
print(response.usage.total_tokens) # бесполезно — цифра есть, а где срезать?
Этот код показывает только общее число токенов, но ничего не говорит о важности каждого блока. Правильно — использовать профилировщик как middleware:
from context_profiler import ContextProfiler
from openai import OpenAI
profiler = ContextProfiler(saliency_threshold=0.15) # отбрасывать токены с весом < 15%
client = OpenAI()
with profiler.track() as session:
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": long_system_prompt},
{"role": "user", "content": user_query_with_rag}
]
)
# Получаем отчёт по каждому сегменту контекста
report = session.report()
print(report.salient_tokens_ratio) # 0.42 — значит 58% контекста не используется
1 Собираем профиль на репрезентативной выборке
Запустите профилировщик на, скажем, 1000 реальных запросах. Сохраните все отчёты. Обратите внимание на распределение важности по сегментам контекста: системный промпт, контекстные документы, история диалога. Часто оказывается, что системный промпт весит много, но его редко используют полностью. Или что история диалога из последних 10 сообщений важна, а из первых 20 — почти нет.
2 Оптимизируем контекст на основе профиля
Допустим, профиль показал, что в RAG-контексте 70% токенов имеют вес ниже 0.1. Это значит, что вы можете либо уменьшить количество возвращаемых документов (перейти с top_k=10 на top_k=4), либо обрезать сами документы до первых N токенов, где сосредоточена важность. Как это сделать правильно, я описывал в материале Когда токены вздуваются — обратите внимание на разницу в токенизации разных языков; профилировщик это учитывает автоматически.
3 Проверяем качество после сокращения
Самый страшный сон: вы сократили контекст на 40%, а модель начала ошибаться. Поэтому после каждой итерации нужно прогнать авто-тесты или хотя бы семплирование. ContextProfiler умеет сравнивать ответы модели до и после оптимизации с помощью встроенной метрики semantic similarity (на базе эмбеддингов). Если расхождение больше 5% — откатываем изменения.
Что показывает реальный профиль: разбор на примере
Недавно я профилировал один сервис поддержки на основе LLM. Контекст состоял из системного промпта (1800 токенов), истории чата (3000 токенов) и результатов RAG-поиска (5000 токенов). Итоговый профиль:
| Сегмент | Токенов | Используется | % мусора |
|---|---|---|---|
| System prompt | 1800 | 850 | 53% |
| История (последние 5 сообщ.) | 1200 | 1100 | 8% |
| История (сообщ. 6-10) | 1800 | 200 | 89% |
| RAG-документы | 5000 | 2100 | 58% |
Очевидно, что историю глубже 5 сообщений можно смело выбрасывать — сэкономили 1800 токенов. Системный промпт переписал с 1800 до 900 токенов, выкинув инструкции, которые модель не читала. RAG-документы стали возвращать только топ-3 результата вместо топ-5 (убрали два самых тяжёлых и неиспользуемых). Итог: контекст сократился с 9800 до 4200 токенов. Расходы на API упали на 57%, а качество ответа по тестам не изменилось.
Три грабли, об которые спотыкаются даже сеньоры
Грабли 1: Доверие к единичному профилю. Профилировщик анализирует один запрос. На тысяче запросов картина может отличаться. Если вы оптимизируете на основе всего 10 запросов, рискуете вырезать то, что модель использует в других сценариях. Всегда собирайте профиль на репрезентативном датасете, а ещё лучше — внедрите непрерывное профилирование в production. Для этого можно использовать Tokentap — MitM-прокси для мониторинга токенов; он как раз подходит для сбора непрерывных профилей без изменения кода.
Грабли 2: Не учитывать динамику контекста. Сегодня модель активно использует один раздел системного промпта, а завтра, после обновления, может начать использовать другой. Если вы один раз «оптимизировали» и забыли — через месяц всё сломается. Нужно автоматизировать цикл: каждую ночь запускать профилировщик на последних логах, и если паттерн важности изменился — бить тревогу или автоматически адаптировать контекст.
Грабли 3: Спрятанные в неактивных токенах подсказки. Даже с низкой салиенсностью некоторые токены могут быть важны для правильного понимания косвенных отсылок. Например, вы вырезали фрагмент документа, где упоминалось название компании, и модель перестала понимать контекст. Профилировщик может не показать высокий вес у такого токена, если он используется только в паре с другими. Поэтому после каждой итерации строго обязательна валидация качества — без неё вы рискуете получить модель, которая отвечает невпопад.
Как связать профилировщик с маршрутизацией и кэшированием
Когда вы знаете, какие части контекста реально нужны, вы можете пойти дальше: динамически подставлять только нужные сегменты в зависимости от запроса. На эту тему я уже писал про LLMRouter — снижение расходов на 30-50%. Комбинируя профилировщик и роутер, вы строите систему, которая модельному узлу отправляет минимально необходимый контекст, а дешёвому классификатору (например, на базе BERT) отдаёт всю историю для принятия решения — это радикально дешевле, чем гонять всё через LLM.
Плюс не забывайте про кэш. Если вы сократили контекст, запросы становятся более повторяемыми, и доля кэш-хитов растёт. В моём проекте после оптимизации hit rate кэша vLLM подскочил с 12% до 44%. Метрики для стабильной работы self-hosted LLM я разбирал в статье 5 ключевых метрик для self-hosted LLM — cache hit ratio там на первом месте.
Скрещиваем с топ-k и time-to-first-token
Ещё один приём: после обрезки контекста вы можете уменьшить количество генерируемых токенов (если ответы тоже были раздуты). Тут поможет оптимизированный Top-K на CPU — на инференсе он ускоряет выборку, а профилировщик подскажет, какие выходные токены избыточны.
И конечно, не забывайте про динамическую лень: если ваш профилировщик показывает, что контекст после обрезки стал маленьким, вы можете ставить менее агрессивные таймауты на prefill. Настройку такой динамики я описывал в статье про LazyGate для vLLM — она идеально ложится на наш пайплайн.
А что с неанглийскими языками?
Если ваш контекст на русском, китайском или арабском, токенов будет больше, чем для английского, при том же смысле. Раздувание в неанглийских языках — отдельная боль, и контекстный профилировщик здесь особенно полезен: он покажет, какие именно токены «лишние» именно в вашем языке. Я подробно разбирал эту тему в материале про вздувание токенов. Совет: для неанглийских запросов порог салиенсности можно повысить до 0.25 — тогда отсев будет агрессивнее, а качество, как показывает практика, не страдает, потому что много токенов — это артефакты токенизации.
Когда профилировщик бессилен: честный диагноз
Есть случаи, когда контекстный профилировщик не спасёт:
- Модель использует почти все токены равномерно (например, при суммаризации длинных текстов). Тогда вырезать нечего.
- У вас одна-единственная цепочка запросов без повторяющихся паттернов — профиль не накопит статистику.
- Вы работаете с закодированным или сильно структурированным контекстом (JSON, XML), где каждый токен важен для формата — но даже здесь можно выбросить лишние ключи.
Но в 90% продакшен-систем профилировщик даёт драматический эффект. Особенно если совместить его с маршрутизацией и правильной архитектурой промптов.
Не верьте никому, кто говорит, что можно срезать токены вслепую, без анализа. Только профилировщик даёт объективную картину. И да, я не постесняюсь сказать: если вы до сих пор не используете профилирование контекста, вы просто выбрасываете деньги в мусорку. Каждый день.