Przejdź do głównej treści
Wbudowane strategie — cheapest, quality, balanced, adaptive — wybierają model na podstawie ceny i jakości. Routing DSL to warstwa poniżej, na wypadek gdy właściwy model zależy od tego, czym żądanie faktycznie jest: długą agentyczną turą kodowania, tanim wywołaniem klasyfikacyjnym, żądaniem wizyjnym, ponowieniem po nieudanym teście. Piszesz reguły; bramka ewaluuje je per żądanie i routuje odpowiednio. To strategia dsl nazwanego routera — więc Twoja aplikacja nadal wywołuje orcarouter/{name}, a logika routingu żyje w panelu, wersjonowana i edytowalna bez redeployu.

Kiedy sięgnąć po DSL

Użyj wbudowanej strategii, gdy “najtańszy żywy model” lub “najlepsza jakość” oddaje Twoją intencję. Sięgnij po DSL, gdy routing zależy od treści lub kontekstu żądania:
  • Specjalizacja zadań — wysyłaj kod do modelu do kodowania, wizję do modelu wizyjnego, tani chat do taniego modelu.
  • Routing świadomy trudności — eskaluj tylko trudne żądania do drogiego modelu; łatwe trzymaj tanio.
  • Routing świadomy agenta — routuj różnie na podstawie stanu sesji (których narzędzi agent użył, czy testy właśnie zawiodły, która to tura).
  • Reguły czasu / najemcy / nagłówka — różny routing według godziny, grupy użytkowników lub nagłówka żądania.

Włączanie

W panelu pod Routing otwórz router i ustaw jego Strategia na DSL. To odsłoni edytor DSL dla tego routera. Wszystko inne dotyczące routera nadal obowiązuje — glob Allowed models, siatka bezpieczeństwa Default model oraz wywołanie orcarouter/{name}.

Edytor

Edytor jest zbudowany tak, by szybko przeprowadzić Cię od intencji do działającego zestawu reguł:
  • Templates zasiane Twoimi prawdziwymi modelami z workspace (przez jednorazowy dialog mapowania tierów), więc nigdy nie zaczynasz od pustego pliku ani nie wpadasz na ścianę “unknown model”.
  • Insert — wstaw Model, Router (orcarouter/<name>) lub Pool z autouzupełniania, zamiast wpisywać identyfikatory ręcznie.
  • Generate — opisz routing, jakiego chcesz, zwykłym językiem i otrzymaj skompilowany, czysty wg lintingu DSL osadzony w Twoich prawdziwych modelach.
  • Explain — parafraza zwykłym językiem tego, co robi bieżący zestaw reguł.
  • Inline lint — każdy błąd raportuje {line, column, message}, a każdy kod lintingu ma objaśnienie pod ?. Pierwszeństwo (first-match-wins) i typowe wzorce CEL są pokazane w miejscu.

Struktura pliku

Zestaw reguł to YAML z trzema kluczami najwyższego poziomu:
version: 1              # required — currently must be 1
rules: [...]            # required — 1 to 30 rules, evaluated in order
default: {...}          # required — the effect when no rule matches
Reguła to warunek when: i efekt use::
rules:
  - id: hard_code              # required: ^[a-z][a-z0-9_]{0,39}$, unique
    when: |                    # optional CEL boolean; absent ⇒ always matches
      task_class == "code" && difficulty > 0.6
    use:
      model: "anthropic/claude-sonnet-4-6"
default:
  delegate: balanced           # fall back to a built-in strategy
Reguły są ewaluowane od góry do dołu; wygrywa pierwsza reguła, której when: jest prawdą. Jeśli żadna nie pasuje, stosuje się default:. Uporządkuj reguły od najbardziej szczegółowej — szeroka, wczesna reguła przesłoni wszystko poniżej.

when: — warunek

Warunki pisze się w CEL (Common Expression Language): bezpiecznym z założenia — bez pętli, bez I/O, ewaluacja w mikrosekundach, wyłącznie regex RE2. Te sześć wzorców pokrywa zdecydowaną większość rzeczywistych reguł:
WzorzecPrzykład
Dostęp do polatask_class == "agent"
Porównanie liczbowedifficulty > 0.6 && request.input_tokens < 50000
Logika boolowskaagent_state.has_edited && !agent_state.has_run_tests
Przynależność do listy"Edit" in agent_state.tools_used
Makro regexsystem_prompt_matches("(?i)planning agent")
Makro narzędziatool_calls_present_any(["Edit","Write","apply_patch"])

Zmienne

