
Инфраструктура маршрутизации OrcaRouter: маршрутизация с учетом сессий и эскалация до frontier-моделей
- obsidianНОВИНКАQwen3.8 27B Uncensored (Aggressive)2026-08-15$0.40 / $4.21 за 1 млн токенов · 22 tok/s
- qwenНОВИНКАQwen: Qwen3.8 27B (free)2026-08-1343 tok/s
- deepseekНОВИНКАDeepSeek: DeepSeek V4 Pro 08132026-08-1253Интеллект69Кодинг
- grokНОВИНКАSpaceXAI: Grok 4.62026-08-1261Интеллект77Кодинг
- metaНОВИНКАMeta: Muse Spark 1.22026-08-0557Интеллект72Кодинг
- qwenQwen: Qwen3.8 Max2026-08-0358Интеллект72Кодинг
- deepseekDeepSeek: DeepSeek V4 Flash 07312026-07-3152Интеллект69Кодинг
- minimaxMiniMax: MiniMax-H32026-07-31minimax/minimax-h3
- qwenQwen: Qwen3.7 Flash2026-07-27$0.03 / $0.13 за 1 млн токенов · 273 tok/s
- orcaOrcaDub: OrcaDub 1.02026-07-27orca/dub
- anthropicAnthropic: Claude Opus 52026-07-2463Интеллект78Кодинг
- googleGoogle: Gemini 3.6 Flash2026-07-2152Интеллект69Кодинг
- googleGoogle: Gemini 3.5 Flash-Lite2026-07-2137Интеллект49Кодинг
- metaMeta: Muse Spark 1.12026-07-1653Интеллект71Кодинг
- kimiMoonshotAI: Kimi K32026-07-1560Интеллект76Кодинг
- openaiOpenAI: GPT-5.6 Luna2026-07-0952Интеллект71Кодинг
- openaiOpenAI: GPT-5.6 Terra2026-07-0957Интеллект77Кодинг
- openaiOpenAI: GPT-5.6 Sol2026-07-0961Интеллект77Кодинг
- grokxAI: Grok 4.52026-07-0856Интеллект72Кодинг
- tencentTencent: Hy32026-07-0642Интеллект59Кодинг
ORCAROUTER · АРХИТЕКТУРА МАРШРУТИЗАЦИИ
Каждый LLM-шлюз, который кэширует промпты, должен привязывать диалог к одной модели. {{1}}Каждый шлюз, который привязывает диалог, принимает решение о маршрутизации на основе наименее информативной реплики этого диалога.{{/1}} Это отчёт об этом компромиссе, {{2}}а также о механизме tiered-stickiness, который OrcaRouter поставляет, чтобы избежать этого.{{/2}}
Тема: LLM-шлюз OrcaRouter (Go / Gin / Redis) · Компонент: привязка сессий + механизм Frontier Escalation · Метод: воспроизведение 400 сессий на продакшн-коде принятия решений · Дата: 14 августа 2026
АННОТАЦИЯМаршрутизация LLM на уровне запросов — оценка каждого запроса независимо и отправка его на самую дешёвую подходящую модель — это режим, которому посвящены почти все опубликованные работы по маршрутизации. Но это также неправильный режим для трафика, который сейчас составляет основной объём шлюзового трафика: многоходовых агентных сессий, где промпт на 90 % состоит из перенесённого контекста, а кэш промптов провайдера вознаграждает за непрерывность. Переключение моделей в середине разговора приводит к потере скидки 10× на общий префикс, поэтому шлюзы закрепляют сессии. Но закрепление, сделанное на первом ходе, — это закрепление, сделанное на ходе с наименьшим количеством информации, и оно сохраняется на протяжении всего разговора.
100 / 100 — латентно-сложные сессии, чей результат первого хода неотличим от тривиального
+16% — дрейф оценки сложности, обусловленный одной лишь длиной транскрипта, при одинаковой сложности задачи
45% — от стоимости always-frontier при покрытии 67 % его сложных поворотов
0.019 — margin between the shipped gate and the ceiling of realistic scores
1 Два режима маршрутизации
LLM-шлюз, стоящий перед множеством провайдеров, должен на каждый запрос отвечать на один вопрос: какая модель его обслуживает? Существуют два структурно различных способа ответить на него, и литература и производственная реальность разошлись в том, какой из них важен.
Маршрутизация на уровне запросов рассматривает каждый запрос как независимый. Оценщик оценивает сложность запроса или прогнозируемое качество ответа, и запрос направляется самой дешёвой модели, которая, как ожидается, с ним справится. Это режим практически всех опубликованных работ по маршрутизации: RouteLLM обучает маршрутизаторы на данных предпочтений, которые достигают 95 % качества GPT-4 при 14 % вызовов сильной моделиsup>[1]/sup>; FrugalGPT использует каскад от дешёвой к дорогой модели с проверкой приём/отклонение и сообщает о снижении затрат до 98 %sup>[2]/sup>; RouterArena создаёт эталон из 8 400 запросов для сравнения маршрутизаторов именно по этому критериюsup>[3]/sup>. Единицей анализа является запрос.
Маршрутизация с учетом сеансов
Причина, по которой существует маршрутизация с учётом сеансов, — не элегантность. Это арифметика.
2 Экономика кэша, которая делает липкость обязательной
In a multi-turn agent session, turn n's prompt is turn n−1's prompt plus a delta. By turn 10 the carried-over prefix is the overwhelming majority of the input tokens. Every major provider now prices that prefix differently depending on whether it is a cache hit:
Таблица 1.Семантика кэша промптов по провайдерам. Кэш индексируется по точному префиксу и по обслуживающему ключу — переключение модели или ротация ключа считается холодным чтением по полной стоимости.
OrcaRouter кодирует именно эти времена жизни как TTL пинов: карта окон кэша провайдеров по типу канала — 5 минут для OpenAI, Anthropic и Gemini, 60 минут для DeepSeek — со значением по умолчанию 5 минут для несопоставленного провайдера. Пин канал+ключ истекает вместе с этим окном, поскольку устаревший индекс ключа не имеет кэш-ценности и только искажает балансировку нагрузки. Модельный пин, на Redis-развертывании и для идентификатора сессии, допускающего длинный пин, сохраняется в течение 30 дней — не из-за кэш-ценности, которой уже давно нет, а для непрерывности формата запроса. Смена модели в середине разговора вынуждает конвертацию формата запроса, которая может быть несовместима с данными: блоки мышления и идентификаторы вызовов инструментов не обязательно переживают перевод между схемами провайдеров.
НЕДООЦЕНЕННАЯ ДЕТАЛЬ
Кэши промптов привязаны к API-ключу, а не к модели. Шлюз, который фиксирует модель, но распределяет нагрузку между тремя ключами на одном канале, всё равно будет читать из холодного кэша в двух из трёх обращений. Именно поэтому пин канала в OrcaRouter хранит {ChannelID, KeyIndex}, а не идентификатор канала, и поэтому пин сбрасывается, когда записанный индекс ключа больше не указывает на включённый ключ — повышенный, но ротированный ключ смещал бы выбор в сторону холодного кэша в обход балансировки, что является худшим из обоих вариантов.
Пины мягкие везде: пин без разрешимого идентификатора сессии не выполняет никаких действий; отключенный или нездоровый закрепленный канал откатывается к обычному сбалансированному выбору; а пин к каналу с нулевым весом в смешанном пуле отбрасывается, поэтому липкость не мешает администратору, осушающему канал. Они никогда не приводят к сбою запроса.
3 Ловушка: липкость отключает маршрутизатор
Вот режим отказа. В OrcaRouter-овскомпредэскалационном кодовом пути, для маршрутизатора с поддержкой сессий при любой не-DSL стратегии, привязка session→model вернула
Это было бы терпимо, если бы первый ход был репрезентативным. Систематически это не так, по двум усугубляющим причинам.
3.1 Ход 1 является наименее информативным ходом.
Скаляр сложности (service/model_router_difficulty.go) представляет собой взвешенную линейную комбинацию шести лексических признаков:
LogPromptTokens × 0.20, ограничение: log(8001) ≈ 8.99
ReasoningCueCount × 0.15, максимум 5
SystemPromptLogLen × 0.10 с ограничением log(2001) ≈ 7.60
CodeKeywordDensity × 0.20 предел 5.0 (совпадений на 100 символов)
HasTools × 0.15 уже 0/1
MathMarkerCount × 0.20 не более 5
Короткое вступительное сообщение без истории получает низкий балл почти по построению: токенное слагаемое с весом 0,20 находится почти на нижней границе, а термины рассуждений/математики срабатывают на лексику, которую у пользователя ещё не было повода использовать. Поэтому сессии фиксируют модель слабого пула в момент наименьшей информации — а с привязкой модели на 30 дней на базе Redis эта фиксация оказывается долгой.
Рисунок 1. Средняя сложность последнего хода в зависимости от номера хода разговора, рассчитанная по 100 латентно-сложным и 200 действительно лёгким сессиям, оценённым продакшн-скоррером. На ходе 1 — ходе, на котором записывается закреп, — две популяции неразличимы (0.210 против 0.208). Сложная популяция пересекает гейт на ходе 5. При политике, основанной только на закрепе, все 100 латентно-сложных сессий попадают в дешёвый пул до того, как появляется хоть какое-то из этих свидетельств.
3.2 Длина маскируется под сложность
Вторая проблема тоньше, и она подрывает очевидное исправление. Если вы просто повторно запускаете порог сложности на каждом ходу, вы повторно запускаете его на оценке, вычисленной по всему объединённому транскрипту. Эта оценка имеет встроенный восходящий дрейф: член LogPromptTokens с весом 0.20 монотонно растёт с длиной разговора, а для любой сессии агента члены HasTools (0.15) и SystemPromptLogLen (0.10) фактически являются постоянными нижними пределами. Длинная скучная сессия выглядит всё более трудной.

