Lightning Lesson · Tue 4 August 2026 · 30 min · live

Most of your LLM calls don't need a frontier model.
Tonight we find out which ones.

There's a task in something you shipped that goes to a frontier API because that's the reflex, not because the task required it. A quantized 4-bit model on the machine often owns it outright. Then it walks off a cliff, and the only question that matters is whether you find that edge in a rehearsal or in production.

Ehsan Gazar
Staff Software Engineer · 16 years in production · 500+ mentees
Where we're going · 30 minutes

The run sheet.

0–3The reflexwhy every task ends up at an API
3–8The rulefour axes, and which one is a veto
8–15Run 1 · it winssame task, three tiers, live numbers
15–23Run 2 · it breaksone step deeper, on screen
23–27The surprisewhere the line actually falls
27–30Yours tonightthe repo runs with no network
By the end of tonight

You'll be able to…

1Score a task before you build it: latency, cost, privacy, and dependent reasoning steps, with the last one acting as a veto over the other three.
2Find your own quality cliff: the specific, repeatable way a small model fails, and how to binary-search for the edge on your task shape rather than trusting a benchmark table.
3Run it tonight: a pinned local setup and two graded tasks, so "try it" is a command rather than an afternoon.
0–3 · the lived experience

Classification.
Three fields out of a document.
Tidying up text.

Each one pays a network round trip, a per-request cost, and a privacy surface nobody asked for. Not because the task demanded it. Because reaching for the API is the reflex, and the reflex was formed back when the small models were genuinely useless.

What changed while you weren't looking

A 3B model at 4-bit is 2.4GB on disk and runs on the laptop you already have. The question stopped being "can it" some time ago. It's now "for which tasks, and how would you know".

