Skip to content

The model router

The cheapest model that meets the quality bar for the job. Not the cheapest model.

For each model call it is asked about, the router looks at the models your deployment may use for that call, keeps those whose measured quality on that kind of work meets the bar you set, and chooses the one with the lowest expected cost for this call. A model with no fresh measurement is never chosen: when the router cannot decide on evidence, the call keeps the model its agent named.

Every decision explains itself: every candidate, why it was kept or dropped, the one chosen, and the estimated saving against the most capable model you could have run.

  1. Off (the default): the agent’s own model.
  2. Pinned: the model you pinned for this task class, if your policy allows it.
  3. Candidates: every model your policy prices and allows for this call, narrowed by your allow list, your exclusions, your residency rule, availability, and a context window large enough for the call.
  4. Evidence: each candidate’s score for this task class, yours where you have one, else Atlantic’s published figure, and only if it is fresh. No fresh score, no candidacy.
  5. The bar: drop candidates below the quality bar for the class, or slower than the latency the call needs.
  6. Cheapest expected cost wins: the call’s projected cost on each model, plus the chance of failing times the cost of the escalation that failure would buy.
  7. Nothing survived: the agent’s own model, with the reason.

Ties break on quality, then latency, then model ID, so the same inputs always give the same model. A router whose choice varied would make an evaluation meaningless.

Each step is on its own page: Inputs, A decision, worked, Escalation, How a model earns its scores and Control.

The router is part of the engine’s gateway (aal_engine.routing), in your account. It reads your deployment’s policy and evidence there, and the controls you set in LightHouse reach it as signed commands. It is rebuilt every 60 seconds, so switching it off in LightHouse is obeyed within a minute.

It decides when asked. An agent’s code asks the gateway for a decision before a call, naming the task class, and then calls the model the decision names:

decision = gateway.choose(task_class="retrieval_qa", env=env, model=card_model,
context_tokens=context_tokens, span=step_span)
model = decision.chosen if decision is not None else card_model
result = await gateway.acall(prompt, env=env, model=model, system=system)

choose never raises. Where the router is off, or cannot decide, it returns nothing and the agent keeps its own model. Each decision is recorded in your account’s gateway store and sent to LightHouse as one content-free routing_decision record.

  • Agents in the library asking the router on every call without code of their own: Coming
  • Recording what the router would have chosen while it is switched off, so you can compare before you switch it on: Coming. Today the gateway builds no router while it is off, so no decision is recorded.
  • In LightHouse: Agents → Routing. The decisions, by task class, model, agent and reason; each decision’s candidate table; the controls; the Token Value Benchmark.
  • In the API (any viewer): GET /api/v1/routing for the figures and recent decisions, GET /api/v1/routing/decisions/{id} for one decision in full, GET /api/v1/routing/settings for the controls. Add format=csv for a spreadsheet.
  • Through MCP: the read-only tools routing, routing_decision and benchmark.
Terminal window
# Last month's decisions, grouped by task class
curl "https://$AAL_TENANT.atlanticagenticlabs.com/api/v1/routing?since=2026-10-01&until=2026-10-31&group_by=task_class" \
-H "Authorization: Bearer $AAL_KEY" \
-H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
-H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET"

The answer carries totals and breakdowns by task class, model, agent and mode, each with decisions, routed, escalated, changed, saving_usd (net of escalations), escalation_usd, quality and bar; the recent decisions, each with its candidates and its plain sentence; and label: "estimated".

The generated API reference does not list these routes yet; this page and Control describe them.