Рисунок 2. Артефакт смещения по длине, измеренный на 60 сессиях, состоящих исключительно из тривиальных правок («переименовать эту переменную», «добавить проверку на nil»). Оценка по полной стенограмме дрейфует на +16 % в течение 25 ходов при постоянной сложности задачи; оценка последнего хода (дельта) остаётся плоской. Наивная переоценка полной стенограммы на каждом ходу приводила бы к эскалации сессий за то, что они длинные.
Поставляемое OrcaRouter исправление — это отдельный дельта-экстрактор (service/model_router_delta.go), который оценивает только последний ход — новый текст пользователя плюс любые результаты инструментов, прикреплённые после последнего сообщения ассистента, — повторно используя те же веса и ограничения, но намеренно обнуляя SystemPromptLogLen, который не является частью дельты. Плоская синяя линия на рисунке 2 — это тот экстрактор.
4 Дизайн: многоуровневая липкость
Наивный выход из блокировки на первом ходе — перенаправлять каждый ход, что является лишь маршрутизацией на уровне запросов и жертвует кэшем. Наивное исправление в другую сторону — сделать закрепление памятью о том, что «эта сессия стала сложной», что не может выразить снижение напряжённости и не может быть ограничено. Дизайн OrcaRouter отвергает оба подхода.
Переформулировка: сессия привязана к модели в пределах уровня, и небольшое Redis-состояние уровня является единственной памятью эскалации. Привязка к модели никогда не является памятью.
Уровневые пулы. Сильный уровень — это итоговый эскалационный пул (escalation_pool, по умолчанию — strong_pool маршрутизатора). Базовый уровень — это AllowedModels за вычетом пула сильного уровня; модель, входящая в оба пула, относится к сильному уровню. Внутри базового уровня разбиение сложности gated_adaptive на слабые, средние и сильные диапазоны продолжает работать точно так же, как раньше.
Закрепления, ограниченные уровнем. Ключ закрепления модели сильного уровня получает суффикс :t:strong; базовый уровень сохраняет прежний ключ без изменений. Поэтому эскалация сохраняет базовое закрепление, так что сессия после деэскалации — или возобновлённая после истечения состояния уровня — возвращается к той самой модели, с которой начала, а не к произвольному повторному выбору. Сильные закрепления записываются только с коротким TTL окна провайдера: 30-дневное сильное закрепление пережило бы 4-часовое состояние уровня, которое послужило его обоснованием.
Шлюз срабатывает первым. В selectByStrategy (service/model_router.go:1374) уровень определяется заранее, множество кандидатов сужается до пула этого уровня, и только затем обращаются к липкому пину — в пределах этого уровня. Это структурное исправление для §3: вычисление сложности и триггеры эскалации выполняются на каждом шаге, прежде чем пин сможет их обойти.
4.1 Три класса триггеров, ранжированные по доверию
Таблица 2. Триггеры эскалации. Ни один нечеткий сигнал никогда не срабатывает в одиночку; только явный запрос клиента фиксируется при n=1, и даже он подчиняется ограничениям.
Три гигиенических инварианта являются несущими. Страйки дедуплицируются по идентификатору запроса через кольцевой буфер, поэтому перемежающиеся клиентские повторные попытки не могут привести к двойному учёту. Сбой инфраструктуры никогда не является сбоем возможности — 429-е, 5xx-е и резервные каналы никогда не считаются страйком; учитываются только сигналы качества после успеха. А «ход» определяется как завершённый запрос с успешным выставлением счёта, прошедший оценку страйков, поэтому неудачные запросы не продвигают ни затухание страйков, ни счётчик чистых ходов.
4.2 Resolve чист; commit откладывается
Наиболее значимое структурное свойство движка заключается в том, что ResolveEscalation ничего не записывает. Он возвращает решение и список ожидающих намерений. Распределитель применяет эти намерения в своём блоке post-success к свежему чтению внутри транзакции Redis WATCH. Это важно, потому что резолвер выполняется на путях, которые никогда не должны изменять состояние: спекулятивные разрешения цепочек резервных вариантов, диагностические эндпоинты только для чтения и запросы, которые позже получают 403 или завершаются ошибкой выше по потоку. Повторное применение намерений к свежему состоянию также означает, что устаревший параллельный писатель не может затереть зафиксированную эскалацию, а две конкурирующие идентичные эскалации объединяются идемпотентно.
4.3 Капсы, и почему они связывают всё
A false-positive escalation costs (strong − base) price × remaining warm-episode tokens, and it costs it silently — nothing fails. The blast radius is bounded by caps that apply to every class:
escalation_max_per_session (по умолчанию 1). Понижение эскалации и сбросы клиента не возвращают его, что закрывает путь эксплуатации цикла сброса.
На каждый маршрутизатор лимит доли эскалаций (по умолчанию 20 %) за скользящее окно 24–48 ч на основе дневных бакетов Redis, плюс кросс-маршрутизаторный лимит рабочего пространства. При достижении лимита вся маршрутизация эскалаций подавляется, включая явные запросы и разовые повышения.
Деэскалация только на границах холодного кэша, поэтому ложное срабатывание ограничено одним тёплым эпизодом.
Причина, по которой класс A соблюдает лимиты, — это вывод модели угроз, а не предпочтение политики: на API-шлюзе тот, кто владеет токеном рабочего пространства, контролирует заголовки. Путь, освобождённый от лимитов, по принципу «клиент так захотел», — это не учитываемый канал расходов. В §7 измеряется, что происходит, когда каждый клиент злоупотребляет этим.
4.4 Деэскалация асимметрична по замыслу
Escalate on corroborated evidence; de-escalate only when it is free. A strong session returns to base only when all of: the session is cache-cold (idle past the provider window recorded at escalation), it has accumulated ≥3 strike-free evaluated turns, and the latest delta difficulty is below T1. Inside the warm window, a switch pays a full-price cold re-read — flapping is the one guaranteed way to make escalation cost-negative.
5 Метод
Мы измерили механизм, прогнав синтетический корпус сессий через реальный продакшн-код принятия решений. Тестовая обвязка — это Go-тест в пакете сервиса, который для каждого хода вызывает ResolveEscalation и CommitEscalationDecision против хранилища уровней на базе miniredis, с реальными модулями расчёта сложности, реальными генераторами страйков на стороне запроса и реальной механикой ограничения долей. Никакая часть пути принятия решений не реализована заново и не заменена моком, кроме приёмника событий аудита.
ЧТО РЕАЛЬНО, А ЧТО НЕТ
Реальное: каждое решение о маршрутизации, оценка сложности, обнаружение страйков, правило серий, оценка лимитов и переход состояния Redis — это реально работающие функции. Синтетическое: трафик. Корпус генерируется, а не собирается из производственных логов. Его смесь архетипов (50 % сложных) — это стрессовая смесь, выбранная для проверки механизма, а не оценка реального трафика; в §6.4 показана чувствительность к этому выбору, и она велика. Приведённые ниже «чистые» показатели точности отражают корпус, классы которого разделимы по построению, и их следует понимать как «механизм срабатывает там, где он был задуман», а не как оценку точности в производстве.
5.1 Корпус
400 сессий, 3 968 ходов, с заданным сидом и детерминированные. Каждый ход — это полное тело запроса chat-completions, содержащее кумулятивную историю, массив из двух определений инструментов и реалистичный системный промпт — форму, которую фактически отправляет агент кодирования. Пять архетипов, каждый с эталонной меткой:
Таблица 3. Состав корпуса. «Требует сильной доработки» — это эталонные данные, используемые для расчёта показателей точности и полноты.
Сложные шаги содержат вставленный дамп горутин или фрагмент исходного кода размером 3–8 КБ в дополнение к тексту, потому что именно так выглядит настоящий сложный шаг отладки. Эта деталь оказалась чрезвычайно важной — см. §6.2.
5.2 Модель затрат
Затраты вычисляются на основе опубликованных прейскурантных цен с семантикой кэширования для каждого провайдера; модель изложена полностью, чтобы с ней можно было не согласиться.
Таблица 4. Параметры модели затрат. Цены указаны в долларах за 1 млн токенов, прайс-лист августа 2026 года.
Тёплое обращение стоит 0.1·p_in·prefix + write·p_in·delta; холодное обращение стоит write·p_in·prompt. Обращение 1 всегда является полной записью в кэш. Обращение переключения уровня в рамках политики эскалации явно тарифицируется как холодное, поэтому механизм сам оплачивает инвалидацию своего кэша.
Качество сообщается как покрытие сложных поворотов — доля сложных по эталону поворотов, обслуженных сильной моделью, — а не как показатель точности. Мы не запускали вышестоящий инференс, поэтому отказываемся выдумывать показатели точности.
6 результатов
6.1 Механизм срабатывает там, где это было задумано
Таблица 5. Результаты эскалации по архетипам, авторежим, canary 100 %, T2 = 0,70 (поставляемое по умолчанию).
Ноль ложных срабатываний на 200 лёгких сессиях, включая 60 длинных, которые скоринг по полному транскрипту мог бы ошибочно отнести к сложной группе. Классы триггеров специализируются чётко и без пересечений: difficulty ловит работу с интенсивными рассуждениями, strikes ловят циклы неудач. Обратите внимание, что пиковый показатель сложности failure_loop равен 0,262 — гейт difficulty вообще не видит эти сессии. Агент, застрявший в цикле ошибок компиляции, не создаёт плотный по сигналам рассуждений текст; он создаёт тот же короткий промпт с другим стектрейсом. Без срабатываний Class C каждая из этих 60 сессий бесконечно долго молотила бы на дешёвой модели.