flowchart TB
  t["A small task
classify · extract · tidy"]:::in --> reflex{{"the reflex"}}:::model reflex --> api["Frontier API call"]:::warn api --> a["Network round trip"]:::bad api --> b["Per-request cost
forever"]:::bad api --> c["Your data on
someone's server"]:::bad a --> q["Was any of that
required by the task?"]:::boom b --> q c --> q classDef in fill:#DCEBFE,stroke:#0D1B33,color:#0D1B33; classDef model fill:#EEE6FF,stroke:#0D1B33,color:#0D1B33; classDef warn fill:#FEF3C7,stroke:#0D1B33,color:#0D1B33; classDef bad fill:#FEE4E2,stroke:#0D1B33,color:#0D1B33; classDef boom fill:#0D1B33,stroke:#0D1B33,color:#fff;
The reframe · the spine of the talk

"Local or cloud" is
the wrong first question.

The right one is how many dependent reasoning steps does this task need. Answer that and you know which capability tier you need. Only then does where it runs become a question, and at that point it's a straightforward trade on cost and privacy.

💡 In plain English

Decide capability first, location second. Almost everyone does it the other way round, picks a deployment story, and then discovers the model can't do the job.

1local 3B, 4-bit2cheap hosted3frontier
3–8 · the takeaway, up front

Four axes.
The fourth one vetoes the other three.

Latency sensitivity, privacy exposure and call volume all push work towards the edge. Dependent reasoning steps pushes it back, and it wins, because no amount of cost pressure buys a small model a capability it doesn't have.

And one hard constraint

"Must work offline" isn't a weight, it's a constraint. No score beats an API you can't reach. If a task must run offline and needs deep reasoning, the honest output is a conflict, not an answer: decompose the task or ship a bigger local model.

$ npm run score -- --latency=high --privacy=high \
                   --volume=1000000 --steps=1

LOCAL   (score 7.0; >=3 local, <=0 frontier)

  · latency high: a round trip you cannot amortise
  · privacy high: data leaving the device is the whole cost
  · 1,000,000 calls: per-request cost dominates at this volume

$ npm run score -- --privacy=high --steps=5 --offline

LOCAL REQUIRED, BUT TOO DEEP. Decompose the task into
single-step pieces, or ship a bigger local model. Do not
paper over it with a better prompt.
The rule is not a substitute for measuring. It stops you building the wrong thing for a week before you measure.
Before the demo · four commands

Two and a half gigabytes,
and one check nobody does.

Pin the tag. qwen2.5 without :3b follows whatever you last pulled, which is how a rehearsed demo becomes a different demo in front of an audience.

The check that saves the argument

ollama ps must say 100% GPU. On CPU you'll see roughly a third of the throughput, conclude local models are hopeless, and be wrong: that's a conclusion about your configuration, not about the model.

$ brew install ollama && ollama serve
$ ollama pull qwen2.5:3b          # 2.4GB, Q4_K_M

$ ollama ps
NAME          SIZE      PROCESSOR    CONTEXT
qwen2.5:3b    2.4 GB    100% GPU     4096

$ ollama run qwen2.5:3b --verbose "One line on tides."
eval rate:  40.57 tokens/s        # ← write yours down
Every judgement later in the talk leans on that last number.
8–15 · live · run 1

A support ticket in.
Five fields out.

Bounded, fixed schema, every answer present verbatim in the input. One step. This is the shape a small model owns, and it's the shape most of your API calls actually are.

Graded, not vibed

The task has an automatic checker. I'm not going to squint at the output and tell you it looks good. It passes or it doesn't, and you'll see which.

$ npm run bench

Pull five fields out of a support ticket
─────────────────────────────────────────────────
local 3B (4-bit)  PASS  all five fields correct
cheap hosted      PASS  all five fields correct
frontier          PASS  all five fields correct

{
  "order_ref":    "NW-88213",
  "amount_gbp":   49,
  "card_last4":   "4471",
  "sentiment":    "negative",
  "wants_refund": true
}
The same task, three tiers, measured

Two things collapse.
One doesn't.

local 3B, 4-bitcheap hostedfrontier
modelqwen2.5:3bgpt-4o-minigpt-4o
latency5856ms1566ms1173ms
tokens/sec11.633.244.3
cost / 1M calls$0$58$960
data leaves the boxnoyesyes
Apple M4, 32GB, Ollama 0.13.5, hosted via OpenRouter, measured 31 July 2026. Yours will differ, and that's the exercise.
The claim I'm here to stop repeating

Cost collapses. Privacy collapses.
Latency collapses.

On this machine local was 3.7× slower than the cheap hosted model on the same task. Their hardware beats your laptop by more than the round trip costs you. That's the normal result on a laptop, and it's the one that gets left out of the pitch.

Local wins on latency when the network is bad, absent, or the payload is large. Not otherwise. Anyone who says local is faster full stop has batched their workload, run on a real GPU, or not measured.
Cost still goes to zero and stays there at any volume, and the ticket still never leaves the machine. Those two carry the argument on their own.
15–23 · live · run 2 · the honest half

Same domain.
Same format.
One step deeper.

Five shipping rules with an explicit precedence order, and one trap: rule 4 overrides rule 2, so the free-shipping waiver doesn't apply to an offshore postcode. The correct answer is £12.00.

What's controlled

Same length, same output contract, same domain, temperature 0. The only variable is the number of dependent steps. If I changed three things at once this would prove nothing.

Rules, ascending precedence:
 1. Base £4.00, or £8.00 over 2kg
 2. Orders over £50.00 ship free
 3. Fragile adds £2.50
 4. Offshore postcodes ALWAYS pay base,
    plus a £4.00 offshore surcharge
 5. Trade accounts get 50% off the surcharge

Order: 3.4kg · £62.00 · not fragile
       IV51 9XR · personal account

                       → £8.00 base  (rule 1)
                       → rule 4 outranks rule 2
                       → + £4.00 surcharge
                       ────────────────────
                         TOTAL: 12.00
How it fails is the whole lesson

It doesn't get confused.
It gets confident.

It finds the first matching rule, applies it, and stops. Clean reasoning, well-formatted, numbered steps, entirely wrong. This is not a prompt problem and a better prompt doesn't fix it.

Why this matters more than the score

A model that failed loudly would be fine, you'd catch it. This one produces exactly the shape of output your parser expects, with a wrong number in it. That ships.

local 3B (4-bit)  FAIL  answered 0.00: took rule 2 and
                        stopped, missing that rule 4
                        outranks it

--- local 3B (4-bit) said ---
1. **Base Shipping**:
   - The weight is 3.4kg, more than 2kg.
   - Therefore base shipping is GBP 8.00.
2. **Order Value and Free Shipping**:
   - The order value is GBP 62.00, over GBP 50.00.
   - Orders over GBP 50.00 are free of charge.
   - This rule overrides the base shipping cost…
Confident, structured, and wrong. Read the last line twice.
23–27 · the result I didn't expect

The cheap hosted model
falls off the same cliff.

local 3B, 4-bit
cheap hosted
frontier
extract
1 step
owns it
owns it
owns it
rules
3 dependent steps
falls over
falls over
owns it
And it fails it the same way: takes the first matching rule and stops. So the line isn't laptop versus cloud. It's capability versus dependent steps.
What that reframes

Decide capability first.
Decide location second.

If a cheap hosted model can do it…
…then a local model can do it too. You're paying per request and exporting your data for nothing. This is the biggest bucket, and it's the one nobody audits.
If it needs the frontier model…
…then running it locally on 3B was never going to work, whatever your budget or your deployment story. Stop trying to prompt your way across the cliff.
The interesting consequence: "we'll save money by moving off the frontier model to a cheaper hosted one" often lands you on the same side of the cliff as free, having paid for the privilege.
One more thing worth knowing

"The frontier model handles it"
is a frequency, not a fact.

gpt-4o got this task right in 5 runs out of 6 at temperature 0. The sixth answered £4.00, with confident reasoning. Temperature 0 stops being a determinism guarantee the moment a request crosses a router that can pick a different backend.

If your acceptance criterion is "the frontier model handles it", measure how often, not whether. A 1-in-6 failure rate is a different engineering problem from a working feature, and it's invisible if you run the prompt once and believe it.
27–30 · yours tonight

Clone it, and it runs
on a dead network.

Every response you saw tonight is checked in as a recording. DEMO_REPLAY=1 and the whole thing runs with nothing called, which is also how I'd survive this venue's wifi dying mid-talk.

Where the real work is

Step 6 in the runbook: add a third task between the two in difficulty and binary-search for the edge. Where it lands is a property of your task shape, not a number you can read off a benchmark table.

$ git clone github.com/ehsangazar/\
             lightning-lesson-on-device-starter
$ npm install
$ DEMO_REPLAY=1 npm run cliff   # no network needed

# then, with your own key and your own model:
$ npm run bench
$ npm run cliff
$ npm run score -- --privacy=high --steps=2
MIT, no runtime dependencies. Read runbook.md first: nine steps, every command written out.
Your turn · 3 minutes · in chat

Name one task in your system
that's on the wrong tier.

Not a task you'd like to move. One you'd bet on. Give me the task and how many dependent steps it needs, and I'll tell you whether I think it survives the cliff.

A strong answer looks like

"We call gpt-4o to classify support tickets into eight categories. One step, the label set is fixed, roughly 40k a month." That's local, obviously and immediately, and it's currently costing real money to export real customer data.

The weak version is "we use AI for our search". That's not a task, it's a product area, and it can't be scored.
The whole thing, in order

Five steps.

1Count the dependent steps before anything else. That decides the capability tier, and nothing else on this list can override it.
2Then score latency, cost and privacy to decide where it runs. Offline is a hard constraint, not a weight.
3Measure on your machine. ollama ps says 100% GPU, and write down your tokens/sec before you trust any latency claim, including mine.
4Find the cliff deliberately, with a grader, before your users find it. A suite where nothing fails has told you nothing.
5Measure how often, not whether. Once is an anecdote, at any tier.
Take it with you

Point it at a real task.
Not a toy one.

Tonight was one decision, made properly, on one small task. Making that decision repeatedly and defensibly across a whole system, where models change under you and "it worked when I tried it" isn't evidence, is an architecture problem. That's what the cohort is built on.

Clone it tonight
github.com/ehsangazar/
lightning-lesson-on-device-starter
read runbook.md first
Production-Ready Systems with LLMs and Agents
October cohort, four weeks. Enrolling now, small and capped.
maven.com/gazar
If your company has a learning budget, this is an expensable line item, and I'm happy to send the blurb. Reply and tell me which task you moved, I read every one.
Ehsan Gazar
Staff Software Engineer · 500+ mentees · me@gazar.dev