Routing DSL: componi un pannello di modelli che pensa come Fable 5
Per due anni, la strategia per "più intelligenza" è stata "aspettare il prossimo modello." Pensiamo che questa sia l'unità di progresso sbagliata. La frontiera non è un singolo checkpoint — è un comitato. Dai a tre buoni modelli lo stesso problema difficile, lasciali dissentire e arbitra tra le risposte, e il comitato batte qualsiasi dei suoi membri. Spesso batte il modello successivo nella classifica dei prezzi.
Il Routing DSL è il modo in cui costruisci quel pannello. È una strategia di routing programmabile — YAML + CEL — che trasforma il tuo endpoint OrcaRouter in un grafo di inferenza: instradare per difficoltà, instradare per compito, distribuire a più modelli contemporaneamente, giudicare o votare i loro output, fare fallback quando la confidenza è bassa e ottimizzare il tutto per costi, latenza o qualità. Scrivi regole; il gateway le compila e le esegue su ogni richiesta in ~5 ms.
Questo post è un tour ingegneristico: la grammatica, le variabili su cui puoi diramarti, i quattro arbitri, la cascata e un set completo di regole di produzione alla fine.
Prima il risultato
Due benchmark illustrativi. (I numeri sono illustrativi — servono a mostrare la forma dell'effetto, non per essere citati come punteggi ufficiali.)
Frontier comparison — un endpoint DSL instradato per difficoltà vs. il solo Frontier:

Pannelli Fusion vs. modelli singoli — valutati su 93 di 100 compiti (da OpenRouter):

Tre cose che meritano di essere fissate:
Ogni pannello di fusione batte ciascuno dei suoi stessi membri. Opus 4.8 + GPT-5.5 (~67.5%) supera sia Opus da solo (~58.5%) che GPT-5.5 da solo (~60%) di 7–9 punti. Il disaccordo è segnale; l'arbitraggio lo raccoglie.
Fusion raggiunge il livello successivo. Tre pannelli diversi incrociano Fable 5 solo (~65.5%) utilizzando solo i modelli sotto di esso.
Non hai bisogno di membri costosi. Opus + Opus auto-fusione (~65.5%) eguaglia Fable 5 con un modello e un sampler. Un panel di economici modelli — Gemini 3 Flash + Kimi K2.6 + DeepSeek V4 Pro (~64.5%) — si colloca leggermente sotto Fable 5 a una frazione del costo per token. Questa è l'intera tesi: acquista intelligenza con la topologia, non con il prossimo livello di prezzo.
Il Routing DSL è la superficie di controllo che ti consente di spendere quella topologia solo dove paga — modelli economici sull'80% facile, un pannello di fusione sulla coda dura.
La grammatica in 30 secondi
Un ruleset è versione, un elenco di regole e un default obbligatorio. Le regole vengono valutate dall'alto verso il basso; la prima when: quella vera vince. No when: significa "sempre corrisponde".
versione: 1
rules:
- id: only_rule
use: { model: "claude-sonnet-4-6" }
default:
delegate: balancedIl when: è un'espressione booleana CEL — sandboxed, regex solo RE2, nessun loop, nessun I/O, valutazione in microsecondi, con un singolo deadline di 5 ms condiviso su tutto il ruleset. Il use: è l'effetto: dove va la richiesta e come è ottimizzata. I limiti sono volutamente piccoli (≤30 regole, ≤16 KiB di source, ≤200 caratteri per when:) così il ruleset rimane verificabile.
Primitive 1 — percorso per difficoltà e compito
Il distributore classifica ogni richiesta prima di instradarla ed espone le funzionalità a CEL. Puoi diramare direttamente su di esse:
versione: 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: balancedLe variabili che puoi leggere in when: (abbreviato — consulta il riferimento completo nella documentazione):
Esempi di gruppo
Forma della richiesta
request.input_tokens, request.output_max_tokens, request.stream, request.vision, request.message_count, request.has_toolsClassificazione
task_class (chat/code/agent/vision/audio/rag/creative), difficulty (0.0–1.0), code_keyword_density, reasoning_cue_count, log_prompt_tokens, tool_countSessione
agent_state.turn, agent_state.tools_used, agent_state.has_edited, agent_state.last_test_failed, agent_state.consecutive_errors, agent_state.models_triedContesto
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).Qualsiasi destinazione può portare manopole per chiamata, tradotte nei parametri nativi di ogni provider dall'adattatore relay: reasoning_effort (basso/medio/alto), thinking_budget_tokens (1024–64000), samples (1–16), temperature (0.0–2.0), più param_override / header_override protetti da denylist. Questo è già sufficiente per costruire l'endpoint con routing basato sulla difficoltà dalla Tabella A: modello economico per la coda facile, Opus con un budget di pensiero per quella difficile.
Primitive 2 — espansione a ventaglio su un pannello (fusione)
È da qui che proviene l'incremento del benchmark. Un parallelo: l'effetto invia la richiesta a 2–5 percorsi contemporaneamente, quindi un arbitro decide ciò che il client vede effettivamente:
- 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"Quattro strategie arbitrali, ciascuna una risposta diversa a "di chi vince l'output?":
primo — gareggia con le gambe, servi il primo successo, cancella i perdenti. Ottimizza latenza (ottieni il più veloce tra N).
maggioranza — voto strutturato tra gli output delle gambe, nessuna chiamata aggiuntiva al modello. Quando le gambe divergono senza una maggioranza stretta, il ramo opzionale on_disagreement: ri-invia un tentativo nuovo e più forte invece di fornire uno spareggio. Ottimizza robustezza nei compiti con una risposta canonica.
best_of_n — un giudice LLM legge tutti i candidati e li classifica. Questa è la configurazione Opus + GPT-5.5 → judge della Tabella B. Ottimizza la qualità su lavori aperti; ricade su first-successful se il giudice commette errori.
test superati — basato sull'esecuzione: serve il candidato la cui patch fa effettivamente passare la suite di test. Nessun giudice che indovina — è il sistema di test a decidere. Questo è il più forte arbitro per il lavoro su codice/agenti. Il verificatore risiede al di fuori del gateway (collegato tramite un VerifierProvider); senza alcun verificatore collegato, degrada al primo riuscito.
max_latency_ms (1000–600000, default 120000) limita il fan-out in modo che un ramo lento non possa bloccare la risposta — i ritardatari vengono eliminati. L'annidamento di parallel all'interno di parallel viene rifiutato al lint; il pannello è intenzionalmente profondo un solo livello.
Nota sulla disponibilità: il runtime di fan-out N-way è subordinato al flag del server ROUTING_DSL_ENSEMBLE_RUNTIME mentre la fatturazione per gamba è stata resa stabile in staging — ecco perché la fusione è in anteprima, non GA. Con il flag disattivato, una regola parallel: serve correttamente la sua prima gamba, quindi puoi creare e shadoware i tuoi pannelli oggi e attivarli quando la fusione arriverà nella tua regione.
Primitiva 3 — fallback e cascate di confidenza
Fan-out spende N× in anticipo. Una cascata spende extra solo quando la prima risposta sembra sbagliata. Dopo la risposta, on_low_confidence: valuta i segnali e, se uno si attiva, reinvia a una destinazione più forte:
- 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"I segnali: patch_invalid (il diff fallisce git apply --check), self_doubt (un set di regex per frasi di attenuazione), low_logprob (logprob medio del token sotto soglia, dove il provider lo espone), e next_turn_test_failed (un latch tra turni — il prompt di questo turno porta la forma dei test falliti del turno precedente). Le cascate sono depth-1 per progettazione. Abbinale con agent_state.models_tried per ottenere diversità al riprovare — non inviare mai la riparazione al modello che ha appena fallito.
Regolare la manopola: costo, latenza, qualità
Lo stesso DSL esprime tutti e tre gli obiettivi; scegli per regola:
Costo — delegato: il più economico, mantieni il modello economico sulla coda facile, e riserva il fan-out per difficoltà > 0.7. Il pannello economico della Tabella B (~64.5% ≈ Fable 5 solo) è la prova di esistenza: una fusione di modelli piccoli può sostituire un modello di frontiera a una frazione del costo per token. Sii chiaro, però — la fusione utilizza il "fattura ogni gamba" modello: un pannello best_of_n a 3 gambe fattura tre candidati più il giudice. L'economia funziona perché (a) fai il fan-out solo sulla minoranza difficile delle richieste e (b) fondi più economici membri rispetto al modello di frontiera che stai sostituendo.
Latenza — arbiter: { strategy: first } più uno stretto max_latency_ms ti dà il più veloce di N con un tetto massimo.
Qualità — best_of_n per lavori aperti, tests_pass quando c'è una suite su cui basarsi. samples e thinking_budget_tokens acquistano di più in un unico turno.
Operandolo senza rompere prod
I cambiamenti di routing sono spaventosi, quindi il DSL è dotato delle barriere di sicurezza che un SRE si aspetta:
Lint su ogni salvataggio — schema, CEL type-check (ogni when: deve valutare a bool), risoluzione dei ref, range dei knob, denylist di header/param. Gli errori vengono restituiti come {line, column, message, rule} e visualizzati come gutter chips nell'editor.
Prova a secco — Invia una richiesta sintetica tramite POST (task_class, difficulty, agent_state, …) e ricevi la regola corrispondente, l'effetto risolto e il tempo di valutazione prima che qualsiasi cosa venga spedita.
Modalità ombra — per 24 ore dopo il primo salvataggio, il DSL viene valutato ma non utilizzato; un log ombra registra le selezioni potenziali e la console mostra una differenza (percentuale di rotte modificate, delta del costo giornaliero previsto, conteggi di attivazione per regola).
Canary— un cursore di traffico 0–100. Rampa 5 → 25 → 50 → 100 osservando le metriche per slice; annulla portando a 0.
Audit + rollback — ogni salvataggio/rollback scrive una riga di audit nella stessa transazione; le modifiche concorrenti ricevono un 409 con la versione corrente, in modo da poter riprovare con lo stato aggiornato.
Casi di test, replay di tracce e una vista AI 'spiega questo set di regole' completano il tutto. Lo trovi nella dashboard sotto routing → strategy → DSL.
Un set completo di regole
Economico su facile, medio su medio, un pannello di fusione giudicato sulla coda agente dura, con una cascata di fiducia sotto:
versione: 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: balancedQuell'endpoint è quello che si trova in cima alla Tabella A — non perché abbia trovato un modello migliore, ma perché spende il modello giusto per la richiesta giusta e fonde un pannello esattamente dove il pannello vince.
Inizia a comporre
Il prossimo salto di capacità non deve aspettare il prossimo checkpoint. È un grafo che puoi scrivere oggi pomeriggio: instrada per difficoltà, dirama sulla coda dura, giudica o testa gli output, cascata quando la fiducia cala.
Documentazione: https://docs.orcarouter.ai/routing/routing-dsl
UI: routing → Crea router -> Strategia di routing → DSL (esperto)
La Frontier è un pannello. Vai a costruire il tuo.
