Главная / Статьи

Маршрутизация трафика Claude Code по заголовкам вместо обработки запроса

Узнайте, как заголовки-советы в режиме опт-ин от Claude Code позволяют шлюзу больших языков модели приоритизировать, контролировать объем и управлять кэшами на основе метаданных запроса, не анализируя содержимое вводных данных.

Издатель: REACTAPP.TOP9 мин чтения1990 слов

Источники: Your LLM Gateway Reads Your Prompt to Decide Where to Send It. Claude Code Just Shipped Five Headers That Make That Unnecessary.

Когда компания направляет трафик Claude Code через шлюз LLM, этот шлюз должен принимать решения по каждому запросу перед его пересылкой: какой источник данных использовать, в какую очередь добавить запрос, какой лимит скорости применить и какой приоритет назначить. До недавнего времени единственным источником информации для принятия таких решений было тело запроса, то есть ваши инструкции, содержимое файлов, результаты работы инструментов и CLAUDE.md. Набор заголовков запроса с опцией включения, добавленный в недавней версии Claude Code, перемещает эту информацию на уровень заголовков запроса. Ниже вы узнаете, что можно определить с помощью каждого заголовка, как меняется поведение прокси при использовании этих заголовков и в каких случаях им всё равно нельзя доверять.

Почему шлюзы в итоге читают ваши инструкции

Проверка тела запроса — это не теоретический вопрос; именно так сегодня работают многие маршрутизаторы. Семантические маршрутизаторы, такие как vLLM Semantic Router, извлекают запрос пользователя, встраивают его с помощью модели в стиле BERT и сравнивают полученный вектор с векторами эталонных задач для классификации запроса. Маршрутизаторы, оптимизированные для снижения задержек при прямой передаче данных, могут определить название модели примерно из первого килобайта и передавать остальную часть данных, но любой маршрутизатор, который должен классифицировать запрос, вынужден хранить в буфере и проверять всё тело запроса.

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

В чат-логе версии Claude Code 2.1.273 от 15 сентября 2026 года было добавлено пять заголовков, предназначенных для операторов шлюзов. В совокупности они скорее представляют собой минимальные метаданные, необходимые шлюзу для работы в роли планировщика без функций читателя, нежели функцию обеспечения видимости данных.

Ограничения первоначальных заголовков идентификаторов

До версии 2.1.273 в руководстве по совместимости шлюзов были описаны три заголовка Claude Code, все из которых являлись идентификаторами:

+--------------------------------+---------------------------------+
| HEADER                         | WHAT IT IS                      |
+--------------------------------+---------------------------------+
| x-claude-code-session-id       | which session                   |
| x-claude-code-agent-id         | which subagent (if any)         |
| x-claude-code-parent-agent-id  | which agent spawned it          |
+--------------------------------+---------------------------------+
                  |
                  v
        good for GROUPING after the fact
        useless for DECIDING before forwarding

Документация предусматривает их использование для агрегации: идентификатор сессии позволяет группировать всё, что было отправлено в рамках сессии, без необходимости парсинга тела запроса, а идентификатор агента в сочетании с идентификатором сессии позволяет присваивать затраты агентам, работающим параллельно. Это и есть учет. Достаточно этого для панели контроля затрат, но недостаточно для планирования. Знание того, что запрос пришел из сессии abc и агента def, ничего не говорит о том, насколько он будет дорогим, сколько времени займет или может ли система позволить себе ждать. Поэтому любой шлюз, стремящийся быть более умным, чем простой счетчик, вынужден был открывать тело запроса.

Пять новых заголовков-советов

Согласно чарту изменений, в версии 2.1.273 было добавлено пять заголовков, все они включаются одновременно с параметром CLAUDE_CODE_GATEWAY_HINT_HEADERS=1. Два из них описывают вызывающую сторону (x-claude-code-agent-type и x-claude-code-request-class), один описывает недавние временные показатели (x-claude-code-prev-tool-durations), а пара заголовков отвечает за перезапись контекста (x-claude-code-context-compacted вместе с x-claude-code-compaction).

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

Группировка по решениям, которые позволяют принимать каждый заголовок:

