Something changed between 2023 and 2026, and naming it precisely is the first real skill in AI engineering. Generating a chunk of boilerplate, writing a one-off script to call an API, turning a plain-English request into a regular expression, summarising a long document — a language model now does all of that for almost nothing. The barrier to producing code and text collapsed.
What did not collapse is everything that turns a model into a feature you can ship to paying users. Deciding whether a model should be involved at all, feeding it the right context, bounding what it costs, checking whether its answer is actually correct — that work is still engineering, and it is still where the salary sits. This lesson draws that line cleanly.
flowchart TD
A["a request arrives"] --> Q{"fixed format,<br/>rule-verifiable?"}
Q --> D["deterministic code<br/>cheap, exact, fast"]
Q --> M["model plus full system<br/>where judgement is needed"]
style D fill:#166534,color:#fff
style M fill:#6d28d9,color:#fff
What the model commoditised
Be specific. A model is now the fastest way to draft a function you can describe in one sentence, to translate a curl command into your language's HTTP client, or to produce a first pass of a regex for a fiddly format. These are generation tasks: open-ended output, no single right answer, where a fluent guess beats ten minutes of typing. The model replaced the typing, not the thinking.
What it did not
Judgment did not get commoditised. Should this endpoint call a model at all, or would a twenty-line deterministic function do the job better, faster, and a thousand times cheaper? That is not a prompt — it is a design decision, and the wrong answer turns a cheap feature into an expensive, flaky one. The instinct to ask that question, every time, is what hiring managers screen for.
function classifyTask(t) {
let score = 0; // higher = stronger case for deterministic code
if (t.fixedFormat) score += 2; // e.g. pull a date out of a known layout
if (t.ruleCanVerify) score += 2; // a regex or lookup can check the answer
if (t.outputIsBounded) score += 1; // yes/no, a number, an enum
if (t.needsJudgement) score -= 3; // open-ended, correctness needs a human eye
return score >= 2 ? "deterministic" : "model";
}
console.log(classifyTask({ fixedFormat: true, ruleCanVerify: true, outputIsBounded: true, needsJudgement: false }));
console.log(classifyTask({ fixedFormat: false, ruleCanVerify: false, outputIsBounded: false, needsJudgement: true }));
A model is a component, not a product
The mental model that survives is this: a language model is one component inside a larger system, the way a database or a regex engine is a component. You would never ship a product that was only a database — you ship the read and write logic, the schema, the migrations, the connection pool. The same is true here. The model is the part that produces fluent output; the system around it is the part that makes that output safe, cheap, and correct enough to rely on.
That surrounding system is mostly ordinary software — branches, loops, lookups, tests — and ordinary software is exactly what a model is worst at replacing, because it has to be right every single time.
flowchart LR T["extract a postcode<br/>from a fixed format"] --> R["regex: microseconds,<br/>free, always correct"] T --> L["model: far more cost,<br/>far more latency, sometimes wrong"] style R fill:#166534,color:#fff style L fill:#b91c1c,color:#fff
The classic trap: throw an LLM at it
Every team that adopts a model hits the same trap. A task arrives — extract the postcode from an address, validate an email, sort a list, pull a total out of a receipt — and someone routes it to the model because the model is new and impressive. The result feels magical for a week. Then the bill arrives, the latency creeps up, and one request in fifty returns something the model invented instead of extracted.
The fix is the instinct this lesson trains. If a task has a fixed format and a rule can verify correctness, do not send it to a model. A regex extracts a postcode in microseconds for free and gets it right every time. The model costs many times more, takes far longer, and is occasionally wrong. Reach for the cheaper tool on purpose.
The three things that still pay
If generation is commoditised, what is left to be good at? Three things, and they are the spine of this course. First, systems — the deterministic pipeline around the model: a router that decides what kind of request this is, a retriever that fetches the context the model needs, a guard that checks the answer before a user sees it. Second, evaluation — a way to measure whether a change made the feature better or worse, because you cannot improve what you cannot score. Third, cost and latency control — knowing, before you ship, what one request will cost and how long it will take. None of these are prompts; all of them are code you can test.
function classifyTask(t) {
let score = 0;
if (t.fixedFormat) score += 2;
if (t.ruleCanVerify) score += 2;
if (t.outputIsBounded) score += 1;
if (t.needsJudgement) score -= 3;
return score >= 2 ? "deterministic" : "model";
}
const tasks = [
{ name: "extract postcode", fixedFormat: true, ruleCanVerify: true, outputIsBounded: true, needsJudgement: false },
{ name: "draft a marketing email", fixedFormat: false, ruleCanVerify: false, outputIsBounded: false, needsJudgement: true }
];
tasks.forEach((t) => console.log(t.name + " -> " + classifyTask(t)));
flowchart TD P["what still pays in 2026"] --> S["systems: the deterministic<br/>pipeline around the model"] P --> E["evaluation: score every<br/>change before it ships"] P --> C["cost and latency: budget<br/>a request before you build it"] style P fill:#3776ab,color:#fff
function costEstimate(route) {
// latency in ms, cost in micro-dollars per call (illustrative, fixed numbers)
if (route === "regex") return { latencyMs: 1, microDollars: 0 };
if (route === "model") return { latencyMs: 900, microDollars: 500 };
return { latencyMs: 0, microDollars: 0 };
}
const regex = costEstimate("regex");
const model = costEstimate("model");
console.log("latency penalty: " + (model.latencyMs / regex.latencyMs) + "x");
console.log("a task a model never earned, routed to one anyway");
What does this print? The classifier adds 2 for a fixed format and 2 again when a rule can verify the answer.
function classifyTask(t) {
let score = 0;
if (t.fixedFormat) score += 2;
if (t.ruleCanVerify) score += 2;
if (t.outputIsBounded) score += 1;
if (t.needsJudgement) score -= 3;
return score >= 2 ? "deterministic" : "model";
}
console.log(classifyTask({ fixedFormat: true, ruleCanVerify: true, outputIsBounded: false, needsJudgement: false }));
fixedFormat adds 2 and ruleCanVerify adds another 2.
4 reaches the threshold of 2, so the result is deterministic.
Write classifyTask(t) that scores a task and returns "deterministic" when the score is 2 or higher, otherwise "model". Add 2 for fixedFormat, 2 for ruleCanVerify, 1 for outputIsBounded, and subtract 3 for needsJudgement.
function classifyTask(t) {
// score the task, then return "deterministic" or "model"
}
Start a score at 0 and add or subtract for each signal.
Return "deterministic" when score >= 2, else "model".
function classifyTask(t) {
let score = 0;
if (t.fixedFormat) score += 2;
if (t.ruleCanVerify) score += 2;
if (t.outputIsBounded) score += 1;
if (t.needsJudgement) score -= 3;
return score >= 2 ? "deterministic" : "model";
}
This classifier has the judgement signal backwards: it adds 3 when a task needs human judgement, so open-ended tasks wrongly score as deterministic. Judgement should push the task towards the model. Change the one operator that fixes it.
function classifyTask(t) {
let score = 0;
if (t.fixedFormat) score += 2;
if (t.ruleCanVerify) score += 2;
if (t.outputIsBounded) score += 1;
if (t.needsJudgement) score += 3;
return score >= 2 ? "deterministic" : "model";
}
needsJudgement should lower the score, not raise it.
Change the + before the 3 into a -.
function classifyTask(t) {
let score = 0;
if (t.fixedFormat) score += 2;
if (t.ruleCanVerify) score += 2;
if (t.outputIsBounded) score += 1;
if (t.needsJudgement) score -= 3;
return score >= 2 ? "deterministic" : "model";
}
Write nonModelTasks(tasks) that returns an array of the names of every task classifyTask calls "deterministic" — the work you would NOT send to a model. classifyTask is provided for you; use it, do not rewrite it.
function classifyTask(t) {
let score = 0;
if (t.fixedFormat) score += 2;
if (t.ruleCanVerify) score += 2;
if (t.outputIsBounded) score += 1;
if (t.needsJudgement) score -= 3;
return score >= 2 ? "deterministic" : "model";
}
function nonModelTasks(tasks) {
// return the names of the tasks that are "deterministic"
}
Filter to the tasks classifyTask calls deterministic, then map each to its name.
Use the .length and [index] of the result to check it without nested quotes.
function classifyTask(t) {
let score = 0;
if (t.fixedFormat) score += 2;
if (t.ruleCanVerify) score += 2;
if (t.outputIsBounded) score += 1;
if (t.needsJudgement) score -= 3;
return score >= 2 ? "deterministic" : "model";
}
function nonModelTasks(tasks) {
return tasks.filter((t) => classifyTask(t) === "deterministic").map((t) => t.name);
}
Which task should you NOT route to a language model — a deterministic tool does it better?
A postcode has a fixed format and a regex can verify the answer, so a deterministic extractor is cheaper, faster, and perfectly reliable. The other three are open-ended generation where a model earns its place.
Recap
- A model commoditised generation — drafting code, one-off scripts, first-pass regexes, summaries. It replaced the typing, not the thinking.
- It did not commoditise judgment: deciding whether to call a model at all, and building the system that makes its output safe, cheap, and correct.
- A model is a component inside a system, not the system itself. Most of that system is ordinary, testable software.
- The classic trap is throwing an LLM at a deterministic task — paying many times more for something a regex does perfectly.
- The durable skills are systems, evaluation, and cost control — the focus of the rest of this module.
Next you will map the parts of that surrounding system and see that most of an AI product is code you already know how to write and test.