The Local Tier

The Hard Ones Don't Announce Themselves

Two articles in this series ended by pointing at a line between local and frontier. Neither built it — and the thing that draws it turns out not to be a model choice at all.

Subscribe
AIAgentsDeveloper Tools
Listen to this post
AI Summary The obvious approach to routing between local and frontier models—classifying requests by difficulty upfront—fails because judging how hard a task is requires most of the work of actually doing it. …
  • The obvious approach to routing between local and frontier models—classifying requests by difficulty upfront—fails because judging how hard a task is requires most of the work of actually doing it.
  • The alternative design is a cascade that sends everything to the local model first and escalates to the frontier when verification detects failure, but self-reported confidence scores are nearly useless, with models showing only a 3-point difference between correct answers (72.5% confidence) and wrong ones (69.4%).
  • The routing line is actually drawn by what you can cheaply verify, not by which models you have—teams with fast tests and strict types can route more work locally because failures surface in seconds, while work without mechanical checks must go to the frontier.
  • Agentic coding turns out to be the best case for local inference rather than the worst, because code repositories provide free verifiers like parsers, compilers, and tests that immediately reveal when the local model has failed.
  • The router itself decides whether local hardware economics work at all, because conservative tuning creates two failure modes: escalation adds retry costs, while bypass—sending requests straight to the frontier—leaves the local machine unused and unable to reach break-even.

Part one worked out whether a model belongs on hardware you own and landed on a routing line.1 Part two worked out what to configure once it's there, and landed on the same routing line.2 Both pieces did the same slightly dishonest thing at the end: gestured at a boundary, called it the real answer, and stopped.

So build it. You have a local endpoint — in my case llama-server on 127.0.0.1:8080, holding Qwen3.8-27B at about 39.6 tokens per second — and you have an account with someone who will sell you a frontier model by the token. Both speak the same API. Now write the thing that decides.

It is harder than it looks, and it fails in a specific place.

The boundary isn't a setting. It's a program, and it has its own bugs.

The Dispatch Fantasy

The dispatch fantasy

The obvious design is a classifier. Look at the incoming request, judge how hard it is, send easy work to the local box and hard work to the frontier. Cheap requests stay home, expensive ones go out, and you capture most of the savings with none of the quality loss.

This doesn't work. Judging how hard a task is requires most of the work of doing it. Not all of it — but enough that the classifier has to be roughly as capable as the model it's protecting you from needing. If you had something cheap that could reliably tell a hard refactor from an easy one, you'd have solved a decent chunk of the refactor.

The proxies people reach for instead are noise dressed as signal. Prompt length doesn't work: a two-line question can require a deep answer and a forty-file context dump can require a rename. Keyword matching doesn't work: "just quickly" appears in front of some of the nastiest requests ever typed. Task-type routing — code to one model, prose to another — is real but coarse, and it splits along a seam that has nothing to do with difficulty.

There's genuine research on learned routers, and the good ones are more subtle than keyword matching — clustering queries and applying cost-aware dispatch before anything runs.3 Prediction still gets you only a useful fraction of the way, because the thing being predicted is not visible in the input.

So it has to be escalation

If you can't tell in advance, run it and find out. Send everything local first. Detect when the local answer isn't good enough. Retry that request against the frontier. This is the cascade, and it's the design nearly every serious system converges on — the original work on it reported cost reductions up to 98% against always calling the best available API, at matched output quality.4

The savings are real. But notice what the design just did: it moved the entire problem into one word. Detect.

Everything now rests on a failure signal. Get that right and the cascade is close to free money — you pay local prices for the majority of requests and frontier prices only for the ones that needed it. Get it wrong in one direction and you ship bad output. Get it wrong in the other and you pay for the frontier on every request while also paying for the local attempt you wasted first.

The cascade doesn't solve routing. It relocates the whole problem into the word "detect."

Ask the model? No.

The tempting shortcut is to ask. Have the local model rate its own confidence, and escalate below a threshold. It costs almost nothing and it feels principled.

It doesn't work, and the numbers are worse than most people expect. Across tested models, mean self-reported confidence runs about 72.5% on answers that were correct and 69.4% on answers that were wrong.5 Three points. That is the entire signal you're proposing to route production traffic on. On lower-tier models the gap collapses to a tenth of a point — 79.6% against 79.5% — which is to say no signal at all, delivered with total assurance.

The failure has structure. Confidence tracks familiarity rather than correctness: models appear to draw certainty from having seen something like this before, not from having reasoned about this instance.6 So confidence is highest exactly where memorization is doing the work, and the cases where it should be lowest — genuinely novel problems — are the ones it can't distinguish from the ones it has effectively memorized.