Kształt żądania
ZmiennaTyp
modelstring
request.input_tokensint
request.output_max_tokensint
request.streambool
request.visionbool
request.message_countint
request.has_system_promptbool
request.has_toolsbool
Klasyfikacja (obliczana przez bramkę per żądanie)
ZmiennaTypZnaczenie
task_classstringchat / code / agent / vision / audio / rag / creative
difficultydouble0.01.0
code_keyword_densitydouble0.01.0
reasoning_cue_countintsygnały rozumowania wykryte w promptcie
tool_countintodrębne definicje narzędzi w żądaniu
Sesja agenta (agent_state.*, utrwalana w obrębie konwersacji)
ZmiennaTyp
agent_state.turnint
agent_state.tools_usedlist<string>
agent_state.files_readlist<string>
agent_state.has_editedbool
agent_state.has_run_testsbool
agent_state.last_test_failedbool
agent_state.consecutive_errorsint
agent_state.elapsed_secondsint
agent_state.models_triedlist<string>
Kontekst
ZmiennaTyp
headers["x-foo"]string
user.id / user.groupint / string
token.id / token.nameint / string
time.hour / time.weekdayint (UTC)
workspace.idint

Makra

Zarejestrowane funkcje CEL do typowych sprawdzeń “zajrzyj do wnętrza żądania”:
MakroZwraca
system_prompt_matches(regex)RE2 po połączonych wiadomościach systemowych
user_message_matches(regex)RE2 po ostatniej wiadomości użytkownika
tool_definitions_include(name)narzędzie jest zadeklarowane w żądaniu
tool_calls_present_any(list)żądanie niesie którekolwiek z tych wywołań narzędzi
tool_results_from_any(list)żądanie ma wiadomości roli tool od któregokolwiek
header_matches(name, regex)RE2 po wartości nagłówka

use: — efekt

Blok use: nazywa cel (dokładnie jeden) oraz dowolną liczbę opcjonalnych pokręteł per wywołanie.

Cel

use:
  model:    "anthropic/claude-sonnet-4-6"   # one upstream model
  models:   ["openai/gpt-4o-mini", "..."]   # load-balance across a list
  pool:     "@pool:<name>"                   # an admin-curated pool
  delegate: balanced                         # hand off to a built-in
                                             #   strategy: cheapest |
                                             #   quality | balanced |
                                             #   linucb | gated_adaptive
delegate: dsl jest odrzucane (powodowałoby rekurencję). Przypinanie do konkretnych kanałów (channels: / @channel:) nie jest obecnie dostępne i jest lintowane jako nieobsługiwane — routuj przez model, models lub pool.

Pokrętła per wywołanie

Połącz z dowolnym celem, aby ukształtować wywołanie upstream:
use:
  reasoning_effort:       low | medium | high     # OpenAI o-series, Gemini
  thinking_budget_tokens: 1024..64000             # Claude / Gemini thinking
  samples:                1..16                    # the n parameter
  temperature:            0.0..2.0
  param_override:         { ... }                  # merged into upstream params
  header_override:        { ... }                  # merged into upstream headers
  reason_tag:             "<[a-z0-9_]+>"           # shows up in logs/telemetry
  affinity_ttl:           "5m"                      # channel stickiness window
  model_rewrite:          "<upstream-model>"       # send under a different name
param_override i header_override egzekwują listę zablokowanych — nie możesz nadpisać model, messages, stream, tools, nagłówków uwierzytelniania itp. (te podważyłyby rozliczanie, audyt lub stan agenta).

Kaskady pewności i ensemble (zaawansowane)

Dwa zaawansowane efekty pozwalają regule zareagować na słabą pierwszą odpowiedź lub rozwidlić się na kilka modeli. Tworzy się je tak samo jak każdą regułę. Cascade — ponów próbę przy sygnale niskiej pewności z silniejszym efektem:
rules:
  - id: code_with_repair
    when: task_class == "code"
    use:
      model: "openai/gpt-4o-mini"
    on_low_confidence:
      signals: [patch_invalid, self_doubt, next_turn_test_failed]
      use:
        model: "anthropic/claude-sonnet-4-6"   # repair attempt
Ensemble — wydaj kilka odnóg równolegle i pozwól arbitrowi wybrać:
use:
  parallel:
    - { model: "anthropic/claude-sonnet-4-6" }
    - { model: "openai/gpt-4o-mini", samples: 2 }
  arbiter:
    strategy: best_of_n        # or majority | first | tests_pass
    model:    "anthropic/claude-sonnet-4-6"   # judge (best_of_n only)
  max_latency_ms: 120000
Środowisko runtime dla ensemble / cascade jest objęte bramką i domyślnie wyłączone. Ponieważ każda odnoga równoległa i każda naprawa kaskadowa rozlicza się jako osobne wywołanie, runtime rozwidlenia jest za flagą serwera, dopóki rozliczanie per odnoga jest walidowane. Przy wyłączonym, reguła parallel: obsługuje tylko pierwszą odnogę, a kaskada zapisuje swój sygnał, ale nie redyspozycjonuje ponownie — zestaw reguł nadal lintuje się, zapisuje i routuje swój podstawowy efekt normalnie. Skontaktuj się z nami, aby włączyć runtime ensemble dla Twojego workspace.

Bezpieczne wdrażanie

