Sign in

AI Engineer

beginner~25 minorientationcareerai-engineering

What an AI engineer actually does, and how this 30-day path gets you there.

AI Engineer

Overview

"AI engineer" is a new enough title that nobody agrees what it means, which is why it sounds like it needs a research background it doesn't.

Here is the honest version: you are a software engineer whose stack now includes a model. You will not train one. You will call one, and then do the real work — getting the right context in front of it, constraining what comes out, handling the times it is confidently wrong, and keeping it fast and cheap enough to ship. This lesson is about where that role sits, and what the next twenty-nine days actually cover.

Theory

Three roles, often confused. The ML researcher trains models: architectures, loss functions, GPU clusters. The prompt hobbyist types into a chat box and shares screenshots. The AI engineer is neither — you treat a model as a dependency and build the product around it.

Your job is everything between the model and the user. Getting the right context in front of it, constraining what comes out, deciding what happens when it is wrong, and keeping the whole thing fast and affordable. The model is maybe 10% of the system. The other 90% is ordinary engineering applied to an unusual dependency.

Which is why this is reachable. You do not need a PhD or a GPU. You need to be good at the things you are already learning — data, APIs, state, failure handling — and to understand exactly one new thing: your dependency is non-deterministic, and that changes how you test it, retry it, and pay for it.

Visual Diagram

Not your job

The ML researcher's half

  • Training and fine-tuning foundation models
  • Architecture and loss functions
  • GPU clusters and distributed training
  • Publishing benchmark results

Your job

Everything between the model and the user

  • Context: retrieval, chunking, memory
  • Contracts: schemas, validation, evals
  • Product: streaming, latency, cost, failure states
  • Operations: tracing, guardrails, rollback

The model is a dependency you call. The product around it is the engineering.

Where the AI engineer sits: not training the model, not ignoring it either.

Read the diagram as three concentric layers. At the center is the model provider — a black box you send text (and increasingly images, audio, and tool results) to and get text back from. Around that sits the layer this path is mostly about: the application layer, where an AI engineer works — prompt templates, an SDK like the Vercel AI SDK, retrieval and tool-calling, evaluation, caching, and observability. The outer layer is the product itself: the UI a user actually touches, auth, the database that stores their data, and the deployment and monitoring that keep it running. A researcher lives in the center circle. A hobbyist pokes at the center circle through someone else's UI. An AI engineer builds and owns the middle and outer rings.

Examples

Concrete things an AI engineer builds, roughly in order of how often they show up on the job:

  • A support-ticket triage system that reads an incoming ticket, classifies its urgency and category with a structured-output call, and routes it — with a fallback to "send to a human" whenever model confidence is low or the output fails validation.
  • A code review assistant that fetches a pull request's diff, sends it to a model with a project-specific system prompt (style guide, common footguns for that codebase), and posts comments — with a human still required to approve merges.
  • A semantic search feature bolted onto an existing product's search bar, using embeddings and a vector index so "cancel my plan" also matches a help article titled "How to end your subscription."
  • An internal agent that can look up a customer's account, check their invoice history, and draft (never auto-send) a refund email, using tool calls to real APIs behind a permission layer.

None of these require training a model. All of them require the software engineering discipline described above: schemas, retries, budgets, tests, and a rollback plan for when the model does something unexpected.

Code

Here is the smallest realistic unit of AI-engineer work: a typed function that wraps a model call, using the Vercel AI SDK (ai), which this platform already uses under src/lib/ai-gateway.server.ts for its own provider abstraction.

import { generateText } from "ai";
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { z } from "zod";

// The provider is swappable — this points at an OpenAI-compatible gateway,
// which is exactly how you avoid hard-coding a single vendor into your app.
const provider = createOpenAICompatible({
  name: "example-gateway",
  baseURL: "https://ai.gateway.lovable.dev/v1",
  headers: { "Lovable-API-Key": process.env.LOVABLE_API_KEY ?? "" },
});

const ticketSchema = z.object({
  category: z.enum(["billing", "bug", "feature-request", "other"]),
  urgent: z.boolean(),
});

type TicketClassification = z.infer<typeof ticketSchema>;

/**
 * Classifies a support ticket. Falls back to a safe default instead of
 * throwing, because a model call is a network call — it can time out,
 * rate-limit, or return malformed JSON, and the caller shouldn't crash.
 */
export async function classifyTicket(body: string): Promise<TicketClassification> {
  try {
    const { text } = await generateText({
      model: provider("gpt-4o-mini"),
      system:
        "Classify the support ticket. Respond with ONLY compact JSON matching " +
        '{ "category": "billing"|"bug"|"feature-request"|"other", "urgent": boolean }. No prose.',
      prompt: body,
    });

    return ticketSchema.parse(JSON.parse(text));
  } catch {
    // Never let a model failure become a user-facing crash.
    return { category: "other", urgent: false };
  }
}

Notice what makes this "AI engineering" rather than "prompting": the schema that validates the model's output before anything downstream trusts it, the try/catch with a safe fallback, and the fact that the provider is injected rather than hard-coded. Swap provider("gpt-4o-mini") for any other model string and the function doesn't change. That swappability is the point — you are not betting your product on one vendor's uptime.

Real Product Example

