Skip to content

fig. Bai

From Web Developer to AI Engineer: The Skills That Transfer

You don't need a PhD to build AI features. A practical roadmap for Next.js and Python developers: tool calls, retrieval, evals, streaming and cost control.

Written by
Mayank Panchal
Published
Reading time
4 min
Filed under
ai
  • ai
  • python
  • nextjs
  • careers
On this page · 11
  1. What you already know
  2. What is genuinely new
  3. 1. Non-deterministic output
  4. 2. Structured output
  5. 3. Tool use
  6. 4. Retrieval (RAG)
  7. 5. Evaluations
  8. 6. Cost, latency and failure
  9. Streaming to a Next.js UI
  10. A 4-week learning plan
  11. The takeaway

"AI engineer" sounds like a different profession, one that needs research papers and a doctorate. For most jobs, it isn't. Building AI features is mostly software engineering with an unusual, probabilistic component. If you already ship web apps, you own most of the skills.

Here is what transfers, what is new, and a project to learn it with.

What you already know#

Web skill Where it applies in AI work
REST and async APIs Calling model APIs, handling timeouts and retries
Streaming responses (SSE) Streaming tokens to the UI
Databases and search Retrieval over your own data
Caching Avoiding repeat model calls, which are slow and pricey
Auth, rate limits, validation Protecting expensive endpoints
Testing and observability Evaluating and monitoring model behaviour

What is genuinely new#

1. Non-deterministic output#

The same input can return different text. You can't assert equality, so you design around it: constrain outputs, validate them, and expect a failure rate.

2. Structured output#

Don't parse free text. Ask for JSON that matches a schema, then validate it:

Python
from pydantic import BaseModel, ValidationError


class Ticket(BaseModel):
    category: str
    urgency: int  # 1-5
    summary: str


def parse_ticket(raw_json: str) -> Ticket | None:
    try:
        return Ticket.model_validate_json(raw_json)
    except ValidationError:
        return None  # retry, repair, or fall back

If you use FastAPI, you already know Pydantic, which is exactly the tool for this.

3. Tool use#

Models can request calls to functions you define, such as get_order(id). You run the function and return the result. The model never touches your database; your code does, so validation and permissions stay yours. The MCP post covers building a tool server.

4. Retrieval (RAG)#

A model doesn't know your data. Retrieval-augmented generation fetches relevant documents first and puts them in the prompt. The pipeline is ordinary:

  1. Split documents into chunks.
  2. Store them with embeddings in a vector index (Postgres with pgvector is a fine start).
  3. At query time, find the nearest chunks and include them in the prompt.

Most of the quality comes from chunking, ranking and filtering, which are search-engineering problems, not model problems.

5. Evaluations#

This is the biggest mindset change. Without tests you can't tell whether a prompt change helped or hurt. Build a small set of real inputs with expected properties and score each version:

Python
CASES = [
    {"input": "I was charged twice", "expect_category": "billing"},
    {"input": "App crashes on login", "expect_category": "bug"},
]

def run_eval(classify) -> float:
    hits = sum(classify(c["input"]).category == c["expect_category"] for c in CASES)
    return hits / len(CASES)

Twenty good cases beat none. Run them on every change, as you would unit tests.

6. Cost, latency and failure#

Models are slow and priced per token. Learn to:

  • Stream output so the interface feels fast.
  • Cache identical requests.
  • Route easy tasks to a smaller, cheaper model.
  • Set timeouts and a fallback when the provider is down.

Streaming to a Next.js UI#

A common first feature is a chat box that streams. The server returns a stream, and the client reads it as it arrives:

TypeScript
// app/api/chat/route.ts
export async function POST(req: Request) {
  const { prompt } = await req.json()
  const upstream = await fetch(PROVIDER_URL, {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.PROVIDER_KEY}` },
    body: JSON.stringify({ prompt, stream: true }),
  })
  return new Response(upstream.body, {
    headers: { 'Content-Type': 'text/event-stream' },
  })
}

The key stays on the server and the browser only sees the stream. Add authentication and a rate limit before this goes anywhere public, since it spends your money on every call. The rate-limiting post shows how.

A 4-week learning plan#

  1. Week 1: call a model. Build a summariser with structured output and validation.
  2. Week 2: add retrieval. Index a folder of your own notes and answer questions with citations.
  3. Week 3: add tools. Let the model look up data through functions you define, with permission checks.
  4. Week 4: evaluate and harden. Write 20 test cases, add caching, a rate limit, cost logging and error handling.

At the end you have a portfolio piece that shows the skills employers actually ask for: not "I used an API", but "I measured it, bounded its cost, and made it fail safely."

The takeaway#

Becoming an AI engineer is not a leap to a new field. It is applying the engineering habits you already have (validation, testing, caching, observability) to a component that is probabilistic and expensive. The developers who do this well are valuable regardless of which model leads this year.

Written by

Mayank Panchal

Software Developer & Full-Time Learner. Coding on the clock, learning around the clock. Software developer in Bengaluru - Next.js, FastAPI, PostgreSQL, AI-native tooling.

fig. B.1keep reading

fig. B.2contact

Let’s build something sharp.