Take any model call and make it production-grade: track its cost and latency against a budget, cache the repeats, survive failure with a fallback ladder, and make side effects safe to retry.
What you'll build
One call(request) that knows what it is allowed to spend, answers instantly on a repeat, degrades instead of throwing when the model misbehaves, and never double-charges on a retry.
Like a good waiter: remembers your usual so you do not reorder, has a backup if the kitchen is slammed, and never puts the same meal on your bill twice, even if he has to ask the chef again.
The shape
flowchart TB
A["Big model"] -- "timeout / error" --> B["Small model"]
B -- "still failing" --> C["Cached / retrieved answer"]
C -- "no cache" --> D["Deterministic default"]
D -- "nothing works" --> E["Honest try-again + log"]
classDef ok fill:#D6F5E3,stroke:#1F2937,color:#0E1726;
classDef warn fill:#FEF3C7,stroke:#1F2937,color:#0E1726;
class A,B ok; class D,E warn;
Starter code
import OpenAI from "openai";
const client = new OpenAI();
const ladder = ["gpt-4o-mini", "gpt-4o"]; // ladder: cheap first, then capable
async function call(request, budgetUsd = 0.02, timeoutMs = 4000) {
const key = semanticKey(request);
const hit = cache.get(key); // semantic cache: skip the model entirely
if (hit) return hit;
let spent = 0.0;
for (const model of ladder) {
try {
const out = await client.chat.completions.create(
{ model, messages: [{ role: "user", content: request }] },
{ timeout: timeoutMs },
);
spent += costOf(out);
if (isValid(out) && spent <= budgetUsd) {
cache.set(key, out);
return { answer: out, spent, path: model };
}
} catch (err) { // timeout or rate limit: step down a rung
continue;
}
}
return fallback(request); // cached, default, or honest try-again
}
async function doRefund(orderId, idemKey) { // side effects: safe to retry
if (ledger.seen(idemKey)) { // idempotency: run once, ever
return ledger.result(idemKey);
}
const result = await payments.refund(orderId);
ledger.record(idemKey, result);
return result;
}
Do this, in order
You're done when
Go further
Wrapping up
Hand in your call() wrapper, your budget numbers, and the proof that a retry does not double-charge. This becomes your Project 2 (Cost & Latency Budget + Runbook).
The idempotency step is the one that saves a career. Have every student prove it with a counter: force three retries on the refund path and show the ledger records exactly one. That single demo prevents a whole class of production incidents.
Make them actually kill the primary model (bad key, or a forced exception) and watch the ladder degrade. The lesson lands when a "dead" system still answers, users forgive slightly-less-smart, they do not forgive a spinner. Ask everyone to post their p95 and cache-hit rate.