The four triggers that justify an LLM surface
Opens the AI unit with the decision framework for when a feature genuinely needs a language model versus a cheaper deterministic query, form, or pipeline.
A stakeholder drops a line into the sprint: “Can we add AI to this?” Everyone nods, because it feels like the kind of thing a 2026 product is supposed to have. The junior reflex is to open a branch and start wiring a chat box onto the dashboard.
That nod skipped the only question that matters. “Add AI” is not a feature; it is a mood. A model is the most expensive, slowest, least predictable component you can bolt onto a product, and most of the time the thing the stakeholder actually wants is already a Server Component and a SQL query that runs in two milliseconds and never hallucinates. The experienced reflex is to ask, before writing any code, whether this surface is actually shaped like something a probabilistic model should handle, or whether you are about to pay tokens and latency for a worse version of a feature you could ship deterministically today.
The rest of these AI lessons all rest on one claim: most 2026 SaaS still ships without an LLM-backed surface, and that is the correct call. This lesson is not a warm-up before the “real” AI lessons; it is the filter that decides whether you need them at all. You might finish it, run your product through the four triggers below, find that it hits none of them, and walk away. That is a successful outcome, not a failed one. What you leave with is a filter: four product shapes that justify reaching for a model, the look-alikes that don’t, and one sentence to carry through all of it: the model never owns data; tools own data, the model orchestrates language. Hold onto that sentence, because it does a surprising amount of work.
What makes a surface LLM-shaped
Section titled “What makes a surface LLM-shaped”Before the four concrete shapes, here is the single principle they all share, because one rule with four examples is far easier to carry than four unrelated rules to memorize.
A large language model earns its place on a surface only when that surface needs one of three things that ordinary code structurally cannot produce: open-ended natural-language input that no form could have captured in advance, natural-language output that only prose can carry, or orchestration across steps whose shape changes depending on what the input turns out to be. If a surface needs none of those, if the work is “take an id, fetch the matching rows, render them,” then it is a query and a component, and nothing more. Reaching for a model there is like hiring a novelist to read you a phone number.
The distinction is sharp rather than a matter of taste, because a model is probabilistic . Ask it the same question twice and you may get two different answers. That property is exactly what makes it powerful for language you couldn’t anticipate, and exactly what disqualifies it for anything that needs to be exact and repeatable. A WHERE status = 'overdue' clause returns the same rows every time; a model asked “which ones are overdue” might miss one. So the question underneath every trigger below is the same: is natural language genuinely essential here, or are you dressing up a lookup? The four triggers are that question, made concrete enough to answer.
The four triggers that cross the threshold
Section titled “The four triggers that cross the threshold”There are four shapes, and for the purposes of this course only four, where a model is the right tool. Each one leads with the same move: first why the deterministic path structurally fails, and only then the example. If you can’t articulate why a form, a query, or a fixed pipeline can’t do the job, you haven’t found a trigger yet.
Open-ended Q&A grounded in app data
Section titled “Open-ended Q&A grounded in app data”Picture a user staring at an invoices dashboard who wants to know which clients are overdue and trending worse than last quarter. The answer is entirely a function of structured data you already have. But notice what the deterministic path can’t do at either end. Server-side SQL can’t read the question, because there is no form field for “and trending worse than last quarter,” and you cannot pre-build a form for every question a human might phrase. And a search box, even a great one, can’t compose the answer: it returns rows, not a sentence that says “three clients slipped, and Acme is your biggest exposure.”
That two-sided gap, language coming in and prose going out, is the signature of this trigger. So what is the model’s actual job? It reads the question, decides it needs real numbers, and calls a tool, say a getInvoiceStats(...) function you wrote, to fetch them from Postgres. Then it writes the prose around those numbers. The model never invents a balance or a due date; it can’t, because it doesn’t have your data. The tool owns the data, and the model orchestrates the language around it. That is the lesson’s one sentence again, and it resolves almost every hard case here. This is the exact surface the course builds end to end a few chapters from now, invoice Q&A grounded in the org’s own data through a tool; for now we are only naming why it qualifies.
Generation of structured artifacts from prompts
Section titled “Generation of structured artifacts from prompts”A user types “monthly retainer, 40 hours at our standard rate, net 30” and expects a properly filled-in invoice line item to appear, with description, quantity, unit price, and payment terms each in its typed slot. Why can’t a form do this? It can, when the input space is small. But the moment the input is genuinely free text that maps to a typed structure in too many ways to enumerate with dropdowns, you are no longer building a form; you are building a parser for natural language, and that is the model’s job.
The model’s task here is narrow and worth stating precisely: map free text onto a known schema. It does not write the row to your database. Your deterministic code does that, after validating it, exactly as it would validate any untrusted input. (The AI SDK has a primitive built precisely for “free text in, typed object out,” which we’ll meet in the next chapter.) The deciding test is simple: if a dropdown and a number field would have captured the input, build the form. The model earns its place only when the input space is too varied for one.
Classification or extraction over unstructured text
Section titled “Classification or extraction over unstructured text”Consider inbound support emails that need routing by intent, uploaded contract PDFs whose key terms must be pulled into structured metadata, or free-form notes a salesperson scribbled after a call and now need tagging. The common thread is that the input is genuinely messy human text that no regex was ever going to parse reliably, so the model is the only reasonable tool for reading it.
Here is the shape that makes this trigger recognizable on sight: the input is messy and open-ended, but the output is small and tidy, an enum, a short object, or a handful of tags. Ordinary deterministic code then takes that clean output and does the rest: routes the ticket, files the metadata, updates the record. The model is a translator sitting at the edge of your system, turning chaos into structure so the rest of your code never has to look at the chaos. That asymmetry of wild input and structured output is the tell. Keep it in mind, because in the next section it draws a line that trips up almost everyone.
Agentic workflows the user couldn’t run by hand
Section titled “Agentic workflows the user couldn’t run by hand”Consider this request: “Find every customer with an overdue invoice, draft a reminder for each one in a tone that matches how we’ve talked to them before, and queue the drafts for a human to approve.” Each individual step is deterministic: query the overdue customers, fetch prior correspondence, generate a draft, write to a queue. What is not fixed is the path through them, namely how many customers there are, what each one’s history looks like, and which ones need a gentle nudge versus a firmer one. The model’s job is the orchestration, deciding what to do next based on what the previous step actually returned.
Now the qualifier that matters more than anything else in this trigger, because it is precisely where juniors over-reach: this counts only when the steps genuinely vary by input. If you always run step A, then step B, then step C, in that order, every time, regardless of the data, that is not an agent. That is a pipeline, and a pipeline is just a function you write. Wrapping a fixed sequence of known steps in a model pays a decision-maker to make a decision that was never in question. (The loop that lets a model choose its next step is the subject of a later chapter; here we only name when you’d want one.)
Step back and notice that all four are the same idea wearing different clothes. Each one needs either open-ended language, coming in or going out or both, or orchestration whose shape depends on the input. That is the one thing a form, a query, and a fixed pipeline structurally cannot give you, and it is the only thing that justifies the cost of a model. Everything else has a cheaper, faster, more reliable default, which is the entire point of the next section.
What does not cross the bar
Section titled “What does not cross the bar”This section carries as much weight as the last one. The single most expensive beginner mistake with AI in 2026 is reaching for a model on a workload that a query or a form already solves. When you do, the bill is real and the result is worse: the user waits longer, you pay per token, and the answer is occasionally wrong where the deterministic version was always right. A look-alike that fails the filter doesn’t just cost more; it makes the product worse.
Here are the five most common impostors, each paired with the cheaper default you already know how to build.
Smart search over your own data. Someone wants “AI-powered search” across the invoices, the customers, the notes. Almost always what they actually want is good search, and Postgres already ships it: full-text search and pg_trgm trigram similarity together cover the overwhelming majority of the workload, at zero per-query cost and zero hallucination risk. You met Postgres search earlier in the course, and it is the right tool here, not a model.
Form auto-fill from one typed field. A user types a country code and the currency fills in; they pick a customer and the billing address populates. This is an onChange handler and a deterministic lookup, either a map or a single query. It is faster than any model, costs nothing per keystroke, and is incapable of guessing wrong. A model here is pure downside.
“Make the UI feel modern.” Sometimes “add AI” decodes to “the demo would look impressive with a chat box in it.” That is a pitch-deck decision, not a product decision. The user pays the latency, you pay the tokens, and the surface they actually use is worse than the buttons and filters it replaced. If you can’t name which of the four triggers it hits, it hits none of them.
Categorizing a fixed, knowable enum. Sorting transactions into one of five accounting buckets that were defined at design time and won’t change is a switch statement, a set of rules, or at most a tiny purpose-trained classifier. A general-purpose language model is wildly overpowered for choosing among five known options.
This last one sits right next to the extraction trigger from the previous section, and the line between them is the subtlest cut in this lesson, so let me draw it explicitly. Ask one question: are the categories knowable at design time? If you can write down the complete list of buckets today and a rule could plausibly assign them, it’s deterministic, so use the switch or the classifier. If the input is genuinely open-ended text that you have to actually understand to make sense of, like the messy support email or the freeform contract, then it’s the extraction trigger and the model earns its place. The two tasks look alike; the deciding question is whether you knew the answers in advance.
Replacing existing search and filter with chat. This is the most seductive trap. “What if, instead of filters, users just ask the dashboard what they want?” Chat is a poor primary affordance for scanning a list: it is slower, less precise, and it hides the structure users rely on. The move is never to replace the filters with chat; it is to add chat as one more surface alongside the affordances people already know how to use. Take away the filter bar and you’ve shipped a regression with a token bill attached.
Sort the workload
Section titled “Sort the workload”Now make the cut yourself. Below are real-looking feature requests. For each one, decide whether a model genuinely earns its weight or whether a deterministic default does the job better and cheaper. Drag each into its bucket, then check.
For each request, decide whether the surface is genuinely LLM-shaped, or whether a deterministic default is the better tool. Drag each item into the bucket it belongs to, then press Check.
The two worth pausing on are the contract extraction and the tax-category sort. Both look like “categorize or pull structure out of a document,” yet one is a model and the other is a switch. The contract is open-ended text you have to read; the tax categories were knowable at design time. That is the line.
The four-trigger funnel
Section titled “The four-trigger funnel”You now have the triggers and the anti-triggers as separate lists. What turns them into a skill is the order you ask the questions in, because an experienced engineer reaches for the cheap, deterministic default at every branch and only lets the model survive when natural language is genuinely unavoidable. Walk the funnel below. At each question, pick the honest answer for a feature you’re considering; the leaf you land on is the verdict.
The model reads the question, calls a tool for the real numbers, and writes the prose around them: a chat surface backed by tool calling. The tool owns the data; the model orchestrates the language.
Map free text onto a typed schema, then validate and write it with ordinary deterministic code. It earns its weight only when a form couldn’t have captured the input.
Wild input, tidy structured output. Downstream code consumes the clean result and does the rest. The model is a translator sitting at the edge of the system.
The model decides each next step from what the last step actually returned. The orchestration is the model’s job, but only because the path through the steps genuinely varies by input.
Backend data processing is a function you write. There is no language and no user, so there is no trigger to hit.
A lookup or filter over your own data: zero per-query cost, never hallucinates. Add chat alongside it if you must, never instead of it.
Structured input, structured result, no language in between. A form and a query are faster, cheaper, and always exact.
The same known steps every time is a function, not an agent. A model here pays a decision-maker to make a decision that was never in question.
Notice the shape of the walk: every branch has an exit to a cheaper default, and the four model verdicts sit at the end of the longest paths. That is not an accident of layout; it is the experienced engineer’s posture turned into a procedure. The model is where you arrive when nothing cheaper will carry the language, never where you start.
Why the AI SDK is the canonical Next.js integration
Section titled “Why the AI SDK is the canonical Next.js integration”Suppose a feature genuinely lands one of the four triggers. Now, and only now, does the question become what you reach for. For a Next.js team in 2026, the answer is the Vercel AI SDK , and it’s worth understanding the three reasons it’s the default rather than treating it as a given.
It owns the React 19 streaming model. When a model generates a long answer, you don’t want the user staring at a spinner until the last word arrives; you want the text to appear as it’s produced. The SDK streams those pieces and partial objects in a way that composes with Suspense and Server Components by design, rather than as something you bolt on afterward. (How that streaming actually works on the page is the next chapter.)
Provider abstraction is first-class. The model behind a feature sits behind a single identifier. Swapping from one provider to another is, in the best case, a one-line change rather than a rewrite of every call site. This is the durability argument, and it matters more than it sounds, because the provider landscape is not settling down. A major model from a different company lands almost every month, and the SDK is the layer that keeps your integration from breaking every time one does. (The mechanics of that swap are a later lesson in this chapter.)
The surface is tight. There are five primitives an experienced engineer actually reaches for: streamText, generateText, generateObject, streamObject, and the useChat / useCompletion hooks. That’s the whole working vocabulary, with no sprawl and no forty-concept framework to learn before you can ship one feature. You’re seeing the names now only so the shape of what’s coming is familiar; none of them are taught here.
Two alternatives exist, and since you will see them elsewhere it’s worth knowing why the course doesn’t pick them. Calling a provider’s SDK directly, meaning OpenAI’s or Anthropic’s own client, works, but it welds every call site to that one vendor and you lose the unified streaming shape; the only real reason to reach for it is a brand-new provider feature the AI SDK hasn’t surfaced yet, which is rare. Hosting LangChain on the server brings a much heavier programming model of chains, agents, and retrievers, plus a streaming primitive that fights the App Router rather than flowing with it; it earns its place for research-style multi-agent orchestration off the user-request path, not for the user-facing surfaces this course is about. For a Next.js SaaS, the AI SDK is the pick.
The version that matters: v5, not v4
Section titled “The version that matters: v5, not v4”A short but high-value warning, because it will save you from confidently shipping broken code. The moment you start building, you will search for help, and a large share of the tutorials, blog posts, and answers you find, including anything a model generates from older training data, will hand you AI SDK v4 shapes. The SDK had a significant redesign in v5 (stable since mid-2025), and the old shapes aren’t just stylistically dated; they’re wrong by construction against the current SDK. You don’t need to know the v5 APIs yet to protect yourself. You just need to recognize the v4 fingerprints on sight.
Here are the tells. Match each outdated v4 shape to what replaced it in v5. The point is not to memorize the APIs, which is the next chapter’s job, but to make a v4-flavored tutorial set off the alarm immediately.
Each left item is an outdated v4 shape you'll meet in old tutorials. Match it to the v5 replacement that signals current code. Click an item on the left, then its match on the right. Press Check when done.
.content string on each messageparts array on each UIMessageappend and reload to send and retrysendMessage and regenerateuseStatemaxSteps on the client to bound an agent loopstopWhen with stepCountIs(n)The rule is blunt: any tutorial, or any prompt you hand a model, that emits these v4 shapes is wrong by construction for this stack. The actual mechanics of parts, sendMessage, and stopWhen land in the next two chapters; right now this is purely a way to calibrate your search results.
The architectural shape: server calls, client streams
Section titled “The architectural shape: server calls, client streams”There is one architectural rule to hold in your head before you write a single line of AI code, and the good news is you already know it. Every LLM call runs on the server. The Client Component subscribes to the resulting stream through the SDK’s hooks. The provider key never, under any circumstances, reaches the browser.
If that sounds familiar, it should: it is the same server-seam rule you already learned for authedAction and authedRoute earlier in the course. Secrets and privileged work live behind a server boundary, and the client only ever talks to that boundary, never to the resource directly. An LLM call is just one more privileged operation behind that seam. This is not a new rule; it’s the rule you know, applied to a new kind of work.
What makes the AI SDK pleasant here is that it enforces this by shape. The React hooks are built to talk to a server endpoint, not to a provider directly, so there is nowhere to put a key on the client even if you wanted to. The secure architecture is the path of least resistance, not extra discipline you have to remember to apply. The diagram below is the whole trust boundary, and the key lives on exactly one box.
flowchart LR client["<b>Client Component</b><br/><code>useChat</code><br/><i>no key — runs in the browser</i>"] server["<b>Server route handler</b><br/>auth + provider key<br/>🔑 <i>key lives only here</i>"] provider["<b>Provider</b><br/><i>OpenAI · Anthropic · …</i>"] client -- "request" --> server server -- "model call" --> provider server -. "streamed response" .-> client class client browser class server seam class provider external classDef browser fill:#dbeafe,stroke:#1d4ed8,color:#111,stroke-width:2px classDef seam fill:#bbf7d0,stroke:#15803d,color:#111,stroke-width:3px classDef external fill:#1f2937,stroke:#94a3b8,color:#f8fafc,stroke-width:2px
Two things are worth naming as forward pointers, since they both live inside that middle box. The cost guards that keep a public surface from burning your budget are the next lesson, and the provider configuration that makes the model a one-line swap is the lesson after. Both sit inside the server seam you just drew.
Landing this surface is an architectural decision
Section titled “Landing this surface is an architectural decision”One more habit before anyone touches a keyboard. Earlier in the course you learned the three-test rule for when a decision deserves a written record, an ADR : it touches multiple parts of the system, reasonable alternatives exist, and reversing it costs more than a single PR.
An LLM-backed surface passes all three easily. It touches multiple files: a route handler, a schema, a client component, environment config, and very likely billing. Reasonable alternatives genuinely exist: ship no model at all, pick a different provider, or lean on a hosted service. And reversal is expensive, because by the time the surface is live it has dragged in a rate limiter, a per-user quota, audit-log events, and possibly Stripe metering, none of which unwind in one commit. So when this shape lands in a real codebase, write the ADR. Capture which trigger justified it, which alternatives you weighed, and what reversing it would cost the team that inherits it.
To be clear about scope: the worked surface this course builds later doesn’t ship a fresh ADR as a deliverable, because the habit attaches to the decision, not to this course’s project. When this lands in your codebase, that’s the moment to write one.
Pushing back, and the failure modes
Section titled “Pushing back, and the failure modes”The thread running through this entire lesson is a posture, not a checklist, so let me close on how an experienced engineer holds the line when the pressure to “add AI” arrives, because it always does.
When a stakeholder asks “can we add AI?”, remember that they’ve handed you a how, not a what. The LLM is a means; the question you owe them back is what user problem it’s meant to solve, and then whether that problem hits one of the four triggers. If it doesn’t, the professional answer is to offer the cheaper deterministic surface that solves it better, not a chat box built to satisfy the literal request.
Two more traps catch teams under deadline pressure. The first is “we’ll worry about cost later,” which is wrong the instant the surface is public. Every authenticated user can now spend your money in tokens at the speed of their keyboard, so abuse is not a someday problem but a day-one one, and the next lesson is entirely about bounding it. The second is picking a provider’s SDK directly because some model team’s launch blog used it in their example. That welds your call site to one vendor on the strength of a marketing post, and the AI SDK exists precisely to keep that decision easy to reverse.
Is the trigger real?
Section titled “Is the trigger real?”A final self-check. Each question below is a feature request dressed up the way they actually arrive: some hit a trigger, some are impostors wearing a trigger’s clothes, and one hits nothing at all and should ship no model. Reason it through; the deciding question is always which of the four shapes, if any, this really is.
A teammate pitches it as the headline AI feature: a single box where a user types anything — a half-remembered company name, a typo’d contact, a partial domain — and the matching customer surfaces instantly. The ticket title is literally “AI customer search.” Before you size it, what shape is this actually?
pg_trgm similarity ranks the closest matches and ships today with no per-query bill.Support is drowning in long inbound emails. The ask: as each one arrives, automatically produce a two-line gist plus a short list of suggested next actions, so an agent grasps the ticket without reading the whole thread. Which of the four triggers, if any, does this land?
Sales leadership wants the dashboard to “feel like AI.” Concretely: take the exact revenue and overdue-invoice figures the page already renders and, on load, restate each KPI as a friendly sentence — “Revenue is up 4% this month” instead of a bare number. No new question is being asked; the inputs are the same metrics as today. Which trigger justifies a model here?
If those felt like judgment calls rather than recall, that’s the point: the filter is only useful when it transfers to inputs you’ve never seen phrased exactly this way.