How we routed a production assistant's questions to the right model per request — with per-hop receipts, a deterministic classifier, and one honest failure we found and fixed along the way.
Our design partner runs a fleet-operations platform. Inside it lives an AI assistant that answers owners' questions — driver performance, attendance, coaching, vehicle compliance — by calling ~23 internal data tools in a loop and synthesizing the results.
Like most production assistants, it was pinned to one model: every question, easy or hard, went to a fast, inexpensive model. That's the rational default — until you look closely at what it does to the hard questions. So we looked closely. This is the full pilot: what we built, how we tested it on the customer's real question set, and every number we measured along the way.
Three facts collide in any production assistant:
The answer is routing: size each question first, then pick the model. The interesting part is doing that accurately, deterministically, and cheaply — and being able to prove all three from the ledger.
A judge in front of the model pool. Every incoming question is first read by a
small, fast model — the judge — which classifies it into a tier (SIMPLE / MEDIUM /
COMPLEX / REASONING). Tiers map to models: for this pilot, SIMPLE and MEDIUM →
claude-haiku-4-5, COMPLEX and REASONING → claude-sonnet-5. Five design decisions
did the heavy lifting:
1. The judge reads the application, not just the question. Here's the thing question-wording can't tell you. Compare:
"Which employees called off last week, and why?"
"Who are my worst 3 quality-flagged drivers, and why?"
Identical shape. Opposite difficulty — because in this customer's app, the call-off tool returns rows that already include the reason, while the quality tool returns raw week-by-week entries the model must aggregate itself. The first is reading a list; the second is real analysis. So the judge's system prompt is a domain profile: a compact encoding of the customer's tool catalog — which lookups come pre-joined, which return raw data, which questions require stitching two domains together. Tier = the work left over after the tools. When we benchmarked wording-only approaches on this workload, a surface heuristic scored 39% and keyword rules collapsed from 93% (on the set they were tuned on) to 62% on real queries. The domain-profile judge scored 21/21 on the customer's labeled question sheet and 8/8 on hold-out questions it had never seen.
2. Deterministic by construction. Judges default to sampling — which means a borderline question can route differently between runs. We measured exactly that before fixing it: the same cross-domain question classified MEDIUM four runs out of five and COMPLEX the fifth. The judge now runs at temperature 0 with a bounded output: same question, same route, every time (we re-ran the borderline set 5× each — zero flips).
3. Classify once per turn, not per hop. The assistant is an agentic tool loop — one user question can mean five model calls as tools return data. The judge's verdict is cached for the turn, so a 5-hop question pays for classification once. On real traffic this cut classification overhead ~5× versus judging every hop.
4. Fail toward cheap, never silently expensive. If the judge times out, a static fallback classifies; if everything fails, the request runs on the fast model. Routing can never block a request or quietly upgrade one.
5. Everything gets a receipt. Every judge call lands in the usage ledger as its own labeled line item — its cost, its verdict, and a pointer to the request that triggered it. Every answer records both the model requested and the model served. The entire pilot below is reconstructed from those receipts, not from our notes.
Here is a single real turn from the pilot — a genuinely hard question ("who has the most attendance coachings and the worst quality score?") asked through the customer's production assistant, with routing on:
| Step | What happened | Tokens in / out | Cost | Time |
|---|---|---|---|---|
| Routing check | judge reads the question → verdict: COMPLEX | 944 / 10 | $0.000994 | 1.7 s |
| Hop 1 | question + tool definitions → strong model; primes the prompt cache | 21,555 / 445 | $0.058278 | 5.8 s |
| Hop 2 | first tool results (21,435 tokens read from cache) | 21,929 / 163 | $0.006905 | 1.7 s |
| Hop 3 | tool loop continues (21,435 cached) | 22,108 / 147 | $0.007103 | 1.7 s |
| Hop 4 | tool loop continues (21,435 cached) | 22,271 / 139 | $0.007349 | 2.0 s |
| Hop 5 | final answer (21,435 cached) | 22,367 / 78 | $0.006931 | 1.7 s |
| Turn | 1 check + 5 hops | 111,174 / 982 | $0.0876 | ~11.6 s |
Four things this table proves at once: the app asked for its fast tier and the gateway served the strong model (that requested-vs-served pair is the receipt); classification cost 1.1% of the turn and ran once, not five times; provider prompt caching survived routing (hops 2–5 read 21k tokens at ~1/10 price); and every line is independently auditable in the ledger.
We took the customer's own 21-question ground-truth sheet — each question pre-labeled with its intended tier by analyzing what their tools would actually have to do — and ran it through the live assistant twice: once pinned (the old setup), once routed.
Routing accuracy: 15/15. Of the 21, fifteen were answerable by the deployed tool set; the judge routed every one correctly — 12 stayed on the fast model, 3 upgraded — including the trap question the sheet's authors predicted wording-based routers would get wrong (a "both understaffed AND underperforming" question that sounds like cross-domain analysis but is served by a single pre-joined tool, so it's mid-tier at most; the judge kept it on the fast model).
The other six questions? The assistant had no tool for that data at all — and declined cleanly every time, in fresh threads and long ones, never inventing a number. (Routing kept those on the cheapest path, where a decline should live. The gap itself became roadmap input for the customer.)
What the upgrades bought — checked against the raw data. On the three hard questions, we compared the fast model's answers and the strong model's answers against the raw tool tables:
On one cross-domain question, the strong model failed to answer at all: it worked more cautiously than the fast model — five narrow tool calls instead of two broad ones — and ran into the assistant's 5-step tool budget before it could synthesize. $0.127 spent, no answer, while the fast model had answered the same question correctly in 3 hops for $0.027.
This wasn't a routing mistake (the classification was right) or a model-quality problem. It was a client-harness interaction: step limits tuned for one model's tool-calling style can strangle another's. It's exactly the kind of thing you only find by instrumenting real turns — and exactly why we pilot before flipping production traffic. The fix was a one-setting change on the customer's side (a tier-aware step budget), verified by re-running the question. Found in testing, fixed in testing, never seen by an end user.
| Measure | Value |
|---|---|
| One routing check | $0.00097 |
| Per 1,000 questions, with per-turn caching | ~$0.19–0.97 |
| Check as share of a real analysis turn | 1.1% |
| Check as share of the full 15-question sweep | 3.4% |
| Added latency, once per question (not per hop) | ~1 s |
| Pinned-cheap sweep vs routed sweep | $0.23 → $0.43 |
| Routed vs pinning everything to the strong model | ~35% cheaper |
Read that middle row honestly: routing made this workload more expensive than pinning everything to the cheap model — because its job here was to fix quality, and the delta is almost entirely the three hard questions now served properly (the check itself is noise). Against the alternative way of getting that quality — the strong model everywhere — routing is ~35% cheaper, and the policy is a dial: a cost-leaning customer can upgrade only the hardest tier and pull the ratio back toward 1×.
For perspective on the latency line: during the same pilot we recorded an 11-second provider-side stall on a plain, unrouted call. Raw model variance dwarfs a 1-second check that runs once per question.
More from UnitSense: all posts · The AI Unit Economics Handbook →