Routing DSL: составьте панель моделей, которая мыслит как Fable 5

Routing DSL: составьте панель моделей, которая мыслит как Fable 5

Дата публикации

Назад ко всем статьям

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

Routing DSL — это то, как вы строите эту панель. Это программируемая стратегия маршрутизации — YAML + CEL — которая превращает вашу конечную точку OrcaRouter в граф вывода: маршрутизация по сложности, маршрутизация по задаче, разветвление на несколько моделей одновременно, оценка или голосование по их результатам, откат при низкой уверенности и настройка всего этого под стоимость, задержку или качество. Вы пишете правила; шлюз компилирует и выполняет их на каждом запросе за ~5 мс.

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


Сначала результат

Два иллюстративных эталона. (Числа иллюстративны — они призваны показать форму эффекта, а не цитироваться как официальные оценки.)

Сравнение фронтиров — сложно-маршрутизированная DSL-конечная точка против одиночного фронтира:


Панели Fusion против одиночных моделей — оценено на 93 из 100 задач (от OpenRouter):


Три вещи, на которые стоит смотреть:

Каждая объединённая панель превосходит каждого из своих собственных участников. Opus 4.8 + GPT-5.5 (~67.5%) превосходит как Opus solo (~58.5%), так и GPT-5.5 solo (~60%) на 7–9 пунктов. Разногласие — это сигнал; арбитраж его использует.

Fusion достигает следующего уровня. Три разные панели пересекают Fable 5 solo (~65.5%) используя только модели ниже его.

Вам не нужны дорогие подписки.Opus + Opus-самослияние (~65,5%) соответствует Fable 5 с одной моделью и сэмплером. Набор дешёвых моделей — Gemini 3 Flash + Kimi K2.6 + DeepSeek V4 Pro (~64,5%) — немного уступает Fable 5 при значительно меньшей стоимости за токен. В этом и заключается суть: покупать интеллект с помощью топологии, а не за счёт следующего ценового уровня.

Маршрутизирующий DSL — это поверхность управления, которая позволяет тратить эту топологию только там, где это оправдано: дешёвые модели на лёгкие 80%, фьюжн-панель на сложный хвост.


Грамматика за 30 секунд

Набор правил — это версия, список правил и обязательное значение по умолчанию. Правила вычисляются сверху вниз; первый when: который истинен, выигрывает. Нет when: означает "всегда совпадает."

версия: 1

rules:
  - id: only_rule
    use: { model: "claude-sonnet-4-6" }
default:
  delegate: balanced


Параметр when: — это CEL булево выражение — изолированное, допускающее только регулярные выражения RE2, без циклов, без ввода-вывода, вычисляемое за микросекунды, с единым сроком выполнения в 5 мс, общим для всего набора правил. Параметр use: — это эффект: он определяет, куда направляется запрос и как он настраивается. Ограничения намеренно малы (≤30 правил, ≤16 КиБ исходного кода, ≤200 символов на параметр when:), чтобы набор правил оставался проверяемым.


Примитив 1 — маршрут по сложности и заданию

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

версия: 1

rules:
  - id: hard_reasoning
    when: difficulty > 0.8
    use:
      model: "claude-opus-4-8"
      reasoning_effort: "high"
      thinking_budget_tokens: 32000


  - id: code_path
    when: task_class == "code" && code_keyword_density > 0.5
    use: { model: "gpt-5.5" }


  - id: cheap_chat
    when: difficulty < 0.3
    use: { model: "gemini-3-flash" }


default:
  delegate: balanced


Переменные, которые вы можете прочитать в when: (сокращённо — см. полную документацию):

Примеры групп

Форма запроса

request.input_tokens, request.output_max_tokens, request.stream, request.vision, request.message_count, request.has_tools


Классификация

task_class (chat/code/agent/vision/audio/rag/creative), difficulty (0.0–1.0), code_keyword_density, reasoning_cue_count, log_prompt_tokens, tool_count


Сессия 

agent_state.turn, agent_state.tools_used, agent_state.has_edited, agent_state.last_test_failed, agent_state.consecutive_errors, agent_state.models_tried