Рисунок 3. Когда сессии переходят в эскалацию, разделите их по триггеру. Эскалации, вызванные штрафами, резко сконцентрированы (ход 4 — первый ход, на котором два штрафа могут накопиться в пределах окна затухания); эскалации, вызванные сложностью, распределены по ходам 2–11 в соответствии с распределением начала в корпусе. Правило серии из двух подряд идущих ходов означает, что самая ранняя возможная эскалация сложности — ход 2.
6.2 Вывод: отгруженный затвор находится на краю обрыва
Наш первый корпус дал ноль эскалаций, вызванных сложностью. Трудные случаи — нагруженные гонками данных, инвариантами, анализом сложности и лексикой доказательств — достигли пика 0.658 при пороге 0.70. Добавление вставленных трассировок стека, которые реально несут с собой реальные отладочные ходы, подняло их до 0.719. Порог пройден с запасом в 0.019.

Рис. 4. Куда на самом деле расходуется бюджет сложности, в среднем по 855 сложным и 3 113 лёгким ходам. Реалистичный сложный ход достигает 0,719 от теоретического максимума дельты, равного 0,90. Слагаемое CodeKeywordDensity вносит 0,069 из своего бюджета в 0,20 — измеренная плотность составляет 1,72 совпадения на 100 символов при пределе насыщения в 5,0 — а вклад SystemPromptLogLen, равный 0,10, структурно равен нулю в экстракторе дельт. Примерно треть номинального диапазона оценки недостижима для реалистичного текста.
Проход по порогу подтверждает, что это обрыв, а не склон. При T2 от 0,35 до 0,65 результат идентичен — 200 из 400 сессий эскалируются, с нулём пропусков. При установленном значении 0,70 классификатор начинает терять сессии; при 0,75 эскалация, обусловленная сложностью, падает со 122 сессий до 23.

