ReadingThe Hybrid AI Standard: Routing Between On-Device AI and the Cloud
8 min read

The Hybrid AI Standard: Routing Between On-Device AI and the Cloud

Cloud adds 300 ms to every keystroke; on-device freezes 2.5 s while weights reload.

The two columns are the wait a user feels: on each keystroke, and on coming back after an app switch. All cloud is slow on every keystroke and all on-device freezes after the switch. The router answers on the device and falls back to the cloud while the weights reload.Two columns show the lag on each keystroke and after app switch. A cross marks All cloud, where the bill grows with users: 300 ms, then 300 ms again. A cross marks All on-device: under 40 ms, then a 2.5 s freeze. A check marks the Router, which decides per turn: under 40 ms, then cloud fallback. each keystroke after app switch All cloud bill grows with users 300 ms 300 ms All on-device <40 ms 2.5 s freeze Router decides per turn <40 ms cloud fallback The two columns are the wait a user feels: on each keystroke, and on coming back after an app switch. All cloud is slow on every keystroke and all on-device freezes after the switch. The router answers on the device and falls back to the cloud while the weights reload.Two columns show the lag on each keystroke and after app switch. A cross marks All cloud, where the bill grows with users: 300 ms, then 300 ms again. A cross marks All on-device: under 40 ms, then a 2.5 s freeze. A check marks the Router, which decides per turn: under 40 ms, then cloud fallback. each keystroke after app switch All cloud bill grows with users 300 ms 300 ms All on-device 2.5 s freeze <40 ms Router decides per turn <40 ms cloud fallback
Figure 1. The two columns are the wait a user feels: on each keystroke, and on coming back after an app switch. All cloud is slow on every keystroke and all on-device freezes after the switch. The router answers on the device and falls back to the cloud while the weights reload.

I score each feature against the 4 Pillars of On-Device AI, run light and frequent work on the device, and escalate to a cloud model behind App Check when a task outgrows it or the OS evicts the weights.

Listen to the audio overview(3:05)Fenrir Studio Voice
0:00
3:05

I ship AI features in production mobile and web apps. I hit the same physical wall from two opposite sides. First, I routed every prompt to a cloud LLM Large language model. A model trained on huge amounts of text to predict the next token.. On a cellular network, each Round trip The time a request takes to reach a server plus the time its reply takes to come back. added 300 ms, and that ruined my interactive UI. My Token A small piece of text, often part of a word. Models read, write and bill text by the token. bill also grew linearly with active users. Then I moved Inference Running a trained model on an input to get its answer. fully onto the device. When a user switched apps, the mobile OS Evict When memory runs low, the OS throws an app's data out of memory. The app must load it again. my model Weights The numbers a model learned in training. The model must load them into memory before it can answer. from DRAM The main working memory of a phone or computer. It is fast, and the OS shares it among all apps.. When the user came back, my app froze for 2.5 seconds.

So pure cloud and pure on-device both fail under real client limits. I built The Hybrid AI Standard to solve this in my own apps. I run frequent, privacy-sensitive tasks locally, on the device. I escalate complex reasoning and enterprise RAG Retrieval-Augmented Generation. My code looks up documents first and gives them to the model with the question. to stateless Serverless A cloud service runs my code only when requests come, and adds or removes machines for me. cloud containers, one step at a time.

The Hybrid AI Standard: Run frequent, privacy-sensitive tasks locally on the device. Escalate complex reasoning and enterprise data queries to stateless serverless cloud containers.
PART 01

What broke in my terminal and the four pillars

01

Why pure cloud and pure on-device both broke in production

I inspected my network traces on mobile cellular connections. Before the first token rendered, each user action that crossed the wire added 200 to 500 ms. That was TLS The encryption that protects web traffic. Each new connection starts with a handshake of several messages. and HTTP handshake overhead. Real-time autocomplete, UI state classification and input validation need a fast answer. For them, that round trip broke my UI responsiveness budget. It got worse when I tried synchronous split streaming between client and server. Mobile packet Jitter Random changes in how long each network packet takes to arrive. stalled my pipeline again and again.