Контекст

headers["x-…"], user.group, token.name, time.hour, workspace.id
…plus six macros for the things regex-over-payload is good at: system_prompt_matches(re), user_message_matches(re), tool_definitions_include(name), tool_calls_present_any([…]), tool_results_from_any([…]), header_matches(name, re).


Любая конечная точка может иметь параметры для каждого вызова, которые переводятся в нативные параметры каждого провайдера адаптером-ретранслятором: reasoning_effort (низкий/средний/высокий), thinking_budget_tokens (1024–64000), samples (1–16), temperature (0.0–2.0), а также защищенные дени-листом param_override / header_override. Этого уже достаточно, чтобы построить конечную точку с маршрутизацией по сложности из Таблицы A: дешевая модель для легких задач, Opus с бюджетом на размышления для сложных.


Примитив 2 — развёртка на панель (слияние)

Это источник прироста производительности бенчмарка. Параллельный эффект отправляет запрос к 2–5 ветвей одновременно, затем арбитр решает, что в итоге видит клиент:

- id: hard_tail_panel
  when: difficulty > 0.7 && task_class == "agent"
  use:
    parallel:
      - { model: "anthropic/claude-opus-4-8", reasoning_effort: "high" }
      - { model: "openai/gpt-5.5", thinking_budget_tokens: 16000 }
      - { model: "google/gemini-3.1-pro", temperature: 0.3 }
    arbiter:
      strategy: best_of_n
      model: "anthropic/claude-sonnet-4-6"      # the judge
      template: judge_code
    max_latency_ms: 120000
    on_disagreement:                  # majority-only escape hatch
      model: "anthropic/claude-opus-4-8"
      reasoning_effort: "high"


Четыре стратегии арбитра, каждая из которых дает разный ответ на вопрос "чей вывод побеждает?":

первый — разгоняйте ноги, обслуживайте первый успех, отменяйте проигравших. Оптимизирует задержку (вы получаете самый быстрый из N).

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

best_of_n — это LLM судья читает все кандидаты и ранжирует их. Это конфигурация «Opus + GPT-5.5 → judge» из таблицы B. Оптимизирует качество в открытых задачах; при ошибке судьи использует запасной вариант first-successful.

тесты_пройдены — основанный_на_выполнении: предоставлять кандидата, чей патч действительно заставляет набор тестов проходить. Без догадок судьи — решение принимает тестовая среда. Это самый сильный арбитр для работы с кодом/агентом. Верификатор находится за пределами шлюза (подключен через VerifierProvider); если ни один не подключен, он понижается до первого успешного.

max_latency_ms (1000–600000, по умолчанию 120000) ограничивает разветвление, чтобы один медленный участок не мог задержать ответ — отстающие отбрасываются. Вложение parallel внутрь parallel отклоняется на этапе lint; панель намеренно имеет один уровень глубины.

Примечание о доступности: N-way fan-out рантайм ограничен серверным флагом ROUTING_DSL_ENSEMBLE_RUNTIME в то время как per-leg billing закалено на staging — поэтому fusion находится в статусе preview, not GA. При выключенном флаге правило parallel: чисто обслуживает свой первый leg, так что вы можете создавать и shadow свои панели уже сегодня и включать их, когда fusion появится в вашем регионе.


Примитив 3 — запасные варианты и каскады уверенности

Разветвление тратит N× заранее. Один каскад тратит дополнительно только когда первый ответ кажется неверным. После ответа, on_low_confidence: оценивает сигналы и, если один срабатывает, повторно отправляет к более сильному назначению:

- id: agent_with_safety_net
  when: task_class == "agent"
  use:
    pool: "@pool:fast"
  on_low_confidence:
    signals: [patch_invalid, self_doubt, next_turn_test_failed]
    threshold: { low_logprob: -1.5 }
    use:
      model: "claude-opus-4-8"
      reasoning_effort: "high"