Nowy zestaw reguł nie przejmuje Twojego ruchu w chwili, gdy go zapisujesz:
  • Tryb shadow — przez okno po pierwszym zapisie DSL jest ewaluowane, ale nie używane: Twoja poprzednia strategia nadal obsługuje ruch, podczas gdy bramka zapisuje, co DSL zrobiłoby. Panel pokazuje raport różnic — odsetek różniących się tras, prognozowaną deltę kosztu, liczbę odpaleń per reguła oraz jak często wpadało w default:. Przeczytaj go, zanim zaufasz regułom.
  • Canary — wprowadzaj DSL na procent żywego ruchu (5 → 25 → 50 → 100), obserwując metryki per wycinek, i wycofaj natychmiast, przesuwając procent do 0.
Możesz też wykonać dry-run zestawu reguł na syntetycznym żądaniu (klasa zadania, trudność, stan agenta, kształt żądania) wprost w edytorze i zobaczyć ślad oraz dopasowaną regułę — bez ruchu, nic nie jest utrwalane.

Limity i walidacja

Każdy zapis uruchamia ścisły linting; nieprawidłowe zestawy reguł są odrzucane z {line, column, message, rule}:
  • Schema — wymagane klucze, poprawne typy/enumy, brak nieznanych pól.
  • Size — ≤ 30 reguł, ≤ 16 KiB YAML, ≤ 200 znaków na when:.
  • CEL — parsuje się, przechodzi kontrolę typów względem środowiska zmiennych, brak nieznanych identyfikatorów, a when: musi ewaluować się do bool.
  • Effect — dokładnie jeden cel na blok use:; wszystkie odwołania model / models / @pool: muszą rozwiązać się w Twoim workspace.
  • Knob rangesthinking_budget_tokens ∈ [1024, 64000], temperature ∈ [0, 2], samples ∈ [1, 16].
  • Reserved — id reguł zaczynające się od _ są zarezerwowane; default jako id reguły jest odrzucane (użyj bloku default: najwyższego poziomu).
Każdy zapis i rollback dopisuje wiersz audytu; równoczesne edycje są wykrywane, a drugi zapis jest proszony o ponowienie względem świeżego stanu.

Kompletny przykład

version: 1
rules:
  - id: vision
    when: request.vision
    use: { model: "openai/gpt-4o" }

  - id: cheap_chat
    when: task_class == "chat" && difficulty < 0.3
    use: { delegate: cheapest }

  - id: hard_code
    when: task_class == "code" && difficulty > 0.6
    use:
      model: "anthropic/claude-sonnet-4-6"
      thinking_budget_tokens: 8000
      reason_tag: hard_code

  - id: agent_after_failed_test
    when: agent_state.last_test_failed && agent_state.consecutive_errors >= 2
    use:
      model: "anthropic/claude-sonnet-4-6"
      reason_tag: repair

default:
  delegate: balanced
Aby potwierdzić, do jakiego modelu rozwiązało się żądanie, odczytaj nagłówki odpowiedzi X-Orca-Router i X-Orca-Resolved-Model Nagłówki odpowiedzi.

Dokumentacja API

DSL jest zarządzane per router; zapisy wymagają Developer+.
Metoda i ścieżkaRolaCel
GET /api/user/routers/:id/dslMemberŹródło + wersja + stan shadow/canary.
PUT /api/user/routers/:id/dslDeveloper+Linting + zapis (nowa wersja, audytowana).
POST /api/user/routers/:id/dsl/lintMemberLinting szkicu → {errors:[…]}.
POST /api/user/routers/dsl/lintMemberBezstanowy linting (bez id routera).
POST /api/user/routers/:id/dsl/dryrunMemberEwaluacja syntetycznego żądania → ślad + dopasowana reguła.
GET /api/user/routers/:id/dsl/historyMemberHistoria wersji, najnowsze pierwsze.
POST /api/user/routers/:id/dsl/rollback/:versionDeveloper+Ponowny linting i przywrócenie starszej wersji.

FAQ

To jest strategia — opcja dsl obok cheapest / quality / balanced / adaptive. Pozostałe wybierają według ceny i jakości; DSL wybiera według reguł, które piszesz nad kształtem żądania, jego klasyfikacją i stanem agenta. Nadal możesz delegate: do wbudowanej strategii jako efekt reguły lub jako default.
Stosuje się efekt default: najwyższego poziomu. Jest wymagany, więc zawsze istnieje zdefiniowany wynik — zwykle delegate: balanced lub konkretny model siatki bezpieczeństwa.
Tak. CEL działa w piaskownicy wyłącznie z funkcjami biblioteki standardowej, kilkumilisekundowym limitem czasu ewaluacji, regexem RE2 (czas liniowy, brak ReDoS) i bez dostępu do bazy danych, sieci czy systemu plików. Środowisko zmiennych to ustalony zbiór skalarów i list.
Trzy sposoby: wykonaj na nim dry-run względem syntetycznego żądania w edytorze, zostaw go w trybie shadow i przeczytaj raport różnic, a następnie wprowadź go w canary na mały procent żywego ruchu, zanim rozkręcisz do 100%.