Next, I moved everything to a small local model with less than one billion Parameter One learned number inside a model. A model's size is counted in parameters.. That solved my network latency, but it exposed a severe mobile memory trap. Mobile operating systems take memory back aggressively while the user multitasks. Whenever I left my app for 60 seconds, the OS memory manager evicted my local LLM weights and KV cache The attention keys and values a model saved for tokens it already read. Reusing them skips recomputing that prefix. from DRAM. My app then reloaded the weights from flash storage. That caused a TTFT Time to first token. How long the user waits before the first token of the answer appears. (TTFT) freeze of several seconds. Also, my local model had no access to my central production databases, and it could not enforce server-side billing quotas.

02

The four physical pillars I use to route workloads

I stopped guessing which prompts belong on the device and which belong in the cloud. Now I check every feature against four physical mechanics:

  • Low Latency (<40 ms TTFT): I run UI state classification, intent detection and inline autocomplete locally, on the device's NPU Neural processing unit. A chip in a phone or laptop built to run AI models fast and with little power.. The network round trip is 0 ms.
  • Zero Marginal Token Cost: The user's device absorbs frequent, low-entropy interactions, the simple and predictable ones. I do not pay per token for cloud inference on every keystroke.
  • Local Data Privacy: A prompt that the on-device model answers never crosses the network boundary. My router redacts nothing. So a prompt it escalates reaches the cloud as written.
  • Multitasking and Offline Resilience: My core UX keeps working offline. During multitasking, the mobile OS can evict my local weights from DRAM. Then the reload misses my router's on-device deadline. So the router falls back to a serverless cloud endpoint, and local memory restores in the background.
PART 02

My hybrid orchestration backbone

03

Client-side SDKs and stateless serverless containers

My on-device model runs in the browser or on the phone's NPU, for example through the Chrome Built-in AI Prompt API. Sometimes it hits a reasoning wall, misses its latency deadline, or needs enterprise data. Then my client escalates the request to the cloud. I split that escalation into two paths. A request that only needs a larger model goes through a lightweight client-side AI SDK Software development kit. A library a vendor ships so my app can call its service.. A request that needs my data goes to a stateless, autoscaling serverless service. In my stack these are Firebase AI Logic and Cloud Run Google's service that runs my containers on demand and stops them, down to zero, when no requests come..

In my deployment, the client SDK handles payload serialization, token streaming and automatic retries, and it calls the model directly. Requests that need my production data skip the client SDK. They go to a separate Google Cloud Run service. That service scales from zero, runs retrieval over my databases, and then calls the model.

04

Cryptographic client attestation and rate limiting

Say I expose my cloud AI endpoints to client apps with no check on the device or the user. Then I invite automated scraping and token drainage. So I enforce two guardrails at the edge, with no exceptions:

First, I use cryptographic client Attestation Proof, signed by the device or platform, that a request comes from my real app and not from a script.: Firebase App Check, through Apple App Attest, Android Play Integrity or reCAPTCHA Enterprise. It checks that each request comes from my authentic app on an untampered device. Once I enforce it in the Firebase console, requests without a valid attestation are rejected. Replay protection makes each App Check token single-use. Google is candid that App Check "prevents some, but not all, abuse vectors," so it is one guardrail, not the whole defense.

Second, I lower the Firebase AI Logic per-user rate limit. Its default is 100 requests per minute. That is far more than one person needs, and Google recommends tuning it to the app. A tighter limit slows how fast one client can spend my project quota. It does not stop many clients at once.

PART 03

Reference architecture and trade-offs

Figure 2 follows one request through my router, step by step. The deadline comes from my code in section 05: 1,500 ms. The other times come from the introduction and section 02. A warm answer takes under 40 ms, and an eviction costs a 2.5 second freeze.

The device gets the first try

Step 1: a request goes to the on-device model first. The router gives it until the 1.5 second deadline. The cloud model waits. 0 1.5 s deadline 2.5 s On-device on my phone Cloud Firebase AI Logic time to answer every request starts here waits

Warm weights answer in under 40 ms

Step 2: the weights are still in memory, so the on-device model answers in under 40 ms. The cloud is never called. 0 1.5 s deadline 2.5 s On-device on my phone Cloud Firebase AI Logic warm: <40 ms never called

