dsl-Strategie eines benannten Routers — sodass
deine Anwendung weiterhin orcarouter/{name} aufruft und die Routing-Logik
im Dashboard lebt, versioniert und ohne Re-Deployment bearbeitbar.
Wann du zur DSL greifen solltest
Verwende eine eingebaute Strategie, wenn “günstigstes Live-Modell” oder “beste Qualität” deine Absicht erfasst. Greife zur DSL, wenn das Routing vom Inhalt oder Kontext der Anfrage abhängt:- Aufgabenspezialisierung — sende Code an ein Coding-Modell, Vision an ein Vision-Modell, günstigen Chat an ein günstiges Modell.
- Schwierigkeitsbewusstes Routing — eskaliere nur die schwierigen Anfragen an ein teures Modell; halte die einfachen günstig.
- Agent-bewusstes Routing — route unterschiedlich basierend auf dem Sitzungszustand (welche Tools der Agent verwendet hat, ob gerade Tests fehlgeschlagen sind, in welchem Turn er sich befindet).
- Zeit-/Tenant-/Header-Regeln — unterschiedliches Routing nach Stunde, Benutzergruppe oder einem Anfrage-Header.
Aktivierung
Im Dashboard unter Routing öffnest du einen Router und setzt seine Strategie auf DSL. Das blendet den DSL-Editor für diesen Router ein. Alles andere am Router gilt weiterhin — der Erlaubte Modelle-Glob, das Standardmodell-Safety-Net und derorcarouter/{name}-Aufruf.
Der Editor
Der Editor ist darauf ausgelegt, dich schnell von der Absicht zu einem funktionierenden Regelsatz zu bringen:- Templates, geseedet mit den echten Modellen deines Workspace (über einen einmaligen Tier-Mapping-Dialog), sodass du nie mit einer leeren Datei startest oder gegen eine “Unbekanntes Modell”-Wand läufst.
- Insert — füge ein Model, einen Router (
orcarouter/<name>) oder einen Pool per Autovervollständigung ein, statt Bezeichner von Hand einzutippen. - Generate — beschreibe das gewünschte Routing in natürlicher Sprache und erhalte kompilierte, lint-saubere DSL, fundiert in deinen echten Modellen.
- Explain — eine umgangssprachliche Umschreibung dessen, was der aktuelle Regelsatz tut.
- Inline-Lint — jeder Fehler meldet
{line, column, message}und jeder Lint-Code hat einen?-Erklärer. Präzedenz (First-Match-Wins) und die gängigen CEL-Muster werden an Ort und Stelle aufgezeigt.
Dateistruktur
Ein Regelsatz ist YAML mit drei Top-Level-Schlüsseln:when:-Bedingung und ein use:-Effekt:
when: wahr ist,
gewinnt. Wenn keine passt, greift default:. Ordne deine Regeln am spezifischsten
zuerst — eine breite frühe Regel überschattet alles darunter.
when: — die Bedingung
Bedingungen werden in CEL
(Common Expression Language) geschrieben: sicher von Grund auf — keine Schleifen, kein I/O,
Auswertung im Mikrosekundenbereich, nur RE2-Regex. Diese sechs Muster decken die große
Mehrheit echter Regeln ab:
| Muster | Beispiel |
|---|---|
| Feldzugriff | task_class == "agent" |
| Numerischer Vergleich | difficulty > 0.6 && request.input_tokens < 50000 |
| Boolesche Logik | agent_state.has_edited && !agent_state.has_run_tests |
| Listenzugehörigkeit | "Edit" in agent_state.tools_used |
| Regex-Makro | system_prompt_matches("(?i)planning agent") |
| Tool-Makro | tool_calls_present_any(["Edit","Write","apply_patch"]) |
Variablen
Anfrageform| Variable | Typ |
|---|---|
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 |
| Variable | Typ | Bedeutung |
|---|---|---|
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 | im Prompt erkannte Reasoning-Cues |
tool_count | int | distinkte Tool-Definitionen auf der Anfrage |
agent_state.*, über eine Konversation hinweg persistiert)
| Variable | Typ |
|---|---|
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> |
| Variable | Typ |
|---|---|
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 |
Makros
Registrierte CEL-Funktionen für die gängigen “Schau in die Anfrage hinein”-Checks:| Makro | Gibt zurück |
|---|---|
system_prompt_matches(regex) | RE2 über die zusammengefügten System-Messages |
user_message_matches(regex) | RE2 über die letzte User-Message |
tool_definitions_include(name) | ein Tool ist auf der Anfrage deklariert |
tool_calls_present_any(list) | die Anfrage trägt einen dieser Tool-Calls |
tool_results_from_any(list) | die Anfrage hat Tool-Role-Messages von einem davon |
header_matches(name, regex) | RE2 über einen Header-Wert |
use: — der Effekt
Ein use:-Block benennt ein Ziel (genau eines) und beliebig viele
optionale Knobs pro Aufruf.
Ziel
delegate: dsl wird abgelehnt (es würde rekursieren). Das Anpinnen an bestimmte
Channels (channels: / @channel:) ist derzeit nicht verfügbar und lintet
als nicht unterstützt — route stattdessen per model, models oder pool.Knobs pro Aufruf
Kombiniere sie mit jedem Ziel, um den Upstream-Aufruf zu formen:param_override und header_override erzwingen eine Denylist — du kannst
model, messages, stream, tools, Auth-Header usw. nicht überschreiben
(das würde Billing, Audit oder Agent-State unterwandern).
Confidence-Kaskaden & Ensembles (fortgeschritten)
Zwei fortgeschrittene Effekte lassen eine Regel auf eine schwache erste Antwort reagieren oder über mehrere Modelle hinweg fächern. Sie werden genauso verfasst wie jede Regel. Cascade — Retry bei einem Low-Confidence-Signal mit einem stärkeren Effekt:Die Laufzeit von Ensemble / Cascade ist gated und standardmäßig aus. Da
jeder parallele Leg und jeder Cascade-Repair als eigener Aufruf abgerechnet wird, liegt die
Fan-out-Laufzeit hinter einem Server-Flag, während das Per-Leg-Billing
validiert wird. Wenn sie aus ist, bedient eine
parallel:-Regel nur den ersten Leg und
eine Cascade zeichnet ihr Signal auf, dispatcht aber nicht erneut — der Regelsatz lintet,
speichert und routet seinen primären Effekt weiterhin normal. Kontaktiere uns, um die
Ensemble-Laufzeit für deinen Workspace zu aktivieren.Sicheres Ausrollen
Ein neuer Regelsatz übernimmt deinen Verkehr nicht in dem Moment, in dem du ihn speicherst:- Shadow-Modus — für ein Fenster nach dem ersten Speichern wird die DSL
ausgewertet, aber nicht verwendet: deine vorherige Strategie bedient weiterhin den Verkehr,
während das Gateway aufzeichnet, was die DSL getan hätte. Das Dashboard
zeigt einen Diff-Report — Prozentsatz abweichender Routen, prognostizierte
Kostendifferenz, Fire-Counts pro Regel und wie oft auf
default:durchgefallen wurde. Lies ihn, bevor du den Regeln vertraust. - Canary — ramp die DSL auf einen Prozentsatz des Live-Verkehrs hoch (5 → 25 → 50 → 100), beobachte dabei die Metriken pro Slice und rolle sofort zurück, indem du den Prozentsatz auf 0 schiebst.
Limits & Validierung
Jedes Speichern führt einen strikten Lint aus; ungültige Regelsätze werden mit{line, column, message, rule} abgelehnt:
- Schema — erforderliche Schlüssel, korrekte Typen/Enums, keine unbekannten Felder.
- Größe — ≤ 30 Regeln, ≤ 16 KiB YAML, ≤ 200 Zeichen pro
when:. - CEL — parst, typecheckt gegen die Variablenumgebung, keine
unbekannten Bezeichner, und
when:muss zu einem bool auswerten. - Effekt — genau ein Ziel pro
use:-Block; allemodel/models/@pool:-Referenzen müssen in deinem Workspace auflösbar sein. - Knob-Bereiche —
thinking_budget_tokens ∈ [1024, 64000],temperature ∈ [0, 2],samples ∈ [1, 16]. - Reserviert — Regel-IDs, die mit
_beginnen, sind reserviert;defaultals Regel-ID wird abgelehnt (verwende den Top-Level-default:-Block).
Ein vollständiges Beispiel
X-Orca-Router- und X-Orca-Resolved-Model-Antwort-Header.
API-Referenz
Die DSL wird pro Router verwaltet; Schreibvorgänge erfordern Developer+.| Methode & Pfad | Rolle | Zweck |
|---|---|---|
GET /api/user/routers/:id/dsl | Member | Quelle + Version + Shadow-/Canary-Status. |
PUT /api/user/routers/:id/dsl | Developer+ | Lint + Speichern (neue Version, auditiert). |
POST /api/user/routers/:id/dsl/lint | Member | Lint eines Entwurfs → {errors:[…]}. |
POST /api/user/routers/dsl/lint | Member | Zustandsloser Lint (ohne Router-ID). |
POST /api/user/routers/:id/dsl/dryrun | Member | Werte eine synthetische Anfrage aus → Trace + passende Regel. |
GET /api/user/routers/:id/dsl/history | Member | Versionshistorie, neueste zuerst. |
POST /api/user/routers/:id/dsl/rollback/:version | Developer+ | Erneut linten und eine ältere Version wiederherstellen. |
FAQ
Wie unterscheidet sich das von der Strategie eines benannten Routers?
Wie unterscheidet sich das von der Strategie eines benannten Routers?
Es ist eine Strategie — die
dsl-Option neben Cheapest / Quality /
Balanced / Adaptive. Die anderen wählen nach Preis und Qualität; die DSL
wählt nach Regeln, die du über Form, Klassifizierung und
Agent-State der Anfrage schreibst. Du kannst weiterhin als Effekt einer Regel oder
als Default an eine eingebaute Strategie delegate:-en.Was passiert, wenn keine Regel passt?
Was passiert, wenn keine Regel passt?
Der Top-Level-
default:-Effekt greift. Er ist erforderlich, sodass es
immer ein definiertes Ergebnis gibt — üblicherweise delegate: balanced oder ein bestimmtes
Safety-Net-Modell.Ist es sicher, nicht vertrauenswürdiges CEL auf dem Hot Path auszuführen?
Ist es sicher, nicht vertrauenswürdiges CEL auf dem Hot Path auszuführen?
Ja. CEL läuft in einer Sandbox mit ausschließlich Standardbibliotheksfunktionen, einer
Auswertungs-Deadline von wenigen Millisekunden, RE2-Regex (linear-time, kein
ReDoS) und ohne Zugriff auf Datenbank, Netzwerk oder Dateisystem. Die
Variablenumgebung ist ein fester Satz von Skalaren und Listen.
Kann ich einen Regelsatz testen, bevor er echten Verkehr berührt?
Kann ich einen Regelsatz testen, bevor er echten Verkehr berührt?
Auf drei Wegen: führe ihn per Dry-Run gegen eine synthetische Anfrage im Editor aus,
belasse ihn im Shadow-Modus und lies den Diff-Report, dann canary
ihn auf einen kleinen Prozentsatz des Live-Verkehrs, bevor du auf 100 % hochrampst.
