dsl de um roteador nomeado — então
sua aplicação continua chamando orcarouter/{name} e a lógica de roteamento
fica no painel, versionada e editável sem uma reimplantação.
Quando recorrer à DSL
Use uma estratégia integrada quando “modelo ativo mais barato” ou “melhor qualidade” captura sua intenção. Recorra à DSL quando o roteamento depende do conteúdo ou contexto da requisição:- Especialização de tarefa — envie código para um modelo de codificação, visão para um modelo de visão, chat barato para um modelo barato.
- Roteamento ciente de dificuldade — escale apenas as requisições difíceis para um modelo caro; mantenha as fáceis baratas.
- Roteamento ciente do agente — roteie de forma diferente com base no estado da sessão (quais ferramentas o agente usou, se os testes acabaram de falhar, em quantos turnos ele está).
- Regras de tempo / inquilino / cabeçalho — roteamento diferente por hora, grupo de usuários ou um cabeçalho de requisição.
Habilitando
No painel em Routing, abra um roteador e defina sua Estratégia como DSL. Isso revela o editor da DSL para este roteador. Todo o resto sobre o roteador ainda se aplica — o glob de Modelos permitidos, a rede de segurança do Modelo padrão e a invocaçãoorcarouter/{name}.
O editor
O editor foi construído para levá-lo da intenção a um conjunto de regras funcional rapidamente:- Templates semeados com os modelos reais do seu workspace (via um diálogo único de mapeamento de níveis), para que você nunca comece de um arquivo em branco ou esbarre em um muro de “modelo desconhecido”.
- Insert — insira um Model, um Router (
orcarouter/<name>), ou um Pool do autocomplete em vez de digitar identificadores à mão. - Generate — descreva o roteamento que você quer em linguagem natural e receba de volta DSL compilada e sem erros de lint, fundamentada em seus modelos reais.
- Explain — uma paráfrase em linguagem simples do que o conjunto de regras atual faz.
- Lint inline — todo erro reporta
{line, column, message}e todo código de lint tem um explicador?. A precedência (a primeira correspondência vence) e os padrões CEL comuns são exibidos no local.
Estrutura do arquivo
Um conjunto de regras é YAML com três chaves de nível superior:when: e um efeito use::
when: é verdadeira
vence. Se nenhuma corresponder, default: se aplica. Ordene suas regras das mais específicas
primeiro — uma regra ampla logo no início ofusca tudo abaixo dela.
when: — a condição
As condições são escritas em CEL
(Common Expression Language): segura por design — sem loops, sem I/O,
avaliação em microssegundos, apenas regex RE2. Estes seis padrões cobrem a vasta
maioria das regras reais:
| Padrão | Exemplo |
|---|---|
| Acesso a campo | task_class == "agent" |
| Comparação numérica | difficulty > 0.6 && request.input_tokens < 50000 |
| Lógica booleana | agent_state.has_edited && !agent_state.has_run_tests |
| Pertencimento a lista | "Edit" in agent_state.tools_used |
| Macro de regex | system_prompt_matches("(?i)planning agent") |
| Macro de ferramenta | tool_calls_present_any(["Edit","Write","apply_patch"]) |
Variáveis
Formato da requisição| Variável | Tipo |
|---|---|
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 |
| Variável | Tipo | Significado |
|---|---|---|
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 | indícios de raciocínio detectados no prompt |
tool_count | int | definições distintas de ferramentas na requisição |
agent_state.*, persistida ao longo de uma conversa)
| Variável | Tipo |
|---|---|
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> |
| Variável | Tipo |
|---|---|
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 |
Macros
Funções CEL registradas para as verificações comuns de “olhar dentro da requisição”:| Macro | Retorna |
|---|---|
system_prompt_matches(regex) | RE2 sobre as mensagens de sistema unidas |
user_message_matches(regex) | RE2 sobre a última mensagem do usuário |
tool_definitions_include(name) | uma ferramenta está declarada na requisição |
tool_calls_present_any(list) | a requisição carrega qualquer uma dessas chamadas de ferramenta |
tool_results_from_any(list) | a requisição tem mensagens de papel tool de qualquer um |
header_matches(name, regex) | RE2 sobre o valor de um cabeçalho |
use: — o efeito
Um bloco use: nomeia um destino (exatamente um) e qualquer número de
knobs opcionais por chamada.
Destino
delegate: dsl é rejeitado (causaria recursão). Fixar em canais específicos
(channels: / @channel:) não está disponível atualmente e gera lint
como não suportado — roteie por model, models ou pool em vez disso.Knobs por chamada
Combine com qualquer destino para moldar a chamada upstream:param_override e header_override impõem uma lista de bloqueio — você não pode
sobrescrever model, messages, stream, tools, cabeçalhos de autenticação, etc.
(isso subverteria a cobrança, a auditoria ou o estado do agente).
Cascatas de confiança e ensembles (avançado)
Dois efeitos avançados permitem que uma regra reaja a uma primeira resposta fraca ou se ramifique por vários modelos. Eles são escritos da mesma forma que qualquer regra. Cascade — tente novamente diante de um sinal de baixa confiança com um efeito mais forte:O runtime de ensemble / cascade é restrito e desligado por padrão. Como
cada perna paralela e cada reparo de cascata é cobrado como sua própria chamada, o
runtime de ramificação fica atrás de uma flag de servidor enquanto a cobrança por perna é
validada. Com ele desligado, uma regra
parallel: serve apenas a primeira perna e
uma cascata registra seu sinal mas não redespacha — o conjunto de regras ainda
passa pelo lint, salva e roteia seu efeito primário normalmente. Entre em contato conosco para
habilitar o runtime de ensemble para seu workspace.Implantando com segurança
Um novo conjunto de regras não assume seu tráfego no momento em que você o salva:- Modo shadow — por uma janela após o primeiro salvamento, a DSL é
avaliada mas não usada: sua estratégia anterior ainda serve o tráfego
enquanto o gateway registra o que a DSL teria feito. O painel
mostra um relatório de diff — porcentagem de rotas divergentes, delta de custo
projetado, contagens de disparo por regra e com que frequência caiu para
default:. Leia-o antes de confiar nas regras. - Canary — aumente gradualmente a DSL para uma porcentagem do tráfego ao vivo (5 → 25 → 50 → 100), observando métricas por fatia, e reverta instantaneamente deslizando a porcentagem para 0.
Limites e validação
Todo salvamento executa um lint estrito; conjuntos de regras inválidos são rejeitados com{line, column, message, rule}:
- Schema — chaves obrigatórias, tipos/enums corretos, sem campos desconhecidos.
- Tamanho — ≤ 30 regras, ≤ 16 KiB de YAML, ≤ 200 caracteres por
when:. - CEL — faz parse, verifica tipos contra o ambiente de variáveis, sem
identificadores desconhecidos, e
when:deve avaliar para um bool. - Efeito — exatamente um destino por bloco
use:; todas as referênciasmodel/models/@pool:devem resolver em seu workspace. - Faixas de knobs —
thinking_budget_tokens ∈ [1024, 64000],temperature ∈ [0, 2],samples ∈ [1, 16]. - Reservado — ids de regra começando com
_são reservados;defaultcomo id de regra é rejeitado (use o blocodefault:de nível superior).
Um exemplo completo
X-Orca-Router
e X-Orca-Resolved-Model.
Referência da API
A DSL é gerenciada por roteador; escritas exigem Developer+.| Método e caminho | Papel | Propósito |
|---|---|---|
GET /api/user/routers/:id/dsl | Member | Fonte + versão + estado de shadow/canary. |
PUT /api/user/routers/:id/dsl | Developer+ | Lint + salvar (nova versão, auditada). |
POST /api/user/routers/:id/dsl/lint | Member | Lint de um rascunho → {errors:[…]}. |
POST /api/user/routers/dsl/lint | Member | Lint sem estado (sem id de roteador). |
POST /api/user/routers/:id/dsl/dryrun | Member | Avaliar uma requisição sintética → trace + regra correspondente. |
GET /api/user/routers/:id/dsl/history | Member | Histórico de versões, mais recente primeiro. |
POST /api/user/routers/:id/dsl/rollback/:version | Developer+ | Refazer o lint e restaurar uma versão mais antiga. |
FAQ
Como isso difere da estratégia de um roteador nomeado?
Como isso difere da estratégia de um roteador nomeado?
Ela é uma estratégia — a opção
dsl ao lado de cheapest / quality /
balanced / adaptive. As outras escolhem por preço e qualidade; a DSL
escolhe por regras que você escreve sobre o formato, a classificação e o
estado do agente da requisição. Você ainda pode usar delegate: para uma estratégia integrada como
efeito de uma regra ou como o default.O que acontece se nenhuma regra corresponder?
O que acontece se nenhuma regra corresponder?
O efeito
default: de nível superior se aplica. Ele é obrigatório, então há
sempre um resultado definido — comumente delegate: balanced ou um modelo
específico de rede de segurança.É seguro executar CEL não confiável no hot path?
É seguro executar CEL não confiável no hot path?
Sim. O CEL roda em um sandbox apenas com funções da biblioteca padrão, um
prazo de avaliação de alguns milissegundos, regex RE2 (tempo linear, sem
ReDoS) e nenhum acesso ao banco de dados, à rede ou ao sistema de arquivos. O
ambiente de variáveis é um conjunto fixo de escalares e listas.
Posso testar um conjunto de regras antes que ele toque o tráfego real?
Posso testar um conjunto de regras antes que ele toque o tráfego real?
De três formas: faça um dry-run contra uma requisição sintética no editor,
deixe-o em modo shadow e leia o relatório de diff, e então faça o canary
dele em uma pequena porcentagem do tráfego ao vivo antes de subir para 100%.