This is the thing people underestimate about LLM failure generally, and it is fatal here. A wrong answer does not look like a wrong answer. There is no exception, no stack trace, no null. A confidently incorrect refactor is byte-for-byte as plausible as a correct one until something external checks it. Software engineering has spent fifty years building intuitions around systems that fail loudly, and this one fails silently and fluently.

Self-correction doesn't rescue it either. A model asked to review its own output brings the same blind spots to the review that produced the error.

What you can actually detect

Strip out everything unreliable and you're left with a short list. These are the signals that are genuinely external to the model — things the world tells you, not things the model tells you about itself:

Signal Cost Catches
Malformed tool call / invalid JSON free format collapse
Schema validation failure free wrong shape, missing fields
Code doesn't parse free syntactic breakage
Code doesn't compile / typecheck seconds a real class of logic error
Tests fail seconds to minutes behavioural regression
Linter, static analysis seconds narrower classes
Human notices later hours to never everything else

Read that table as a cliff rather than a list. Everything above the last row is mechanical, fast, and honest. The last row is where the routing problem goes to die — and for a great deal of what people actually ask models to do, the last row is the only row available.

The sophisticated middle ground is to build calibration you can trust rather than taking the model's word for it — mapping token-level uncertainty to an actual error probability and setting the escalation threshold by cost minimization. Recent work does exactly this and beats entropy thresholding and learned-threshold approaches at the same operating point.7 It's the right direction. It also requires per-workload threshold tuning, which means it isn't something you drop in on a Tuesday — you build it for your traffic, and you rebuild it when your traffic changes.

The verifier draws the line

Which gives the thesis, and it isn't a statement about models at all:

Your routing line is drawn by what you can cheaply verify. Not by which models you have.

Two teams with identical hardware and identical API keys will end up with completely different local/frontier splits, determined entirely by how much of their work has a mechanical check attached to it. The one with fast tests and strict types can route aggressively to local, because every wrong answer surfaces in seconds and costs one retry. The one shipping unverifiable output has to send nearly everything to the frontier, because it has no way to find out it was wrong.

The corollary inverts the usual intuition. Agentic coding is the best case for local inference, not the worst. That runs against part one of this series, which routed agents to the cloud on context grounds, and against the general sense that agents are the demanding workload you buy the good model for. But agent loops in a code repository are drowning in free verifiers: every tool call either parses or doesn't, every patch either applies or doesn't, every build either goes green or doesn't. The loop that people describe as the hardest thing to run locally is the one where you can actually tell when the local model has failed you.

And the mirror case is the one nobody flags. "Summarise this document." "Draft the announcement." "What should we do about this customer?" No parser, no compiler, no test. Fluent, confident, unverifiable — and therefore unroutable, because the escalation trigger doesn't exist. You either send it to the frontier or you accept whatever comes back.

The work that's easiest to keep at home is the work with a build step.

API Compatibility Trap

"OpenAI-compatible" is a wire format, not a contract

The other half of building this is less philosophical and considerably more annoying. Both endpoints accept the same JSON. They do not behave the same way, and a router written on the assumption that you can swap a base_url will ship bugs that look like model quality problems.

Concretely, from standing this up:

  • Reasoning arrives in a different field. Qwen3.8-27B reasons by default, and llama.cpp puts that in message.reasoning_content, separate from message.content. My first test looked like a truncated failure — a 200-token budget consumed entirely by reasoning, content containing a bare function signature. A router that reads content, finds it thin, and escalates would be escalating correct answers because it was reading the wrong field.

  • Sampling parameters are mode-dependent and the wrong ones are actively harmful. Thinking mode wants temperature 1.0, top-p 0.95, presence penalty 0.0. Non-thinking wants 0.7, 0.80, and 1.5. These aren't preferences to interpolate between — running the non-thinking presence penalty against reasoning output degrades it, and a router that carries one sampling profile across both endpoints is quietly damaging one of them.

  • Tool calling needs the server configured for it. Without --jinja, llama-server doesn't apply the chat template that makes tool calls parse. The failure isn't an error; it's tool calls that don't fire. On the cascade, that reads as local incompetence and triggers escalation on every tool-using request — an infinite bill from a missing flag.

  • Advertised features may not be present. The model ships multi-token-prediction weights for speculative decoding; llama.cpp logs unused tensor blk.64.nextn.* and ignores them. Anything in your cost model assuming MTP throughput is assuming a feature this stack doesn't have.