Рисунок 5. Пороговая чувствительность. Весь диапазон 0.35–0.65 поведенчески идентичен, потому что ни один реалистический дельта-текст в него не попадает — распределение оценок бимодально: лёгкие повороты сгруппированы около 0.23, а сложные — около 0.72, и ничего между ними. Поставляемое по умолчанию значение находится на верхнем краю верхней моды.
Инженерное значение
T2 is calibrated for the full-transcript distribution the gated_adaptive bands were tuned on, and it is being reused as the delta extractor's threshold. The design document flags that the delta extractor “needs its own tuning”; this measurement quantifies how much. Either the delta gate needs a lower T2 of its own — anywhere in 0.45–0.60 buys identical behaviour with real margin — or the percentile-based threshold already scheduled for Phase 3 (“top X % of this router's recent traffic”) should land, which makes the escalation rate the operator's knob and sidesteps absolute calibration entirely.
6.3 Стоимость и покрытие

Рисунок 6. Пять политик на одних и тех же 400 сессиях. Слева: стоимость за 1 000 сессий (логарифмическая шкала). Справа: доля действительно сложных обращений, обслуженных сильной моделью.
Таблица 6. Сравнение политик. Стоимость за 1 000 сессий по модели из таблицы 4.
Стоит разделить два результата. Во-первых, сама по себе привязка сессии экономит 24 % при том же выборе модели (16,64 → 12,63) и 35 % на паре frontier-моделей (290,93 → 188,30). Это чистая экономика кэша — те же модели, всё то же самое, отличается только липкость ключа. На паре frontier-моделей экономия больше, потому что надбавка Anthropic в 1,25× за запись делает холодные вызовы непропорционально дорогими.
Second, escalation lands where a rescue mechanism should: 45 % of always-frontier cost for 67 % of its hard-turn coverage, serving the strong model on only 21.4 % of turns.
The missing third of coverage is not a defect; it is the ratchet's price. The corroboration rules that give zero false positives also mean the mechanism cannot act on turn one of a problem:
Table 7. Escalation latency — hard turns served on the cheap model before the ratchet fires.
Two turns is exactly what the two-consecutive-turn streak rule specifies, and one turn is exactly what two-strikes-to-ratchet specifies. The latency is the design, and it is the same property that produced zero false positives. Anyone who wants faster rescue has the Class A header, which acts at n=1 — that is precisely why the manual escape hatch shipped first.
6.4 The headline ratio depends entirely on your traffic
The corpus is 50 % hard by construction. Real router traffic is not, and the cost comparison is extremely sensitive to that. Re-weighting the measured per-archetype costs across a range of hard-session prevalences:

