PROMETHEUS OS
NATIVE AI OPERATING SYSTEM
[INIT] Prometheus OS loading...
[CORE] Neural interface initializing...
[AI] LLM router connecting...
[MEM] Memory graph loading...
[AGT] Agent chains on standby...
[SEC] Security protocols active...
[NET] Provider mesh established...
[UI] Workspace rendering...
[DONE] All systems nominal.
Welcome to PROMETHEUS OS.
READY · OFFLINE · SECURE · PRIVATE
🎨 THEME ENGINE
PROMETHEUS OS · 23 THEMES
Trial version: Dark + Light themes only.
Full theme access with PROMETHEUS OS license.
Dark theme active
Experience all 23 themes in PROMETHEUS OS

Routing work between local and hosted AI

Intermediate 14 min· 4 exercises

How to decide, request by request, whether a task should run on a model on your own hardware or on a hosted model, and how the AI Index helps you plan the local side.

By the end of this lesson you will be able to
  • Compare local and hosted models on cost, privacy, capability, latency and availability.
  • Design a routing policy that applies hard rules before cost, capacity and difficulty.
  • Compute the expected cost and latency of a pre-router and of a cascade.
  • Size a local model's memory and decode speed with the AI Index formulas.
  • Implement and evaluate a simple router using escalation rate, failure rate, cost and latency.

Before this: What is an AI operating system?, APIs, Tokens and Pricing, Tokens per Second: Estimating Local AI Speed, KV Cache and Context Cost

The best answer to "local or cloud?" is usually "both". Small and private tasks run well on your own hardware for free; the hardest problems still benefit from the largest hosted models. Routing is the practice of sending each request to the right one automatically.

Why not pick just one?

Local modelHosted model
Cost per requestEffectively zero after you own the hardware (plus electricity)Paid per token
PrivacyData never leaves your machineData goes to the provider under their terms
CapabilityLimited by your memory; strong open models up to the size your machine can holdAccess to the largest frontier models
SpeedDepends on your memory bandwidth (see tokens per second)Usually fast, but subject to network and rate limits
AvailabilityWorks offlineNeeds internet and the provider to be up

Neither column wins everywhere, so a single fixed choice either overpays or underdelivers.

The routing questions

A router asks a few questions about each request, roughly in this order:

  1. Is there a hard rule? If the content is sensitive or the task is pinned to local, it stays local. Rules come first and are never overridden by cost or convenience.
  2. How hard is the task? Classifying an email, extracting fields, summarizing a page or drafting a short reply are well within the reach of a good small or mid-size model. Multi-step reasoning across a large codebase may need a frontier model.
  3. How much context does it need? Long contexts cost memory locally (the KV cache, see KV cache and context cost) and money when hosted.
  4. How fast must it be? An interactive chat needs a quick first token; an overnight batch job does not.
  5. What is the budget? Spending caps per task, per agent or per month.

A simple, effective policy many people use: local first, escalate when needed. Try the local model; if the task is classified as hard, or the local answer fails a check, escalate to a hosted model — unless a rule forbids it.

A worked example

Suppose an agent processes 2,000 support emails a day. Each email plus instructions is about 1,500 input tokens and the reply about 300 output tokens.

  • All hosted, at an illustrative $3 per million input and $15 per million output tokens: 2,000 × (1,500 × $3 + 300 × $15) ÷ 1,000,000 = $18 a day, about $540 a month.
  • Routed: 90% are routine and handled by a local model; 10% are escalated. Hosted cost drops to about $1.80 a day.

The local side has to keep up: 2,000 replies × 300 tokens = 600,000 generated tokens a day. At 40 tokens per second that is about 4 hours of generation, comfortably done in a working day on one machine. (Prices here are round illustrative numbers; check current provider pricing.)

Sizing the local side

Routing only works if your local model is good enough for the routine work and fast enough for the volume. Three numbers decide that:

  • Memory decides which models fit.
  • Memory bandwidth decides how fast they generate.
  • Compute decides how fast long prompts are read.