None of these are hard once you know. All of them present as the local model is bad, which is the single most expensive misdiagnosis available to you — because the fix looks like "escalate more," and escalating more is how the economics die.

Every integration bug on the local side masquerades as a quality problem, and the remedy for a quality problem is to stop using the thing you bought.

The asymmetry that eats part one

The costs of a wrong route are lopsided. Send an easy request to the frontier and you've wasted a few cents. Send a hard one to local and you pay the local attempt, the detection, the frontier retry, and the latency of all three stacked in series — on an interactive request, that's the difference between a pause and an abandonment.

Any engineer tuning thresholds against that asymmetry will tune conservatively. Of course they will; the visible failure is the slow wrong answer, and the invisible one is the marginal API spend. So routers drift toward escalation, and the drift is one-directional because nothing pushes back.

There are really two rates here, and conflating them hides the damage.

  1. Escalation — the share of local attempts that fail verification and get retried — adds cost but removes no local hours, because you already paid the attempt.
  2. Bypass — the share sent straight to the frontier without trying local at all — is the conservative drift proper, and it is the one that empties the machine.

Both rates depend on how often a 27B clears the bar, and that varies by task far more than one number can carry. Qwen3.8-27B sits eighth of twenty on SWE-Bench Pro at 61.7% and eighteenth of twenty-five on Terminal-Bench 2.1 at 73.0%, while leading the office and instruction-following rows.8 A single escalation rate across that spread is a fiction, which is why the calculator takes it as an input instead of shipping a default.

Now put that next to part one's arithmetic. Break-even on a $6,500 workstation landed at roughly 170 GPU-hours per month against Runpod's rate, and north of 300 against the market median.1 Those numbers assume the machine is used. A conservative router is a machine-utilization problem wearing a quality-assurance costume: every threshold nudged toward safety moves hours off the local box and onto the invoice, and if it moves enough of them, the hardware that part one justified never clears its own break-even.

Which means the router — not the card, not the quant — decides whether parts one and two were good advice. You can buy the right hardware, configure it correctly, and still end up with an expensive space heater because the thing dispatching work to it doesn't trust it, and never had a way to find out whether it should.

Construction site a domestic house being built

The part that's half-built

The routing layer is mature. LiteLLM, RouteLLM, the vLLM semantic router and a half-dozen commercial gateways will all classify a request and dispatch it, which is the design this article spent its first section arguing can't work reliably. Escalation ships too: NVIDIA's NeMo Switchyard has an escalation router that starts a session on the weak model and upgrades it under sustained trouble.9

But look at what triggers it. Switchyard escalates on an LLM judge reading the conversation transcript, latching to the strong model after a couple of consecutive escalate verdicts. No compile check, no test execution, no external validator. The one productized escalation router in the field picked precisely the signal this article spent a section rejecting — a model's assessment of a model.

The verifier-driven version exists, and it works. MERA runs generated code in an isolated subprocess against test programs, checks schema validity and tool-call legality, and falls back to the larger model when verification fails — reporting 88.3% pass at 60.8% of always-large-model cost.10 R2V trains small models to recognize when to ask for help.11 Both released code. Both verify against benchmark-provided test programs. Point either at your repository, and there is nothing for it to run.

And the last piece is the one that makes this feel close rather than distant. Coding agents already have the verification loop — Cline will read a failing test, patch the component, run the test command, see a TypeScript error, and fix it. That whole cycle exists and runs today. It just retries the same model every time, because nobody wired a model-escalation policy onto a loop that was already checking its own work.

So the gap isn't conceptual, and it isn't a research problem.

Three pieces exist separately:

  • routers that dispatch
  • escalators that use the wrong signal
  • agents that run the right verifiers without escalating.

Nothing connects your repository's actual toolchain — your test command, your typechecker, your linter — to a decision about which model should have handled the turn.

That's where the local-inference case lives or dies. Not in the quantization thread, not in the break-even spreadsheet, but in the shortest piece of missing software in this entire series: the policy layer on a loop that is already, right now, checking the work.

Build that badly and everything upstream of it was decoration.

Part of the series: The Local Tier
  1. Where the Equation Flips
  2. The Wrong Knob
  3. The Hard Ones Don't Announce Themselves