Figure 7. Cost per 1,000 sessions as a function of how much of your traffic genuinely needs the strong model. Within-class behaviour is held at the measured values; only the mix changes.
Table 8. Prevalence sensitivity, $ per 1,000 sessions.
At the design document's own target escalation rate of ≤5 % of sessions, escalation costs 1.6× the cheap-pool bill and 12 % of the frontier bill. At the stress-mix 50 % it costs 6.7× the cheap-pool bill. Both are true; they answer different questions. The operationally relevant one is the first, and it is why the share cap defaults to 20 % rather than to “off” — the cap, not the trigger precision, is what actually bounds the bill.
6.5 The caps hold under adversarial abuse
We re-ran the corpus with the real share-cap machinery — no stub, real Redis day-buckets — under the §8 threat model: every client sends X-OrcaRouter-Tier: strong on every single turn.

Figure 8. Adversarial header abuse against the 20 % escalated-share cap. The first 20 requests are unconstrained by design — the warm-up floor prevents “1 escalation out of 2” reading as 50 % and locking the feature on a fresh router — after which the share converges and holds. Final state: 296 of 1,439 requests served strong (20.6 %), with 1,143 explicit asks denied and audited as denied_cap events.
The residual 0.6 % overshoot is the intended behaviour of a strictly-greater comparison on an approximate trailing counter, and the per-session cap of 1 keeps individual sessions from consuming the budget. Every denial is visible to the client in the X-Orca-Session-Tier: base; reason=denied:share_cap response header and to the operator in the audit table — a suppressed escalation is never silent.
7 What we would change
Give the delta extractor its own threshold. Reusing the full-transcript T2 leaves a 0.019 margin (§6.2). A delta-specific T2 in 0.45–0.60 is behaviourally identical on this corpus with two orders of magnitude more headroom. The percentile-threshold work already scheduled subsumes this and is the better fix.
Do not let the code-density term stay decorative. It contributes 0.069 of its 0.20 budget on the densest realistic text we could construct, because its saturation cap of 5 matches per 100 characters implies roughly one code keyword every twenty characters. Either re-cap it against a measured production distribution or reallocate its weight.
Class C is the workhorse for agent traffic, and it is the least developed. The failure_loop population is invisible to the difficulty gate (peak 0.262) and is caught entirely by strikes. Agent sessions fail by looping, not by getting lexically harder. The remaining response-side producers — and the native-Gemini streaming capture hook that is still missing — are worth more than further difficulty tuning.
Publish the escalation latency. Two turns of hard work served on the cheap model is the honest cost of a corroborating ratchet, and operators should see it in the analytics panel next to precision, not discover it.
8 Limitations
The corpus is synthetic. It was constructed to separate cleanly, so the zero-false-positive result characterises the mechanism's specificity on separable input, not its precision on production traffic. The real precision number can only come from the shadow-mode labelling job the design specifies — full trigger pipeline running, routing nothing, decisions labelled retroactively — with a go-live gate at ≥70 % labelled precision.
The cost model assumes a fixed 500 output tokens per turn, which suppresses a real effect: frontier models emit more reasoning tokens, so the true frontier premium is understated. It also models request-level cache warmth as a uniform 1/N over key slots; a weighted pool would use the Herfindahl index Σw², and a single-key channel would show no cache advantage for session affinity at all at the channel layer — though the model-layer pin still matters for adaptive strategies.
We did not run upstream inference, so no accuracy or task-success claim is made. Hard-turn coverage is a proxy for quality, and it assumes the strong model is actually better on those turns — plausible for the archetypes constructed, unverified here.
Finally, this measures one gateway's implementation. The turn-1 lock-in failure mode should generalise to any cache-aware router that pins sessions, but the specific numbers are properties of these thresholds, these weights and these prices.
9 Related work
Request-level routing is well covered. FrugalGPTsup>[2]/sup> introduced the LLM cascade — query the cheap model, score the answer, escalate on low confidence — reporting up to 98 % cost reduction at matched accuracy. RouteLLMsup>[1]/sup> trains routers on Chatbot Arena preference data and reports 95 % of GPT-4 quality with 14 % strong-model calls, with routers that transfer across model pairs without retraining. RouterArenasup>[3]/sup> supplies the missing evaluation foundation: 8,400 queries across domains and difficulty levels, scored on accuracy, cost, routing optimality, robustness and router overhead.
What none of these address is the conversation as the routing unit. A cascade escalates a request and forgets; the next turn re-runs the same cheap model on the same now-known-hard task. A preference-trained router scores a query, not a trajectory. The gap this report addresses is what a router should remember between turns, how long, and what should be allowed to change its mind — a question that only becomes urgent once prompt caching makes forgetting expensive.
OrcaRouter ships an in-tree RouterArena harness (eval/) that benchmarks its five request-level strategies — cheapest, quality, balanced, linucb, gated_adaptive — against the open dataset without modifying the upstream repository. The session-level mechanism described here is orthogonal to and composes with all five.
10 Conclusion
Prompt caching changed the economics of LLM routing in a way the routing literature has not caught up with. Once continuity is worth a 10× discount on the majority of your input tokens, a router must pin — and the moment it pins, it makes its decision on the turn where it knows least, and lives with that decision for the length of the conversation. Request-level routing does not have this problem and pays for it in cache misses; naive per-turn re-evaluation reintroduces the misses and adds a length-bias artefact on top.
Tiered stickiness resolves it by separating two things that look like one: which model serves this session (the pin, stable within a tier) and which tier this session belongs to (a small, capped, corroborated, expiring piece of state). In our replay that separation recovers 87 % of sessions whose difficulty is undetectable at turn 1, with zero false positives on 200 easy sessions, at 45 % of always-frontier cost — and holds a 20 % spend cap against clients actively trying to defeat it.
The mechanism's honest weaknesses are calibration, not architecture: a difficulty gate reused from a distribution it was not tuned for, a feature term that cannot reach its budget, and two turns of unavoidable rescue latency. Those are tractable. The architectural claim — that the escalation memory must be separate from the pin, that no fuzzy signal may ratchet alone, and that caps must bind the client's own explicit request because the client holds the token — is the part we would keep.
11 Sources
1. LMSYS Org. RouteLLM: An Open-Source Framework for Cost-Effective LLM Routing. a href="https://www.lmsys.org/blog/2024-07-01-routellm/">u>lmsys.org/blog/2024-07-01-routellm//u>/a> · code: a href="https://github.com/lm-sys/RouteLLM">u>github.com/lm-sys/RouteLLM/u>/a>
2. Chen, Zaharia & Zou. FrugalGPT: How to Use Large Language Models While Reducing Cost and Improving Performance. arXiv:2305.05176. a href="https://arxiv.org/abs/2305.05176">u>arxiv.org/abs/2305.05176/u>/a>
3. Lu, Liu, Yuan, Cui, Zhang, Liu & Xing. RouterArena: An Open Platform for Comprehensive Comparison of LLM Routers. arXiv:2510.00202. a href="https://arxiv.org/abs/2510.00202">u>arxiv.org/abs/2510.00202/u>/a>
4. OpenAI. Prompt Caching in the API. a href="https://openai.com/index/api-prompt-caching/">u>openai.com/index/api-prompt-caching//u>/a> — automatic caching, ≥1,024-token prefix in 128-token increments, 5–10 minute idle eviction, ≤1 hour; cached-input discount by model tier. Pricing: a href="https://openai.com/api/pricing/">u>openai.com/api/pricing//u>/a>
5. Anthropic. Prompt caching. a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching">u>platform.claude.com/docs/en/build-with-claude/prompt-caching/u>/a> — cache reads 0.1× base input, writes 1.25× (5-minute TTL) or 2× (1-hour TTL), refreshed on use. Pricing: a href="https://www.anthropic.com/pricing">u>anthropic.com/pricing/u>/a>
6. DeepSeek. DeepSeek API introduces Context Caching on Disk. a href="https://api-docs.deepseek.com/news/news0802/">u>api-docs.deepseek.com/news/news0802//u>/a> — automatic, billed on actual cache hits, order-of-magnitude reduction on hit.
7. Google. Gemini API context caching. a href="https://ai.google.dev/gemini-api/docs/caching">u>ai.google.dev/gemini-api/docs/caching/u>/a> — implicit and explicit caching with storage-priced TTL.
8. OrcaRouter source, this repository: service/session_affinity.go (pins, TTLs, tier-scoped keys) · service/session_escalation.go (the engine) · service/model_router.go:1374 (selectByStrategy: tier narrowing before the pin read) · service/model_router_difficulty.go (weights and caps) · service/model_router_delta.go (delta extractor) · service/escalation_strikes.go (request-side producers) · service/escalation_caps.go (share caps) · docs/features/frontier-escalation.md (design, review rounds 1–4).
Reproducibility. The measurement harness is a Go test in the service package driving ResolveEscalation / CommitEscalationDecision against miniredis, plus a Python analysis and figure pipeline. Corpus generation is seeded (rand.NewSource(20260814)) and the full run is deterministic: 400 sessions, 3,968 turns, three experiments (main replay, adversarial cap run, 9-point threshold sweep). Figures use a CVD-validated categorical palette; every figure is paired with its underlying table. No production data was accessed, and no part of this analysis was committed to the repository.
Сравнение в этой статье1
Определено по этой статье · Бенчмарки: Artificial Analysis · обновляется ежедневно