The AI Hardware & Model Index answers "What can this machine run?" for every machine it lists: the largest model that runs well, the models that fit but are slow, and the ones that need more memory or a cluster. Use it to choose a main local model plus a smaller, faster one for quick routing decisions and simple tasks.

Routing inside Prometheus OS

Prometheus OS routes across the providers you enable, hosted and local, and treats an explicit provider choice as absolute: if a task or agent is set to a particular provider, it does not silently fall back to another. Each request is logged with the model that handled it, so cost and behaviour can be reviewed later. Pooling several of your own machines into one local compute resource is planned and in development.

Going deeper

Routing as an optimisation problem

Stated precisely, a router picks for each request xx the model mm that minimises expected cost, but only among the models the rules allow:

m∗(x)=arg⁡min⁡m∈A(x)[cm(x)+λ (1−qm(x))]m^{*}(x) = \arg\min_{m \in A(x)} \Big[ c_m(x) + \lambda \,\big(1 - q_m(x)\big) \Big]

Here A(x)A(x) is the set of models permitted for this request after hard rules are applied (privacy, pinning, region), cm(x)c_m(x) is the cost of running request xx on model mm, qm(x)q_m(x) is the estimated probability that mm handles it acceptably, and λ\lambda (lambda) is what a bad answer costs you, in the same units as cc. Rules shrink the set before any optimisation, which is why cost can never override them. When a bad answer is cheap (a draft you will edit), λ\lambda is small and cheap models win; when it is expensive (a customer-facing legal reply), λ\lambda is large and the router pays for quality. In practice qm(x)q_m(x) comes from a small classifier, simple rules (length, keywords, task type) or past results; research systems such as FrugalGPT, Hybrid LLM and RouteLLM study how to learn it.

Two architectures: pre-routing and cascades

A pre-router decides before any model runs. A cascade tries the cheaper model first, checks the result, and escalates only on failure. Write ff for the fraction escalated, cHc_H for the hosted cost per request, and tL,tHt_L, t_H for local and hosted response times. Taking the local marginal cost as roughly zero:

  • Cascade: expected cost =f cH= f\,c_H; expected latency =tL+f tH= t_L + f\,t_H, because escalated requests pay for both attempts.
  • Pre-router: expected cost =f cH= f\,c_H; expected latency =(1−f) tL+f tH= (1-f)\,t_L + f\,t_H, but only if its predictions are right.

Worked example, continuing the support-email case. Per email, hosted cost is (1,500×3+300×15)/106=0.009(1{,}500 \times 3 + 300 \times 15) / 10^6 = 0.009 dollars. With f=0.10f = 0.10 and 2,000 emails a day, hosted spend is 2,000×0.10×0.009=1.802{,}000 \times 0.10 \times 0.009 = 1.80 dollars a day, as above. Suppose tL=6t_L = 6 s and tH=4t_H = 4 s (illustrative). The cascade averages 6+0.1×4=6.46 + 0.1 \times 4 = 6.4 s per email; a perfect pre-router averages 0.9×6+0.1×4=5.80.9 \times 6 + 0.1 \times 4 = 5.8 s. The cascade is slower but has evidence (a failed check) for every escalation; a pre-router is faster but can silently send a hard task to a model that cannot do it. Many systems combine them: pre-route the obvious cases and cascade the uncertain ones.

Sizing the local side with the Index formulas

The site's AI Index methodology uses these approximations:

  • Memory needed ≈\approx model file ×1.05\times 1.05 + KV cache + 1.5 GB, where the file is parameters ×\times bits ÷8\div 8. It fits if that is at most 85% of usable memory; on macOS the GPU can use about 75% of unified memory by default.
  • KV cache bytes per token =2×layers×KV heads×head dim×bytes per element= 2 \times \text{layers} \times \text{KV heads} \times \text{head dim} \times \text{bytes per element}.
  • Decode speed ≈1÷(bytes per token÷(0.55×bandwidth)+1.5 ms)\approx 1 \div \big(\text{bytes per token} \div (0.55 \times \text{bandwidth}) + 1.5\ \text{ms}\big), where bytes per token == active parameters ×\times bits ÷8\div 8.
  • Prefill ≈2×\approx 2 \times active parameters FLOPs per input token.

