dsl di un router con nome — così
la tua applicazione continua a chiamare orcarouter/{name} e la logica
di routing vive nella dashboard, versionata e modificabile senza una
ridistribuzione.
Quando ricorrere al DSL
Usa una strategia integrata quando “modello attivo più economico” o “migliore qualità” cattura il tuo intento. Ricorri al DSL quando il routing dipende dal contenuto o dal contesto della richiesta:- Specializzazione per task — invia il codice a un modello di coding, la vision a un modello di vision, la chat economica a un modello economico.
- Routing consapevole della difficoltà — escala verso un modello costoso solo le richieste difficili; mantieni economiche quelle facili.
- Routing consapevole dell’agente — instrada in modo diverso in base allo stato della sessione (quali strumenti l’agente ha usato, se i test sono appena falliti, a che turno si trova).
- Regole per tempo / tenant / header — routing diverso per ora, gruppo utenti o un header della richiesta.
Abilitarlo
Nella dashboard sotto Routing, apri un router e imposta la sua Strategia su DSL. Questo rivela l’editor DSL per questo router. Tutto il resto del router continua ad applicarsi — il glob dei Modelli consentiti, la rete di sicurezza del Modello predefinito e l’invocazioneorcarouter/{name}.
L’editor
L’editor è progettato per portarti dall’intento a un ruleset funzionante rapidamente:- Template seedati con i modelli reali del tuo workspace (tramite un dialog di mappatura dei tier una tantum), così non parti mai da un file vuoto né ti scontri con un muro di “modello sconosciuto”.
- Insert — inserisci un Model, un Router (
orcarouter/<name>) o un Pool dall’autocompletamento invece di digitare gli identificatori a mano. - Generate — descrivi il routing che vuoi in linguaggio naturale e ottieni in cambio DSL compilato e privo di errori di lint, fondato sui tuoi modelli reali.
- Explain — una parafrasi in inglese semplice di ciò che fa il ruleset corrente.
- Lint inline — ogni errore riporta
{line, column, message}e ogni codice di lint ha uno spiegatore?. La precedenza (vince il primo match) e i pattern CEL comuni sono mostrati in loco.
Struttura del file
Un ruleset è YAML con tre chiavi di primo livello:when: e un effetto use::
when: è vero. Se nessuna corrisponde, si applica
default:. Ordina le tue regole partendo dalla più specifica — una
regola ampia messa presto oscura tutto ciò che sta sotto.
when: — la condizione
Le condizioni sono scritte in CEL
(Common Expression Language): sicuro per progettazione — niente loop,
niente I/O, valutazione in microsecondi, solo regex RE2. Questi sei
pattern coprono la stragrande maggioranza delle regole reali:
| Pattern | Esempio |
|---|---|
| Accesso a un campo | task_class == "agent" |
| Confronto numerico | difficulty > 0.6 && request.input_tokens < 50000 |
| Logica booleana | agent_state.has_edited && !agent_state.has_run_tests |
| Appartenenza a una lista | "Edit" in agent_state.tools_used |
| Macro regex | system_prompt_matches("(?i)planning agent") |
| Macro per strumenti | tool_calls_present_any(["Edit","Write","apply_patch"]) |
Variabili
Forma della richiesta| Variabile | 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 |
| Variabile | Tipo | Significato |
|---|---|---|
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 | indizi di ragionamento rilevati nel prompt |
tool_count | int | definizioni di strumenti distinte nella richiesta |
agent_state.*, persistita lungo una conversazione)
| Variabile | 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> |
| Variabile | 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 |
Macro
Funzioni CEL registrate per i comuni controlli “guarda dentro la richiesta”:| Macro | Restituisce |
|---|---|
system_prompt_matches(regex) | RE2 sui messaggi di sistema uniti |
user_message_matches(regex) | RE2 sull’ultimo messaggio dell’utente |
tool_definitions_include(name) | uno strumento è dichiarato nella richiesta |
tool_calls_present_any(list) | la richiesta contiene una qualsiasi di queste chiamate a strumenti |
tool_results_from_any(list) | la richiesta ha messaggi con ruolo tool provenienti da uno qualsiasi |
header_matches(name, regex) | RE2 sul valore di un header |
use: — l’effetto
Un blocco use: nomina una destinazione (esattamente una) e un
numero qualsiasi di knob opzionali per chiamata.
Destinazione
delegate: dsl viene rifiutato (ricorrerebbe su se stesso). Il pinning a
canali specifici (channels: / @channel:) non è attualmente disponibile
e il lint lo segnala come non supportato — instrada invece per model,
models o pool.Knob per chiamata
Combinali con qualsiasi destinazione per modellare la chiamata upstream:param_override e header_override applicano una denylist — non puoi
sovrascrivere model, messages, stream, tools, gli header di auth,
ecc. (lo farebbero a discapito di billing, audit o stato dell’agente).
Cascate di confidenza ed ensemble (avanzato)
Due effetti avanzati permettono a una regola di reagire a una prima risposta debole o di distribuirsi su più modelli. Si definiscono nello stesso modo di qualsiasi regola. Cascade — riprova su un segnale di bassa confidenza con un effetto più forte:Il runtime di ensemble / cascade è gated e disattivato per
impostazione predefinita. Poiché ogni leg parallela e ogni riparazione
di cascade viene fatturata come una chiamata a sé, il runtime di fan-out
è dietro un flag del server mentre il billing per leg viene validato. Con
esso disattivato, una regola
parallel: serve solo la prima leg e una
cascade registra il proprio segnale ma non effettua un nuovo dispatch —
il ruleset supera comunque il lint, viene salvato e instrada normalmente
il suo effetto primario. Contattaci per abilitare il runtime di ensemble
per il tuo workspace.Distribuire in sicurezza
Un nuovo ruleset non prende il controllo del tuo traffico nel momento in cui lo salvi:- Shadow mode — per una finestra dopo il primo salvataggio, il DSL
viene valutato ma non usato: la tua strategia precedente continua a
servire il traffico mentre il gateway registra cosa avrebbe fatto il
DSL. La dashboard mostra un report di diff — percentuale di route
divergenti, delta di costo previsto, conteggi di attivazione per regola
e con quale frequenza è caduto su
default:. Leggilo prima di fidarti delle regole. - Canary — porta il DSL su una percentuale di traffico reale (5 → 25 → 50 → 100), osservando le metriche per slice, e fai rollback istantaneo riportando la percentuale a 0.
Limiti e validazione
Ogni salvataggio esegue un lint rigoroso; i ruleset non validi vengono rifiutati con{line, column, message, rule}:
- Schema — chiavi obbligatorie, tipi/enum corretti, nessun campo sconosciuto.
- Dimensione — ≤ 30 regole, ≤ 16 KiB di YAML, ≤ 200 caratteri per
when:. - CEL — fa il parse, supera il type-check rispetto all’ambiente delle
variabili, nessun identificatore sconosciuto, e
when:deve valutare a un bool. - Effetto — esattamente una destinazione per blocco
use:; tutti i riferimentimodel/models/@pool:devono risolvere nel tuo workspace. - Range dei knob —
thinking_budget_tokens ∈ [1024, 64000],temperature ∈ [0, 2],samples ∈ [1, 16]. - Riservati — gli id di regola che iniziano con
_sono riservati;defaultcome id di regola viene rifiutato (usa il bloccodefault:di primo livello).
Un esempio completo
X-Orca-Router e
X-Orca-Resolved-Model.
Riferimento API
Il DSL è gestito per router; le scritture richiedono Developer+.| Metodo e path | Ruolo | Scopo |
|---|---|---|
GET /api/user/routers/:id/dsl | Member | Source + versione + stato shadow/canary. |
PUT /api/user/routers/:id/dsl | Developer+ | Lint + salvataggio (nuova versione, con audit). |
POST /api/user/routers/:id/dsl/lint | Member | Lint di una bozza → {errors:[…]}. |
POST /api/user/routers/dsl/lint | Member | Lint stateless (nessun id di router). |
POST /api/user/routers/:id/dsl/dryrun | Member | Valuta una richiesta sintetica → trace + regola corrispondente. |
GET /api/user/routers/:id/dsl/history | Member | Cronologia delle versioni, dalla più recente. |
POST /api/user/routers/:id/dsl/rollback/:version | Developer+ | Ripete il lint e ripristina una versione precedente. |
FAQ
In cosa differisce dalla strategia di un router con nome?
In cosa differisce dalla strategia di un router con nome?
È una strategia — l’opzione
dsl accanto a cheapest / quality /
balanced / adaptive. Le altre scelgono in base a prezzo e qualità; il
DSL sceglie in base alle regole che scrivi sulla forma della
richiesta, sulla classificazione e sullo stato dell’agente. Puoi
comunque usare delegate: verso una strategia integrata come effetto
di una regola o come default.Cosa succede se nessuna regola corrisponde?
Cosa succede se nessuna regola corrisponde?
Si applica l’effetto
default: di primo livello. È obbligatorio,
quindi c’è sempre un esito definito — comunemente delegate: balanced
o uno specifico modello di rete di sicurezza.È sicuro eseguire CEL non fidato sul percorso critico?
È sicuro eseguire CEL non fidato sul percorso critico?
Sì. CEL gira in una sandbox con sole funzioni di libreria standard, un
deadline di valutazione di pochi millisecondi, regex RE2 (tempo
lineare, niente ReDoS) e nessun accesso al database, alla rete o al
filesystem. L’ambiente delle variabili è un insieme fisso di scalari e
liste.
Posso testare un ruleset prima che tocchi il traffico reale?
Posso testare un ruleset prima che tocchi il traffico reale?
Tre modi: fai un dry-run contro una richiesta sintetica
nell’editor, lascialo in shadow mode e leggi il report di diff,
poi fai il canary su una piccola percentuale di traffico reale
prima di salire al 100%.
