dsl именованного маршрутизатора —
поэтому ваше приложение продолжает вызывать orcarouter/{name}, а логика
маршрутизации живёт в дашборде, версионируется и редактируется без передеплоя.
Когда выбирать DSL
Используйте встроенную стратегию, когда «самая дешёвая живая модель» или «наилучшее качество» отражают ваше намерение. Обращайтесь к DSL, когда маршрутизация зависит от содержания или контекста запроса:- Специализация под задачу — отправляйте код в модель для кода, изображения в модель для изображений, дешёвый чат в дешёвую модель.
- Маршрутизация с учётом сложности — эскалируйте к дорогой модели только сложные запросы; держите простые дешёвыми.
- Маршрутизация с учётом агента — маршрутизируйте по-разному в зависимости от состояния сессии (какие инструменты использовал агент, провалились ли только что тесты, на каком ходе он находится).
- Правила по времени / тенанту / заголовку — разная маршрутизация по часу, группе пользователей или заголовку запроса.
Включение
В дашборде в разделе Routing откройте маршрутизатор и установите его Strategy в DSL. Это откроет редактор DSL для данного маршрутизатора. Всё остальное в маршрутизаторе по-прежнему действует — glob Allowed models, страховочная Default model и вызовorcarouter/{name}.
Редактор
Редактор устроен так, чтобы провести вас от намерения к рабочему набору правил быстро:- Templates заполнены реальными моделями вашего рабочего пространства (через одноразовый диалог сопоставления уровней), так что вы никогда не начинаете с пустого файла и не упираетесь в стену «неизвестной модели».
- Insert — вставьте Model, Router (
orcarouter/<name>) или Pool из автодополнения вместо ручного ввода идентификаторов. - Generate — опишите нужную маршрутизацию обычным языком и получите скомпилированный, прошедший линтинг DSL, опирающийся на ваши реальные модели.
- Explain — пересказ на обычном языке того, что делает текущий набор правил.
- Inline lint — каждая ошибка сообщает
{line, column, message}, и у каждого кода линта есть пояснение по?. Приоритет (побеждает первое совпадение) и распространённые паттерны CEL подсказываются прямо на месте.
Структура файла
Набор правил — это YAML с тремя ключами верхнего уровня:when: и эффект use::
when:
истинно. Если ни одно не совпало, применяется default:. Располагайте
правила от наиболее специфичных к общим — широкое раннее правило затеняет
всё, что ниже.
when: — условие
Условия пишутся на CEL
(Common Expression Language): безопасном по своей сути — без циклов, без
ввода-вывода, вычисление за микросекунды, только регулярные выражения RE2.
Эти шесть паттернов покрывают подавляющее большинство реальных правил:
| Паттерн | Пример |
|---|---|
| Доступ к полю | task_class == "agent" |
| Числовое сравнение | difficulty > 0.6 && request.input_tokens < 50000 |
| Булева логика | agent_state.has_edited && !agent_state.has_run_tests |
| Проверка вхождения в список | "Edit" in agent_state.tools_used |
| Макрос регулярного выражения | system_prompt_matches("(?i)planning agent") |
| Макрос инструментов | tool_calls_present_any(["Edit","Write","apply_patch"]) |
Переменные
Форма запроса| Переменная | Тип |
|---|---|
model | string |
request.input_tokens | int |
request.output_max_tokens | int |
request.stream | bool |
request.vision | bool |
request.message_count | int |
request.has_system_prompt | bool |
request.has_tools | bool |
| Переменная | Тип | Значение |
|---|---|---|
task_class | string | chat / code / agent / vision / audio / rag / creative |
difficulty | double | 0.0–1.0 |
code_keyword_density | double | 0.0–1.0 |
reasoning_cue_count | int | признаки рассуждения, обнаруженные в промпте |
tool_count | int | различные определения инструментов в запросе |
agent_state.*, сохраняется на протяжении разговора)
| Переменная | Тип |
|---|---|
agent_state.turn | int |
agent_state.tools_used | list<string> |
agent_state.files_read | list<string> |
agent_state.has_edited | bool |
agent_state.has_run_tests | bool |
agent_state.last_test_failed | bool |
agent_state.consecutive_errors | int |
agent_state.elapsed_seconds | int |
agent_state.models_tried | list<string> |
| Переменная | Тип |
|---|---|
headers["x-foo"] | string |
user.id / user.group | int / string |
token.id / token.name | int / string |
time.hour / time.weekday | int (UTC) |
workspace.id | int |
Макросы
Зарегистрированные функции CEL для распространённых проверок «загляни внутрь запроса»:| Макрос | Возвращает |
|---|---|
system_prompt_matches(regex) | RE2 по объединённым системным сообщениям |
user_message_matches(regex) | RE2 по последнему сообщению пользователя |
tool_definitions_include(name) | инструмент объявлен в запросе |
tool_calls_present_any(list) | запрос несёт любой из этих вызовов инструментов |
tool_results_from_any(list) | в запросе есть сообщения с ролью инструмента от любого из них |
header_matches(name, regex) | RE2 по значению заголовка |
use: — эффект
Блок use: называет назначение (ровно одно) и любое число
необязательных настроек для конкретного вызова.
Назначение
delegate: dsl отклоняется (это привело бы к рекурсии). Привязка к конкретным
каналам (channels: / @channel:) сейчас недоступна и при линтинге помечается
как неподдерживаемая — маршрутизируйте через model, models или pool.Настройки для конкретного вызова
Комбинируйте с любым назначением, чтобы сформировать апстрим-вызов:param_override и header_override соблюдают чёрный список — вы не можете
переопределить model, messages, stream, tools, заголовки авторизации
и т. п. (это подорвало бы биллинг, аудит или состояние агента).
Каскады уверенности и ансамбли (продвинутое)
Два продвинутых эффекта позволяют правилу реагировать на слабый первый ответ или развернуться веером по нескольким моделям. Они создаются так же, как любое правило. Cascade — повтор по сигналу низкой уверенности с более сильным эффектом:Среда выполнения ансамблей / каскадов закрыта флагом и по умолчанию
выключена. Поскольку каждая параллельная ветвь и каждый каскадный повтор
тарифицируются как отдельный вызов, среда выполнения веерного развёртывания
находится за серверным флагом, пока проверяется потарифный учёт по ветвям.
Когда она выключена, правило
parallel: обслуживает только первую ветвь,
а каскад записывает свой сигнал, но не перенаправляет повторно — набор правил
всё равно проходит линтинг, сохраняется и маршрутизирует свой основной эффект
как обычно. Свяжитесь с нами, чтобы включить среду выполнения ансамблей для
вашего рабочего пространства.Безопасный выкат
Новый набор правил не берёт на себя ваш трафик в момент сохранения:- Теневой режим — в течение окна после первого сохранения DSL
вычисляется, но не используется: ваша прежняя стратегия по-прежнему
обслуживает трафик, а шлюз записывает, что сделал бы DSL. Дашборд
показывает отчёт о расхождениях — процент отличающихся маршрутов,
прогнозируемую разницу в стоимости, число срабатываний по каждому правилу
и как часто доходило до
default:. Прочитайте его, прежде чем доверять правилам. - Канареечный запуск — наращивайте долю живого трафика, идущего через DSL (5 → 25 → 50 → 100), отслеживая метрики по каждому срезу, и мгновенно откатывайтесь, сдвинув процент к 0.
Ограничения и валидация
Каждое сохранение запускает строгий линтинг; некорректные наборы правил отклоняются с{line, column, message, rule}:
- Схема — обязательные ключи, корректные типы/enum, без неизвестных полей.
- Размер — ≤ 30 правил, ≤ 16 КиБ YAML, ≤ 200 символов на
when:. - CEL — парсится, проходит проверку типов относительно окружения
переменных, без неизвестных идентификаторов, и
when:должно вычисляться в bool. - Эффект — ровно одно назначение на блок
use:; все ссылкиmodel/models/@pool:должны разрешаться в вашем рабочем пространстве. - Диапазоны настроек —
thinking_budget_tokens ∈ [1024, 64000],temperature ∈ [0, 2],samples ∈ [1, 16]. - Зарезервировано — id правил, начинающиеся с
_, зарезервированы;defaultв качестве id правила отклоняется (используйте блокdefault:верхнего уровня).
Полный пример
X-Orca-Router и X-Orca-Resolved-Model.
Справочник API
DSL управляется на уровне маршрутизатора; запись требует роли Developer+.| Метод и путь | Роль | Назначение |
|---|---|---|
GET /api/user/routers/:id/dsl | Member | Исходник + версия + состояние теневого/канареечного режима. |
PUT /api/user/routers/:id/dsl | Developer+ | Линтинг + сохранение (новая версия, с аудитом). |
POST /api/user/routers/:id/dsl/lint | Member | Линтинг черновика → {errors:[…]}. |
POST /api/user/routers/dsl/lint | Member | Линтинг без сохранения состояния (без id маршрутизатора). |
POST /api/user/routers/:id/dsl/dryrun | Member | Вычислить синтетический запрос → трассировка + совпавшее правило. |
GET /api/user/routers/:id/dsl/history | Member | История версий, новейшие сверху. |
POST /api/user/routers/:id/dsl/rollback/:version | Developer+ | Повторный линтинг и восстановление старой версии. |
FAQ
Чем это отличается от стратегии именованного маршрутизатора?
Чем это отличается от стратегии именованного маршрутизатора?
Это и есть стратегия — вариант
dsl наряду с cheapest / quality /
balanced / adaptive. Остальные выбирают по цене и качеству; DSL выбирает
по правилам, которые вы пишете над формой запроса, классификацией и
состоянием агента. Вы всё ещё можете использовать delegate: к встроенной
стратегии как эффект правила или как default.Что произойдёт, если ни одно правило не совпадёт?
Что произойдёт, если ни одно правило не совпадёт?
Применяется эффект
default: верхнего уровня. Он обязателен, поэтому всегда
есть определённый исход — обычно delegate: balanced или конкретная
страховочная модель.Безопасно ли исполнять недоверенный CEL на горячем пути?
Безопасно ли исполнять недоверенный CEL на горячем пути?
Да. CEL исполняется в песочнице только с функциями стандартной библиотеки,
с дедлайном вычисления в несколько миллисекунд, регулярными выражениями RE2
(линейное время, без ReDoS) и без доступа к базе данных, сети или файловой
системе. Окружение переменных — фиксированный набор скаляров и списков.
Могу ли я протестировать набор правил до того, как он коснётся реального трафика?
Могу ли я протестировать набор правил до того, как он коснётся реального трафика?
Тремя способами: выполните пробный прогон (dry-run) против синтетического
запроса в редакторе, оставьте его в теневом режиме и прочитайте отчёт о
расхождениях, затем проведите канареечный запуск на небольшом проценте
живого трафика, прежде чем нарастить до 100%.