Worked example. An 8-billion-parameter model at 4 bits with 32 layers, 8 KV heads and head dimension 128, a 16-bit KV cache and an 8,192-token context, on a hypothetical Mac with 16 GB of unified memory and 400 GB/s of bandwidth.

  1. File: 8×109×4/8=4.08 \times 10^9 \times 4 / 8 = 4.0 GB; with overhead 4.24.2 GB.
  2. KV cache: 2×32×8×128×2=131,0722 \times 32 \times 8 \times 128 \times 2 = 131{,}072 bytes per token; ×8,192\times 8{,}192 tokens =1.07= 1.07 GB.
  3. Need: 4.2+1.07+1.5=6.774.2 + 1.07 + 1.5 = 6.77 GB. Limit: 16×0.75×0.85=10.216 \times 0.75 \times 0.85 = 10.2 GB. It fits.
  4. Decode: 4.0 GB/(0.55×400 GB/s)=18.24.0\ \text{GB} / (0.55 \times 400\ \text{GB/s}) = 18.2 ms, plus 1.51.5 ms, gives 19.719.7 ms per token, or about 51 tokens per second.

Now the workload. The 1,800 routine replies need 1,800×300=540,0001{,}800 \times 300 = 540{,}000 output tokens, which at 51 tokens per second is about 10,600 s, or 2.9 hours. Prefill for 1,800×1,500=2.71{,}800 \times 1{,}500 = 2.7 million input tokens costs 2×8×109×2.7×106=4.3×10162 \times 8 \times 10^9 \times 2.7 \times 10^6 = 4.3 \times 10^{16} FLOPs; assuming the machine sustains 20 TFLOPS of dense compute in practice (an assumption, check your own hardware), that is about 2,160 s, or 0.6 hours. Roughly 3.5 hours of work a day: one machine copes. A 70-billion-parameter model at 4 bits, by contrast, is a 35 GB file that does not fit in 16 GB at all, and even on a machine with enough memory at the same bandwidth it would decode at about 6 tokens per second, taking about 24 hours for the same 540,000 tokens. Bigger is not better if it cannot keep up.

A rules-first router in code

def route(task, local_ok=True):
    # 1. Hard rules first: never overridden by cost or speed.
    if task["sensitive"] or task.get("pinned") == "local":
        return "local" if local_ok else "fail: local required but unavailable"
    if task.get("pinned") == "hosted":
        return "hosted"
    # 2. Capacity: does the prompt fit the local context budget?
    if task["context_tokens"] > 32_000:
        return "hosted"
    # 3. Difficulty estimate (0..1) from a classifier or heuristics.
    if task["difficulty"] >= 0.7:
        return "hosted"
    return "local" if local_ok else "hosted"

tasks = [
    {"sensitive": True,  "context_tokens": 3_000,  "difficulty": 0.9},
    {"sensitive": False, "context_tokens": 1_800,  "difficulty": 0.2},
    {"sensitive": False, "context_tokens": 90_000, "difficulty": 0.3},
    {"sensitive": False, "context_tokens": 2_500,  "difficulty": 0.8},
    {"sensitive": False, "context_tokens": 1_500,  "difficulty": 0.1, "pinned": "local"},
]
print([route(t) for t in tasks])
print(route(tasks[0], local_ok=False))

The order of checks encodes the priorities: rules, then capacity, then difficulty. It prints ['local', 'local', 'hosted', 'hosted', 'local']: the sensitive task stays local despite being hard, and the long-context and hard tasks escalate. When the local model is down, the sensitive task returns a failure rather than leaking to a hosted model.

Measuring whether routing works

Track four numbers per week: the escalation rate (share sent to hosted), the local failure rate (local answers that later failed review), cost per completed task, and 95th-percentile latency. Then sweep the difficulty threshold (0.7 in the code) up and down on a labelled sample and plot cost against quality. Pick the point where extra spend stops buying noticeable quality. Also have a person read a small random sample of local answers each week. The local failure rate is only as good as the checks that measure it, and human review catches kinds of failure that automated checks were never written to detect.