Footnotes

  1. Where the Equation Flips — Part one of this series — the local-versus-cloud decision argued to an honest boundary, and the source of the two-question frame the series runs on: does it fit is capacity, does it run is bandwidth. The break-even figures cited here are its August 2026 numbers: roughly 170 GPU-hours per month against Runpod's $0.99/hour, and over 300 against the ~$0.58 market median. ↩
  2. The Wrong Knob — Part two of this series — quantization is the variable everyone argues about and the one that matters least; context window and KV cache precision decide the setup, and on a discrete card your VRAM picks the quant before you have an opinion. Source of the 39.6 tok/s measurement referenced here (Qwen3.8-27B at UD-Q3_K_XL, 48K context, q8_0 cache, 16 GB card). ↩
  3. Cluster, Route, Escalate: Cascaded Framework for Cost-Aware LLM Serving — A two-stage system that clusters incoming queries and applies cost-aware routing across a model pool, then runs a quality-estimation classifier over the cheap model's output and escalates the low-scoring ones. Representative of the state of learned routing — and note that even here the escalation decision is made on the output, not the input. ↩
  4. FrugalGPT — efficient LLM inference via model cascades — The foundational cascade result: query a sequence of models adaptively, stop when a quality threshold is met. Reported cost reductions up to 98% against always calling the best available API at matched output quality, and 50-98% on average across benchmarks. The savings are not in dispute; what the cascade requires is a working quality threshold, which is the subject of this article. ↩
  5. Benchmarking LLM self-assessment — overconfidence and miscalibration — Across tested models, mean self-reported confidence was approximately 72.5% on correct answers against 69.4% on incorrect ones — a ~3-point separation. On lower-tier models the gap collapses to 79.6% vs 79.5%. Higher-tier models are only marginally better calibrated. This is the empirical basis for rejecting self-reported confidence as an escalation trigger. See also 'Mitigating Overconfidence in Large Language Models: A Behavioral Lens on Confidence Estimation and Calibration', https://openreview.net/forum?id=y9UdO5cmHs ↩
  6. Mirage of Mastery: Memorization Tricks LLMs into Artificially Inflated Self-Knowledge — Models appear to draw confidence from having seen a solution rather than from reasoning about the instance — which puts peak confidence exactly where memorization is doing the work. See also 'LLMs Show No Signs Of Individuated Metacognition', https://arxiv.org/pdf/2605.24299 ↩
  7. UCCI: Calibrated Uncertainty for Cost-Optimal LLM Cascade Routing — A calibration-first router that maps token-level margin uncertainty to a per-query error probability via isotonic regression, then selects the escalation threshold by constrained cost minimisation — beating entropy thresholding, split-conformal routing and a FrugalGPT-style learned threshold at the same operating point. The paper's own framing of the status quo is the relevant part: most deployed routers use uncalibrated confidence scores and require per-workload threshold tuning. ↩
  8. AI Release Tracker — Qwen3.8-27B benchmark table — Every headline score is Qwen's own table and several benchmarks are in-house. Read against the full field the model sits mid-pack on hard agentic coding — SWE-Bench Pro 61.7% (8th of 20; best 80.3%), DeepSWE 1.1 42.2% (13th of 18), Terminal-Bench 2.1 73.0% (18th of 25; best 88.8%) — while leading the in-house and office rows: QwenSWEBench 79.0%, CoWorkBench 70.7%, IFBench 79.5%. The spread across task types is the reason a single escalation rate would be a fiction. ↩
  9. NVIDIA NeMo Switchyard — escalation router — Starts each conversation on a cheaper weak model; an LLM judge reads the transcript and latches the session to the strong model after N consecutive escalate verdicts (default 2, with tunable confirmations, recent_turn_window and window_message_chars). Notably the judge 'rates work the weak model actually did, not a prediction about work it might do' — the right instinct, applied through the wrong instrument. The documentation describes no support for mechanical verification: no compile checks, no test execution, no external validators. ↩
  10. MERA: Model Evolution and Routing with Skill Adaptation for Agentic Systems at Scale — Uses three verifier classes — code executed in an isolated Python subprocess against benchmark-provided test programs, schema validity and tool-call legality for structured output, and environment-state evaluation for tool-use tasks — falling back to a stronger model when verification fails. Reports 88.3% pass at 60.8% of always-large-model cost on 582 held-out HumanEval+MBPP tasks at a 1:10 small-to-large cost ratio. Code at github.com/yh-yao/MERA-Evolve. The constraint for our purposes is that the verifiers are benchmark-supplied, not repository-supplied. ↩
  11. R2V Agent: Teaching SLMs When to Ask for Help — Trains small language models to recognise the boundary of their own capability and escalate, using learned routing rather than a raw confidence threshold. Code at github.com/RaghuHemadri/r2v-agent. ↩
Back to the Journal