+---------------------------+------------------------------------------+
| HEADER                    | DECISION IT UNBLOCKS AT THE EDGE         |
+---------------------------+------------------------------------------+
| request-class             | is this a real turn, or a small          |
|                           | internal call? -> priority, cheap pool   |
+---------------------------+------------------------------------------+
| agent-type                | which kind of subagent is asking         |
|                           | -> per-agent-type budgets and quotas     |
+---------------------------+------------------------------------------+
| prev-tool-durations       | how long the last tools took             |
|                           | -> timeout and retry window sizing       |
+---------------------------+------------------------------------------+
| compaction                | this turn IS the summarization call      |
|                           | -> never count it as user latency        |
+---------------------------+------------------------------------------+
| context-compacted         | the prefix just changed under you        |
|                           | -> do not expect a cache hit this turn   |
+---------------------------+------------------------------------------+

Кратко:

  • request-class отделяет реальные этапы диалога от небольших внутренних вызовов, что позволяет уделять приоритет первым и направлять вторые в более дешевый пул.
  • agent-type указывает, какой тип субагента осуществляет вызов, что обеспечивает возможность установления бюджетов и квот для каждого типа агента.
  • prev-tool-durations сообщает о времени выполнения недавних операций с инструментами, что помогает определять размеры временных ограничений и интервалов повторных попыток.
  • compaction маркирует запрос, выполняющий само краткое изложение, поэтому он никогда не должен учитываться при расчете задержек для пользователя.
  • context-compacted сигнализирует о том, что префикс диалога только что был переписан, поэтому ожидать доступа из кеша не стоит.

Все это не является новой информацией. Шлюз уже может определить класс запроса, различая полный системный промпт Claude Code от упрощенного промпта классификатора, определить тип агента из раздела системного промпта, предназначенного для агентов, и выявить степень сжатия по структуре массива сообщений. Заголовки не раскрывают ничего дополнительного о вас. Изменяется лишь цена знаний: вместо обработки до мегабайта исходного кода шлюз читает короткую строку из заголовков.

Та же самая правило маршрутизации, до и после

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

// BEFORE: the router has to read the conversation to classify it
const body = await readEntireBody(req);        // buffers the whole prompt
const parsed = JSON.parse(body);               // your files are now in gateway memory
const sys = flattenSystemBlocks(parsed.system);
const isBackground =
  sys.includes("summarize the conversation") ||
  parsed.messages.length > COMPACT_THRESHOLD;

и только после этого переслать сохраненный в буфере текст:

route(isBackground ? "cheap-pool" : "interactive-pool", body);

У этого подхода три проблемы, от наименее серьезной к самой серьезной. Буферизация всего содержимого уничтожает задержку потока данных. Поиск по формулировкам запроса крайне чувствителен, поскольку эти формулировки меняются между версиями Claude Code. Самое худшее — полный текст вашего репозитория теперь находится в памяти процесса слоя маршрутизации, в его дампах памяти и, возможно, в логах; это место не отображается ни на одной архитектурной диаграмме, и никто даже не подумал о его защите.

С использованием заголовков-подсказок маршрутизатор считывает два значения из оболочки:

// AFTER: the router decides on the envelope and never touches the body
const cls  = req.headers["x-claude-code-request-class"];
const comp = req.headers["x-claude-code-compaction"];

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

// value strings below are illustrative: confirm them against your own
// traffic, since the wire format is not documented yet
const isBackground = Boolean(comp) || cls === "background";route(isBackground ? "cheap-pool" : "interactive-pool", req);  // streams through

Не происходит буферизации, нет парсинга JSON и никаких сообщений не хранится в памяти. Руководство по совместимости уже разрешает такой подход: помимо anthropic-workspace-id, anthropic-beta и anthropic-version, заголовки описываются как данные, которые шлюз может использовать для отслеживания, атрибуции или маршрутизации, и не обязан передавать дальше. Эти указания предназначены для использования исключительно на уровне шлюза; поскольку модель никогда их не видит, они могут быть примитивными и недорогостоящими.

Пара значений, обозначающая сжатие, является сигналом кэширования