Common pitfalls

  • Cost logic overriding rules. If a budget check or a fallback can send sensitive data to a hosted model, the rules are not hard rules. Filter allowed models first.
  • Uncapped cascades. A task that fails locally, escalates, fails again and retries can cost more than going hosted directly. Cap attempts and log each one.
  • Weak checks. A cascade is only as good as its check. "The output is valid JSON" is not "the answer is right"; use task-specific tests where possible.
  • Ignoring prefill. Long prompts make local prefill slow, especially on machines with modest compute. Size for input tokens as well as output tokens.
  • Stale prices and models. Provider prices and model line-ups change often; re-check before relying on cost projections.
  • Sizing for the average. Work arrives in bursts. Size the local side for peak hour, or allow overflow to a queue.
  • Not logging the routing decision. Without the model, reason and cost recorded per request, you cannot tune the router or explain its behaviour.

In practice

  1. Write down your rules first: what must never leave your machine.
  2. List your recurring AI tasks and mark each as routine or hard.
  3. Use the AI Index to check which models your machine runs well, and test one on your routine tasks.
  4. Send routine work local, escalate the rest, and review the log after a week: what escalated, why, and what it cost.

Key takeaways

  • Local and hosted models have opposite strengths, so most serious setups use both.
  • A router decides per request using rules first, then difficulty, context length, speed needs and budget.
  • "Local first, escalate when needed" cuts hosted costs sharply while keeping access to frontier models for hard tasks.
  • Memory, bandwidth and compute decide whether your local side can handle the routine volume; the AI Index shows this per machine.

Terms in this lesson

Model routing
Automatically choosing which model handles each request based on rules, difficulty, cost, speed and privacy.
Escalation
Passing a task from a smaller or local model to a more capable model when it is too hard or fails a check.
Hybrid AI
A setup that combines models running on your own hardware with hosted models from providers.
Model cascade
A routing pattern that tries a cheaper model first, checks the result, and escalates to a stronger model only when the check fails.
Pre-routing
Choosing a model for a request before running any model, based on rules and a prediction of the request's difficulty.

Check your understanding

  1. 1.

    In a well-designed router, what should be checked first?

  2. 2.

    An agent generates 600,000 tokens a day locally at 40 tokens per second. Roughly how long is that?

  3. 3.

    Which machine resource mainly decides how fast a local model generates text?

  4. 4.

    Using the AI Index decode formula, about how many tokens per second would a model needing 4 GB read per token generate on a machine with 200 GB/s of memory bandwidth?

  5. 5.

    A cascade handles 1,000 requests; 15% fail the local check and escalate to a hosted model costing 0.02 dollars per request. What is the hosted spend?

Exercises