GitHub Copilot is a clean example because its core mechanism is simple to state and its engineering is almost entirely in the surrounding system, not the model. When you type in an editor, Copilot assembles a prompt from your current file, the cursor position, and snippets pulled from your other open tabs and recently-edited files in the workspace — this context assembly is itself a retrieval problem, not a model problem. That prompt goes to a completions model, which streams back a suggestion. The suggestion is then shown as inline "ghost text" the user can accept with Tab or ignore entirely by continuing to type — a UI decision that makes an imperfect, probabilistic model feel low-risk to use, because rejecting a bad suggestion costs nothing.

The AI-engineering work that makes Copilot usable at scale is almost all outside the model call itself: sub-second latency requirements that force aggressive caching and speculative cancellation (if you keep typing, the in-flight request for the old prefix is abandoned), telemetry on acceptance rate that feeds back into ranking and context-selection heuristics, and a fallback to "show nothing" rather than a slow or wrong completion. Nobody at GitHub is retraining the underlying model between your keystrokes. The product is the system built around it — exactly the layer this lesson is about.

Common Mistakes

Treating prompt quality as the whole product

A great prompt on its own is a demo, not a product. Teams that stop at "we found a prompt that works most of the time" ship something that silently degrades the moment a user phrases things differently, the model provider updates the underlying weights, or traffic scales past what manual spot-checking can catch. The prompt is maybe 20% of the engineering effort; the other 80% is validation, fallback behavior, and monitoring.

Skipping evaluation until something breaks in production

It's tempting to eyeball ten outputs, decide they look good, and ship. Without a persistent evaluation set — even 20 real, labeled examples in a JSON file — you have no way to know if a prompt change, a model upgrade, or a new edge case made things worse until a user complains. Build the eval set before the feature, not after the first incident.

Trusting model output like it's a function return value

A model can return malformed JSON, invent a field that doesn't exist in your schema, or simply refuse. Code that does JSON.parse(response) and hands the result straight to a database write or an email send is one bad generation away from a production incident. Every model output that feeds downstream logic needs schema validation (Zod, for example) and an explicit fallback path.

Ignoring cost and latency until the bill or the complaints arrive

It is easy to prototype against a large, expensive, slow model because it "just works" and never think about it again. In production, token costs and per-request latency compound across every user and every retry. Decide early which calls actually need a frontier model and which can run on something smaller and cheaper — most classification and extraction tasks don't need your most expensive model.

Senior Tips

Senior tip

Version your prompts like code, not like config. A prompt change is a behavior change with no compiler to catch regressions. Keep prompt templates in source control, diff them in code review, and tag which prompt version produced which output in your logs — you will need to bisect a "why did this get worse" incident back to a specific prompt commit eventually.

Senior tip

Build the eval harness before the feature, not after. It feels backwards the first time, but writing 15–20 labeled examples and a scoring function before you write the prompt forces you to define "correct" precisely, and gives you an immediate, objective signal every time you tweak the prompt afterward instead of re-reading outputs by eye.

Senior tip

Cache at the semantic layer, not just the HTTP layer. Two requests that are byte-different but semantically identical ("cancel my account" vs. "I want to cancel my subscription") won't hit a normal cache. For high-volume, low-variance tasks like classification, normalize the input (lowercase, strip whitespace, or even embed and cluster near-duplicates) before deciding whether to make a fresh model call.

Senior tip

Treat the context window as a budget, not a bucket. Models weight information near the start and end of their input more heavily than the middle — a well-documented effect sometimes called "lost in the middle." Put the instructions that matter most (the output format, the constraints) at the very start and reiterate the critical ones at the very end, especially once your prompt includes retrieved documents or conversation history.

Exercises

Exercise

Write down, in your own words, the difference between an ML researcher, a prompt hobbyist, and an AI engineer. Then find one job posting online titled "AI Engineer" and check which of the three it's actually describing — job titles in this field are inconsistently used, and learning to read past the title into the actual responsibilities is a skill on its own.

Exercise

Take the classifyTicket function from the Code section and list three ways it could fail in production that the current code does not handle (for example: the provider returns a 429 rate-limit, or the JSON parses but a field is the wrong type). For each, write one sentence describing how you'd handle it.

Exercise

Pick one AI-powered feature you use regularly (a code assistant, a writing tool, a customer-support chatbot). Write three sentences hypothesizing how it's built, using the "three concentric layers" model from the Visual Diagram section — what's the model layer, what's the application layer, and what's the product layer.

Mini Project

Roadmap audit. Before you touch any code, spend 20 minutes being honest about where you're starting from.

  1. List all 25 topic nodes in this roadmap (visible on the graph page once you're through this lesson).
  2. Score yourself 1–5 on each: 1 means "never touched it," 5 means "I could teach this to someone else."
  3. Identify your three lowest scores. These are the days you should slow down on later — reread the theory section twice, do every exercise, and don't rush to the next lesson until the mini project for that day actually works.
  4. Write one paragraph describing what "done" looks like for you at the end of these 30 days — a specific project, a specific job title, a specific skill. Save it somewhere you'll see it again on Day 30.

This isn't busywork: the single biggest predictor of finishing a self-directed path like this one is having written down, on Day 1, a concrete reason to finish it.

Resources

  • Anthropic — Intro to Claude: the recommended path Anthropic gives new developers for going from zero to a working integration — a good model for how a docs site should onboard an AI engineer.
  • Vercel AI SDK — Introduction: the TypeScript toolkit used throughout this path's code samples for calling models, streaming responses, and building agents across providers.
  • Anthropic Engineering — Building Effective AI Agents: a field report from Anthropic's own applied team on which agent patterns are worth the complexity and which aren't — required reading before Week 4 of this path.