Два из этих заголовков кажутся избыточными, но отвечают на разные вопросы. Первый, x-claude-code-compaction, устанавливается при самом вызове, который генерирует краткое изложение. Второй, x-claude-code-context-compacted, появляется при последующих вызовах, после того как сжатие уже было выполнено.

Это различие имеет значение при работе с кэшем. Ключи кэша для промптов состоят из префиксов, сформированных на основе инструментов, затем системного промпта и сообщений; поэтому любые изменения в начале ключа делают недействительными все данные, следующие за ним. Запись в кэш также стоит дороже, чем его чтение, поэтому ненужные записи представляют собой чистую потерю средств. Сжатие является главным фактором, приводящим к аннулированию данных в обычной сессии: оно заменяет накопленную историю на краткое резюме, что по определению создаёт совершенно новый префикс.

turn N        turn N+1 (compaction)      turn N+2
+---------+     +------------------+     +------------------+
| prefix  |     | compaction: 1    |     | context-         |
| stable  | --> | rewrites history | --> | compacted: 1     |
| cache   |     | EXPECT A MISS    |     | new prefix is    |
| hits    |     | bill it as       |     | now the stable   |
+---------+     | background       |     | one, re-warm it  |
                +------------------+     +------------------+

Шлюз, который сохраняет собственную кэш-память, но не имеет никакого представления о процессе сжатия, в момент его выполнения ведет себя крайне плохо: он выполняет полный поиск, не находит нужную информацию, сохраняет запись для префикса, который уже через один шаг станет устаревшим, а затем сообщает о снижении частоты успешных поисков, что рассматривается как дефект. Благодаря заголовкам он может пропустить поиск при запросе на сжатие, отнести этот вызов к фоновой работе и намеренно «разогреть» новый префикс в следующем шаге, когда тот станет стабильным.

Подсказки — это утверждения клиента, а не учетные данные

И чек-лист изменений, и названия переменных используют эти заголовки с подсказками, и здесь важна точность термина. Подсказка — это непроверенное утверждение, сделанное клиентом. Значение x-claude-code-request-class определяется самим Claude Code; никакой компонент выше в иерархии его не проверяет.

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

Вторая практическая проблема — внедрение. Заголовки отключены, если только их не включить явно, что является правильным решением для метаданных, раскрывающих структуру сессии для промежуточного сервера. Учитывая их отсутствие в списках переменных окружения на момент написания текста, вряд ли какие-либо установки будут их использовать. В организации их обычно необходимо внедрять с помощью управляемых настроек администратором, обратившим внимание на отдельную строку в журнале изменений.

План внедрения для операторов шлюзов

Если ваша команда управляет шлюзом для трафика Claude Code, осторожный путь к внедрению выглядит следующим образом:

  • Включите CLAUDE_CODE_GATEWAY_HINT_HEADERS=1 для небольшой группы испытателей.
  • Записывайте все пять заголовков в течение примерно недели, не предпринимая по отношению к ним никаких действий.
  • Сравните их значения с решениями, принимаемыми вашим текущим классификатором для анализа содержимого.
  • Если они согласны, переключите маршрутизацию на заголовки, прекратите буферизацию тела запросов и удалите парсер.
  • Решения о правах доступа должны приниматься на основе авторизованной идентичности, а не значений подсказок.
  • Результатом становится значительно меньший радиус воздействия: исходный код ваших разработчиков больше не должен проходить через память слоя маршрутизации, и это требует всего одной переменной окружения.

    Заключение

    Сами заголовки характерны именно для Claude Code, но извлеченные из этого урока принципы применимы к любой платформе агентов. Любой слой, расположенный перед агентом, должен классифицировать запросы перед их дальнейшей передачей, и для этого существует только два способа: выводить ответ из данных запроса или получать его в виде явных метаданных. Метод вывода всегда работает, но он всегда оставляет копию конфиденциального контента в компоненте, у которого не было причин его хранить. Использование явных метаданных требует дополнительной работы над проектированием, но это единственный вариант, при котором посредник может правильно направлять запросы, не получая при этом самих данных. Чтобы узнать больше о том, что предоставляет шлюз, ознакомьтесь с обзором шлюза LLM в документации Claude Code.