Work each problem before opening the solution.

  1. Exercise 1Core

    A service handles 5,000 requests a day, each with 2,000 input and 500 output tokens. Hosted prices are 3 dollars per million input tokens and 15 dollars per million output tokens (illustrative). Compute the daily hosted cost (a) if everything goes hosted, and (b) if 80% is handled locally.

    Show solution

    Per request: (2,000×3+500×15)/106=(6,000+7,500)/106=0.0135(2{,}000 \times 3 + 500 \times 15) / 10^6 = (6{,}000 + 7{,}500)/10^6 = 0.0135 dollars.

    (a) 5,000×0.0135=67.505{,}000 \times 0.0135 = 67.50 dollars a day.

    (b) 1,0001{,}000 hosted requests ×0.0135=13.50\times 0.0135 = 13.50 dollars a day, a saving of 54 dollars a day (about 1,620 dollars over 30 days), before counting local hardware and electricity.

  2. Exercise 2Core

    Use the Index formulas for a 14-billion-parameter model at 4 bits with 40 layers, 8 KV heads, head dimension 128, a 16-bit KV cache and a 16,384-token context, on a GPU with 24 GB of usable memory and 1,000 GB/s of bandwidth. Does it fit, and what decode speed should you expect?

    Show solution

    File: 14×109×4/8=7.014 \times 10^9 \times 4/8 = 7.0 GB, ×1.05=7.35\times 1.05 = 7.35 GB.

    KV per token: 2×40×8×128×2=163,8402 \times 40 \times 8 \times 128 \times 2 = 163{,}840 bytes; ×16,384=2.68\times 16{,}384 = 2.68 GB.

    Need: 7.35+2.68+1.5=11.537.35 + 2.68 + 1.5 = 11.53 GB. Limit: 0.85×24=20.40.85 \times 24 = 20.4 GB. Fits with room to spare.

    Decode: 7.0/(0.55×1,000)=12.77.0 / (0.55 \times 1{,}000) = 12.7 ms, +1.5+1.5 ms =14.2= 14.2 ms per token, about 70 tokens per second.

  3. Exercise 3Core

    Coding. Extend the router with a daily budget for hosted calls. If a hosted call would push spending over the budget, queue the task instead of overspending. Hard rules must still come first. Test with a 0.05-dollar budget and four hard tasks costing 0.02 dollars each.

    Show solution
    class BudgetRouter:
        def __init__(self, daily_budget_usd):
            self.budget, self.spent = daily_budget_usd, 0.0
    
        def route(self, task, est_hosted_cost, local_ok=True):
            if task["sensitive"] or task.get("pinned") == "local":
                return "local" if local_ok else "fail: local required"
            wants_hosted = task["difficulty"] >= 0.7 or task["context_tokens"] > 32_000
            if not wants_hosted:
                return "local" if local_ok else self._hosted(est_hosted_cost)
            return self._hosted(est_hosted_cost)
    
        def _hosted(self, cost):
            if self.spent + cost > self.budget:
                return "queue: daily budget reached"   # never overspend silently
            self.spent += cost
            return "hosted"
    
    r = BudgetRouter(daily_budget_usd=0.05)
    hard = {"sensitive": False, "difficulty": 0.9, "context_tokens": 4_000}
    print([r.route(hard, est_hosted_cost=0.02) for _ in range(4)], round(r.spent, 2))
    

    It prints ['hosted', 'hosted', 'queue: daily budget reached', 'queue: daily budget reached'] 0.04. The third call would bring spending to 0.06, over the 0.05 budget, so it is queued. Sensitive or local-pinned tasks never reach the budget logic, so a budget can never push private data to a hosted model.

  4. Exercise 4Challenge

    20% of tasks are hard. Local takes 5 s, hosted 3 s and costs 0.01 dollars. Compare per 1,000 tasks: (a) a pre-router that catches 90% of hard tasks but also sends 10% of easy tasks to hosted; (b) a cascade with a perfect check. Give hosted cost, average latency and the number of hard tasks answered badly by the local model. Which would you choose for customer-facing replies, and why?

    Show solution

    (a) Hosted share: 0.2×0.9+0.8×0.1=0.260.2 \times 0.9 + 0.8 \times 0.1 = 0.26, so 260 hosted calls, costing 2.60 dollars. Latency: 0.74×5+0.26×3=4.480.74 \times 5 + 0.26 \times 3 = 4.48 s. Hard tasks sent local by mistake: 1,000×0.2×0.1=1{,}000 \times 0.2 \times 0.1 = 20, answered badly with no signal.

    (b) All 1,000 tried locally; 200 fail the check and escalate, costing 2.00 dollars. Latency: 5+0.2×3=5.65 + 0.2 \times 3 = 5.6 s. Hard tasks answered badly: 0 (assuming the check is perfect).

    For customer-facing replies the cascade is usually better: it is cheaper here, and it never silently sends a weak answer; the price is about 1.1 s more average latency. If latency mattered most, a hybrid would pre-route obvious hard cases straight to hosted (saving the wasted local attempt) and cascade the rest. The conclusion depends heavily on how good the check really is; with an imperfect check, some bad local answers slip through either way.

Further reading

Go further

Sources

Fact-checked and last reviewed 2026-11-05

Stay in the loop
Prometheus OS™ · Native AI OS · Built for the future © 2025 - 2026