If I only wait, eviction freezes 2.5 s

Step 3: the OS evicted the weights, so they reload from flash for 2.5 seconds, past the 1.5 second deadline. If the router only waited on the device, the user would see a 2.5 second freeze while the cloud sat idle. 0 1.5 s deadline 2.5 s On-device on my phone Cloud Firebase AI Logic evicted weights reload from flash 2.5 s freeze if I only wait: idle

At the deadline, the router calls the cloud

Step 4: at the 1.5 second deadline the router sends the request to the cloud model through Firebase AI Logic, and the cloud answers. The reload goes on in the background. 0 1.5 s deadline 2.5 s On-device on my phone Cloud Firebase AI Logic reload goes on in the background cloud answers deadline missed: escalate
1 of 4
Figure 2. One request and its two cases, on one time line from 0 to 2.5 s. The router asks the on-device model first and gives it until the 1.5 s deadline. In the first case, warm weights answer in under 40 ms. In the second, an eviction means a 2.5 s reload, so the router stops waiting at the deadline and calls the cloud model, and the reload goes on in the background.

Figure 2 uses my code's deadline and the times I saw in my own apps. The lab below uses numbers your browser measures. Start your camera, and the lab times four legs on a single frame. First it grabs the frame into a canvas. Then it encodes the frame as a JPEG. Next, the local model writes a one-line caption, if your browser has one. Last, it uploads the same number of bytes to this server. The upload carries random bytes, not the frame, so camera pixels never leave your device. The lab does not call a hosted model; that leg would add inference time on top of the upload.

Interactive Lab · webcam-latencyOn-device vs cloud: where the milliseconds go

Start your camera, grab one frame, and time each leg yourself: frame grab, JPEG encode, an on-device caption if your browser has a local model, and a same-size upload round trip to this server. Frames never leave the device.

the-hybrid-ai-standard-demoRendered scene
HybridAIRouter On-Device NPU to Firebase AI Logic Failover Proof
05

My TypeScript hybrid routing engine

Here is the production TypeScript router I built, HybridAIRouter. It keeps one on-device NPU session loaded, which prevents VRAM Memory on the graphics or AI chip. Loading a model into it again and again wastes time. thrashing, and gives each request a fresh clone of it. It checks that the local runtime is available. It escalates to Gemini through Firebase AI Logic in three cases. The local model is unavailable. Or it misses its deadline while evicted weights reload. Or the caller skips the device tier with requiresEnterpriseContext. Requests that need the enterprise data itself go to my separate retrieval service:

hybridRouter.ts
TypeScript
import { initializeApp } from 'firebase/app';
import { initializeAppCheck, ReCaptchaEnterpriseProvider } from 'firebase/app-check';
import { getAI, getGenerativeModel, GoogleAIBackend } from 'firebase/ai';
// Prompt API types: npm i -D @types/dom-chromium-ai

// Firebase AI Logic attaches an App Check token to each call; I enforce it in the
// Firebase console (required for AI Logic from November 2, 2026)
const app = initializeApp({ apiKey: 'FIREBASE_WEB_API_KEY', projectId: 'my-production-app', appId: '1:12345:web:abcdef' });
initializeAppCheck(app, {
  provider: new ReCaptchaEnterpriseProvider('RECAPTCHA_SITE_KEY'),
  isTokenAutoRefreshEnabled: true,
});

const ai = getAI(app, {
  backend: new GoogleAIBackend(),
  // Replay protection: one token per request (firebase v12.14+), which also needs
  // replay protection set to Enforced in the Firebase console
  useLimitedUseAppCheckTokens: true,
});
const LOCAL_DEADLINE_MS = 1500; // a warm on-device answer lands well inside this

export interface RoutingResult {
  text: string;
  tier: 'on-device' | 'cloud';
}

export class HybridAIRouter {
  // Cache the create() promise itself, so concurrent first calls share one session
  private baseSession: Promise<LanguageModel> | null = null;
  private cloudModel = getGenerativeModel(ai, { model: 'gemini-3.6-flash' });