Сигналы: patch_invalid (diff не проходит проверку git apply --check), self_doubt (набор регулярных выражений для уклончивых фраз), low_logprob (средний логпроб токена ниже порога, если провайдер его раскрывает), и next_turn_test_failed (перекрестная защелка — промпт этого витка содержит форму тестов, провалившихся на прошлом витке). Каскады по замыслу имеют глубину 1. Сочетайте их с agent_state.models_tried, чтобы получить разнообразие при повторной попытке — никогда не отправляйте исправление модели, которая только что ошиблась.


Настройка параметров: стоимость, задержка, качество

Один и тот же DSL выражает все три цели; вы выбираете по правилу:

Стоимость — делегировать: самый дешевый, оставляйте дешевую модель на легком хвосте, а разветвление (fan-out) резервируйте для сложности > 0.7. Дешевая панель Table B (~64.5% ≈ Fable 5 solo) является доказательством существования: объединение маленьких моделей может заменить передовую модель за долю стоимости за токен. Будьте трезвы, однако — объединение использует "выставлять счет за каждую ногу" модель: трехногая панель best_of_n выставляет счета трем кандидатам плюс судье. Экономика работает, потому что вы (a) разветвляетесь только на сложном меньшинстве запросов и (b) объединяете более дешёвых членов, чем передовая модель, которую вы заменяете.

Задержка — арбитр: { strategy: first } с жестким ограничением max_latency_ms дает вам самый быстрый из N с жестким потолком.

Качество — best_of_n для задач открытого типа, tests_pass когда есть набор тестов для опоры. samples и thinking_budget_tokens дают больше в рамках одного шага.


Эксплуатация без нарушения работы продакшена

Изменения маршрутизации пугают, поэтому DSL поставляется с предохранительными рельсами, которые ожидает SRE:

Линтинг при каждом сохранении — схема, проверка типов CEL (каждое when: должно вычисляться в bool), разрешение ссылок, диапазоны ручек, списки запрета заголовков/параметров. Ошибки возвращаются как {line, column, message, rule} и отображаются в виде значков на полях в редакторе.

Пробный прогон — отправляет синтетический запрос (task_class, difficulty, agent_state, …) и возвращает соответствующее правило, определенный эффект и время оценки до того, как что-либо будет отправлено.

Теневой режим — в течение 24 ч после первого сохранения DSL оценивается, но не используется; теневой журнал записывает предполагаемые выборки, а консоль показывает разницу (процент измененных маршрутов, прогнозируемое изменение дневной стоимости, счетчики срабатываний по каждому правилу).

Canary — ползунок трафика от 0 до 100. Увеличивайте с 5 → 25 → 50 → 100, наблюдая за метриками каждого среза; откатите, переместив ползунок на 0.

Аудит + откат — каждое сохранение/откат записывает строку аудита в той же транзакции; конкурентные правки получают 409 с текущей версией, так что вы повторяете попытку на основе свежего состояния.

Тестовые примеры, повтор трассировки и представление AI "объяснить этот набор правил" дополняют его. Вы найдете это в панели управления в разделе маршрутизация → стратегия → DSL.


Полный набор правил

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

версия: 1

rules:
  - id: trivial
    when: difficulty < 0.3 && !has_tools
    use: { model: "gemini-3-flash" }


  - id: standard
    when: difficulty < 0.7
    use:
      model: "gpt-5.5"
    on_low_confidence:
      signals: [self_doubt, low_logprob]
      use: { model: "claude-opus-4-8", reasoning_effort: "high" }


  - id: hard_agent_panel
    when: difficulty >= 0.7 && task_class == "agent"
    use:
      parallel:
        - { model: "anthropic/claude-opus-4-8", reasoning_effort: "high" }
        - { model: "openai/gpt-5.5", thinking_budget_tokens: 16000 }
        - { model: "google/gemini-3.1-pro" }
      arbiter:
        strategy: tests_pass        # execution-grounded; judged fallback if no harness
      max_latency_ms: 180000
      on_disagreement:
        model: "claude-opus-4-8"
        reasoning_effort: "high"


default:
  delegate: balanced


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


Начать написание

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

Документация: https://docs.orcarouter.ai/routing/routing-dsl

ПИ: маршрутизация → Создать роутер -> Стратегия маршрутизации → DSL (эксперт)

Фронтир — это панель. Собери свою.