  public async execute(prompt: string, requiresEnterpriseContext = false): Promise<RoutingResult> {
    // 1. Attempt On-Device Tier if the task is local and the model is on the device
    if (!requiresEnterpriseContext && 'LanguageModel' in self) {
      // The deadline starts before availability(), so a stalled check counts against it too
      const signal = AbortSignal.timeout(LOCAL_DEADLINE_MS);
      const deadline = new Promise<never>((_, reject) =>
        signal.addEventListener('abort', () => reject(signal.reason)));
      try {
        const text = await Promise.race([this.promptLocal(prompt, signal), deadline]);
        if (text !== null) return { text, tier: 'on-device' };
      } catch (err) {
        // Deadline missed (evicted weights reloading) or session lost: escalate to Firebase AI Logic
        console.warn('On-device tier missed its deadline or failed; escalating to cloud', err);
        if (!signal.aborted) this.baseSession = null; // rebuild a broken session, let a slow one finish loading
      }
    }

    // 2. Cloud Escalation via Firebase AI Logic SDK (App Check token attached automatically)
    const result = await this.cloudModel.generateContent(prompt);
    return { text: result.response.text(), tier: 'cloud' };
  }

  private async promptLocal(prompt: string, signal: AbortSignal): Promise<string | null> {
    if ((await LanguageModel.availability()) !== 'available') return null; // not on the device: go to cloud
    this.baseSession ??= LanguageModel.create();
    // The base session is never prompted, so each clone starts with an empty history
    const session = await (await this.baseSession).clone({ signal });
    try {
      return await session.prompt(prompt, { signal });
    } finally {
      session.destroy(); // frees the clone only; the base session keeps the model loaded
    }
  }
}
06

Architectural decision matrix

I use this empirical decision matrix to audit latency, offline resilience and token spend in each setup:

DimensionPure On-DevicePure CloudThe Hybrid AI Standard
How long the user waits Average LatencyFast, until an eviction. 15 to 40 ms (warm) / 2.5 s freeze (DRAM eviction)Slow on every request. 250 to 600 ms (WAN RTT bound)Fast for the UI. 15 to 40 ms (UI) / 250 ms (Reasoning & RAG)
What each request costs Marginal Token CostFree. $0.00 (Client NPU silicon)Grows with users. Linear with active usersFar less cloud spend. 70 to 80% reduction in cloud token spend
Where the prompt goes Data PrivacyNothing leaves. 100% LocalEvery prompt leaves. Raw prompt egress over wireOnly escalated prompts leave. Local answers stay on device; escalated prompts egress as written
With no network Offline AvailabilityWorks. Fully functional (within memory bounds)Stops. Fails entirelyCore features work. Core UX remains functional; graceful cloud fallback

Industry validation and benchmarks

Recent 2026 systems research confirms that others hit the same physical bottlenecks, on cellular WANs and in mobile operating systems:

First published 22 Aug 2026 · last revised 8 Oct 2026 · 24 revisions

Hand this to your agent

You

Read this essay by Ibrahim Ulukaya, https://ulukaya.dev/posts/the-hybrid-ai-standard, and look at my project. Which features could run on the device under the 4 Pillars of On-Device AI, and where should they escalate to a cloud model behind App Check? Name the file and line for each finding.

Cited by
  1. Instrument: 32-Neuron Fly Reflex Circuit vs. LLM Traffic Intersection

    Pit a 32-neuron LIF spiking circuit driven by 7-ray LIDAR raycasting (0.4ms reflex) against a 450ms cloud LLM agent car in a chaotic 4-way city intersection.

  2. Instrument: Biomorphic Reflex Router (64-Neuron LIF Connectome)

    Wire a 64-neuron Drosophila sensorimotor LIF spiking circuit (1,000 Hz, dt=1.0ms) to a Shannon surprise H(t) gate that escalates to on-device Chrome Built-in AI, with a deterministic local fallback and zero network hops.

  3. Instrument: On-device vs cloud: where the milliseconds go

    Start your camera, grab one frame, and time each leg yourself: frame grab, JPEG encode, an on-device caption if your browser has a local model, and a same-size upload round trip to this server. Frames never leave the device.