Stack School LogoStack School
Desktop Recommended. This curriculum contains code blocks and tables best viewed on larger screens.
Official 2026 Curriculum Β· 26 Weeks Β· 9 Phases

The complete, step-by-step roadmap to master AI Engineering.

From Python & HTTP foundations to autonomous multi-agent systems. Grounded in real enterprise AI architecture β€” zero fluff, zero fake projects.

9
Phases
60
Modules
26
Weeks
3
Capstones

Your Progress

Loading...

Mark phases as complete as you finish each module.

Filter Track:

Curriculum Journey12 Items

Modules in this phase

1.1
Generative AI vs AI Agents vs Agentic AI
  • β€”Generative AI β€” single prompt in, content out; no actions, no memory
  • β€”AI Agents β€” an LLM given tools and a goal that acts in a loop
  • β€”Agentic AI β€” autonomous planning, memory, and multi-agent collaboration
  • β€”Where each fits, and why this roadmap builds toward agentic systems
Code Example
python
Generative AI:  "Write me a poem about the ocean" β†’ poem (done, no memory)
AI Agent:       "Find me flights under $500" β†’ LLM calls a flight-search tool,
                 reads results, decides next action, loops until done
Agentic AI:     "Plan and book my entire trip" β†’ multiple agents (research,
                 booking, budget-check) coordinate, remember context across
                 days, and adjust the plan if a flight price changes
End State Outcome

"You can explain the difference between a chatbot, an agent, and an agentic system clearly enough to brief a non-technical founder in two minutes."

1.2
Core Python
  • β€”Variables, data types, and Python's dynamic typing model
  • β€”Control flow β€” conditionals, loops, comprehensions
  • β€”Functions, default/keyword arguments, *args/**kwargs
  • β€”Data structures β€” lists, dicts, sets, tuples, and when to use each
  • β€”Error handling with try/except/finally, custom exceptions
  • β€”Virtual environments and dependency management (venv, pip, requirements.txt)
Code Example
python
def fetch_user_records(user_ids: list[int], *, active_only: bool = True) -> list[dict]:
    records = []
    for uid in user_ids:
        try:
            record = {"id": uid, "active": True}  # placeholder for real lookup
            if active_only and not record["active"]:
                continue
            records.append(record)
        except KeyError as e:
            raise ValueError(f"Malformed record for user {uid}") from e
    return records

# List comprehension instead of a manual loop
active_ids = [r["id"] for r in fetch_user_records([1, 2, 3]) if r["active"]]
End State Outcome

"You can write a clean Python script that reads structured data, transforms it, handles bad input gracefully, and runs in an isolated environment without dependency conflicts."

1.3
Object-Oriented Python
  • β€”Classes, objects, __init__, instance vs class attributes
  • β€”Inheritance, method overriding, and super()
  • β€”Encapsulation and Python's "private by convention" approach
  • β€”Dunder methods (__str__, __repr__, __eq__) and when they matter
  • β€”Composition vs inheritance β€” choosing the right structure
  • β€”Dataclasses for clean, boilerplate-free data models
Code Example
python
from dataclasses import dataclass, field

@dataclass
class Tool:
    name: str
    description: str

@dataclass
class Agent:
    name: str
    tools: list[Tool] = field(default_factory=list)

    def add_tool(self, tool: Tool) -> None:
        self.tools.append(tool)

    def __repr__(self) -> str:
        return f"Agent(name={self.name!r}, tools={[t.name for t in self.tools]})"

search_tool = Tool(name="web_search", description="Searches the web")
agent = Agent(name="ResearchBot")
agent.add_tool(search_tool)
print(agent)  # Agent(name='ResearchBot', tools=['web_search'])
End State Outcome

"You can design a small class hierarchy for a real system (e.g. Agent, Tool, Memory) that's extensible without becoming a tangled mess of inheritance."

1.4
Working with HTTP APIs
  • β€”HTTP fundamentals β€” methods, status codes, headers, request/response cycle
  • β€”Making requests with httpx/requests β€” sync calls, query params, JSON bodies
  • β€”Authentication patterns β€” API keys, Bearer tokens, OAuth basics
  • β€”Handling rate limits, retries, and timeouts gracefully
  • β€”Parsing and validating API responses (intro to pydantic)
  • β€”Reading API documentation efficiently (this is a skill, not just reference-lookup)
Code Example
python
import httpx
from pydantic import BaseModel

class WeatherResponse(BaseModel):
    city: str
    temp_celsius: float

def get_weather(city: str) -> WeatherResponse:
    try:
        response = httpx.get(
            "https://api.example.com/weather",
            params={"city": city},
            headers={"Authorization": "Bearer YOUR_API_KEY"},
            timeout=5.0,
        )
        response.raise_for_status()
        return WeatherResponse(**response.json())
    except httpx.TimeoutException:
        raise RuntimeError("Weather API timed out")
    except httpx.HTTPStatusError as e:
        raise RuntimeError(f"Weather API failed: {e.response.status_code}")
End State Outcome

"You can integrate a third-party API (e.g. an LLM provider) into a script, handle a failed request without crashing, and validate the response shape before using it."

1.5
Async Programming
  • β€”Why async matters for agents β€” concurrent I/O without blocking
  • β€”async/await syntax and the event loop
  • β€”asyncio.gather() for running tasks in parallel
  • β€”Timeouts and cancellation (asyncio.wait_for)
  • β€”Common pitfalls β€” blocking calls inside async functions, forgetting to await
  • β€”When to use async vs threads vs multiprocessing (and when NOT to bother with async at all)
Code Example
python
import asyncio
import httpx

async def call_llm(client: httpx.AsyncClient, provider: str) -> dict:
    try:
        response = await asyncio.wait_for(
            client.post(f"https://api.{provider}.com/generate", json={"prompt": "hi"}),
            timeout=3.0,
        )
        return {"provider": provider, "result": response.json()}
    except asyncio.TimeoutError:
        return {"provider": provider, "result": None, "error": "timeout"}

async def main():
    async with httpx.AsyncClient() as client:
        results = await asyncio.gather(
            call_llm(client, "openai"),
            call_llm(client, "anthropic"),
            call_llm(client, "cohere"),
        )
        return results

# All three providers are called concurrently β€” slow one doesn't block the rest
asyncio.run(main())
End State Outcome

"You can call three different LLM APIs concurrently, enforce a timeout on each, and return whichever results came back without one slow call blocking the rest."

1.6
FastAPI
  • β€”Why FastAPI is the standard for serving agents and AI backends
  • β€”Defining routes, path/query parameters, request bodies
  • β€”Request/response validation with Pydantic models
  • β€”Dependency injection (Depends) for shared logic (auth, DB sessions)
  • β€”Async route handlers and combining them with what you learned in 1.5
  • β€”Auto-generated docs (Swagger/OpenAPI) and why that matters for handoff/testing
  • β€”Basic error handling and custom exception responses
Code Example
python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import asyncio

app = FastAPI()

class PromptRequest(BaseModel):
    prompt: str

@app.post("/ask-all")
async def ask_all_providers(req: PromptRequest):
    try:
        results = await asyncio.wait_for(
            asyncio.gather(
                call_llm("openai", req.prompt),
                call_llm("anthropic", req.prompt),
            ),
            timeout=5.0,
        )
        return {"results": results}
    except asyncio.TimeoutError:
        raise HTTPException(status_code=504, detail="LLM providers timed out")

# Run with: uvicorn main:app --reload
# Auto docs available at /docs
End State Outcome

"You can build a FastAPI endpoint that calls three different LLMs in parallel, times out the slow one, and logs the result without blocking the response."

1.7
Database Connectivity
  • β€”Relational vs non-relational β€” when agents need which
  • β€”Connecting Python to a database (e.g. PostgreSQL) with an async driver
  • β€”Basic ORM usage (e.g. SQLAlchemy / SQLModel) β€” models, sessions, queries
  • β€”CRUD operations from a FastAPI endpoint
  • β€”Connection pooling and why it matters under concurrent load
  • β€”Storing agent state/memory persistently (a preview of what's coming in later phases)
Code Example
python
from sqlmodel import SQLModel, Field, Session, create_engine, select

class AgentLog(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    agent_name: str
    prompt: str
    response: str

engine = create_engine("postgresql://user:pass@localhost/agentdb")
SQLModel.metadata.create_all(engine)

def save_log(agent_name: str, prompt: str, response: str):
    with Session(engine) as session:
        log = AgentLog(agent_name=agent_name, prompt=prompt, response=response)
        session.add(log)
        session.commit()

def get_logs_for_agent(agent_name: str) -> list[AgentLog]:
    with Session(engine) as session:
        return session.exec(
            select(AgentLog).where(AgentLog.agent_name == agent_name)
        ).all()
End State Outcome

"You can build an endpoint that saves an agent's interaction history to a database asynchronously, without blocking other requests."

Open Interactive Lesson

Modules in this phase

2.1
What an LLM actually is
  • β€”Trained on a fixed snapshot
  • β€”Knowledge cutoff dates and what they imply
  • β€”Probabilistic generation, not retrieval
  • β€”Why the same prompt gives different outputs
End State Outcome

"You can explain to a non-technical PM why ChatGPT made up a fact, and tell a hiring panel which model to pick for which job β€” backed by benchmarks, not vibes."

2.2
How an LLM thinks
2.3
Reasoning models vs base models
2.4
Reading model evals & benchmarks
2.5
How to choose the models for your task
Open Interactive Lesson

Modules in this phase

3.1
UI vs API - Calling LLM's via API
  • β€”Why the chat UI and the API give different output β€” hidden system prompts & silent tools
  • β€”Calling LLMs via the OpenAI & Anthropic SDKs
  • β€”Message format β€” system / user / assistant turns
  • β€”Streaming responses
  • β€”Structured output β€” JSON mode, tool-call schemas, XML tags
End State Outcome

"You can take a flaky prompt that works "sometimes" and systematically make it reliable β€” and cut its cost in half with caching while you're at it."

3.2
Prompt Engineering
3.3
Context Engineering
3.4
Applied prompt patterns
3.5
Advanced reasoning techniques
3.6
Prompt management & cost in production
Open Interactive Lesson

Modules in this phase

4.1
Why RAG exists
  • β€”LLMs can't see your private data
  • β€”The brain-in-a-windowless-room reaches its limit
  • β€”Use cases: internal docs, company policies, recent data
End State Outcome

"You can build a RAG system, measure why it's wrong, and fix it with data instead of vibes."

4.2
Embeddings
4.3
Document ingestion pipeline
4.4
Chunking strategies
4.5
Chunk enrichment
4.6
Vector databases
4.7
Hybrid retrieval & next-gen retrievers
4.8
Graph-augmented RAG
4.9
RAG evaluation β€” the part most courses skip

Tech Stack

DoclingPineconeNeo4jECS FargateDynamoDBS3Bedrock embeddingsLangSmith

System Architecture Steps

  • 01PDF ingestion: Docling layout detection β†’ semantic chunking β†’ PII redaction β†’ entity extraction β†’ embeddings β†’ Pinecone + Neo4j
  • 02Distributed async workers on ECS Fargate processing thousands of PDFs concurrently
  • 03DynamoDB state tracking per document (queued / processing / done / failed)
  • 04Hybrid retrieval (vector + BM25 + graph) with reranking
  • 05Evaluation harness with golden dataset, Precision@k / Recall@k / RAG Triad
  • 06FastAPI Q&A endpoint with citation-backed answers

Hiring Proof Statement

"You can build production RAG, not a Streamlit demo."

Modules in this phase

5.1
Function calling / tool use
  • β€”Tool schemas (JSON Schema, Pydantic)
  • β€”How the LLM decides which tool to call
  • β€”Parsing tool-call responses
  • β€”Handling tool errors gracefully
End State Outcome

"You can build a single agent that searches the web, reads internal docs, queries a DB, and emails you a summary β€” and stops if it tries to do something dumb."

5.2
Tool design principles
5.3
MCP β€” Model Context Protocol
5.4
The ReAct pattern
5.5
LangChain agents
5.6
Human in the loop
5.7
Tool security
5.8
Computer use & app SDKs β€” agents with eyes and a mouse

Modules in this phase

6.1
The context window as working memory
  • β€”Why agents "forget" mid-conversation
  • β€”Token budgeting per section
  • β€”The lost-in-the-middle problem
  • β€”Recency bias
End State Outcome

"You can explain why your agent forgot what you said three turns ago, and fix it with the right memory layer instead of throwing more tokens at it."

6.2
Context structure β€” SYSTEM / CONTEXT / USER separation
6.3
Short-term memory β€” session history
6.4
Semantic caching
6.5
Episodic memory
6.6
Context compression
6.7
Long-term memory

Modules in this phase

7.1
When to go multi-agent (and when not to)
  • β€”Single-agent-with-tools beats multi-agent for ~80% of tasks
  • β€”Multi-agent earns its weight when steps need different prompts, tools, or specialised reasoning
  • β€”The Tableauβ†’QuickSight conversion case as a worked example
End State Outcome

"You can design a multi-step agent workflow on a whiteboard, build it in LangGraph, and debug it when one node loops infinitely."

7.2
LangGraph fundamentals
7.3
Common patterns
7.4
Agent-as-tool β€” the lightweight alternative
7.5
State management
7.6
A2A β€” Agent-to-Agent Protocol
7.7
Frameworks compared (briefly)
7.8
Debugging multi-agent systems

Tech Stack

LangChainLangGraphLangSmithAgentCoreRDS PostgreSQLFastAPIStreamlitBedrock

System Architecture Steps

  • 01Multi-agent: Planner β†’ SQL Writer β†’ Validator β†’ Executor β†’ Explainer
  • 02Schema-aware context injection per query (only relevant tables sent to writer)
  • 03LangGraph orchestration with conditional routing and retry loops
  • 04Read-only DB enforcement, query timeout, max-row caps
  • 05Streamlit frontend, FastAPI backend, RDS PostgreSQL with realistic data
  • 06Benchmarked on a golden NLQ test set, target 85%+ accuracy

Hiring Proof Statement

"You can orchestrate multiple specialised agents safely against real production data."

Modules in this phase

8.1
Three-layer guardrail architecture
  • β€”Input Guardrails (gateway, <1ms, deterministic): prompt-injection regex, PII redaction, out-of-domain rejection, toxic filter β€” code-based, never LLM
  • β€”Output Guardrails (LLM-judge OK): faithfulness, contradiction check, medical/legal disclaimers when confidence < threshold, hard-fail to safe fallback
  • β€”Action Guardrails (inside tools, pure functions): max retries, max tool calls per request, query validation, read-only DB, top_k caps
End State Outcome

"You can put a number on how often your agent fails, and ship it anyway with confidence."

8.2
AWS Bedrock Guardrails
8.3
LLMOps β€” observability
8.4
LLMOps β€” evaluation in production

Modules in this phase

9.1
Storage & data
  • β€”S3 β€” durable object storage, document lakes
  • β€”RDS PostgreSQL β€” managed relational DB for agent state
  • β€”DynamoDB β€” KV state for ingestion pipelines
End State Outcome

"You can take any system you built in earlier phases, dockerize it, deploy to ECS Fargate behind API Gateway, manage secrets, stream tokens to a chat UI, load-test it, and watch the cost dashboard move only when it should."

9.2
Compute
9.3
Networking & access
9.4
AI-specific services (and other clouds)
9.5
Deployment & realtime delivery
9.6
Cost & capacity control

Tech Stack

LangChainLangGraphNeo4j + CypherPineconeBedrock + AgentCore + LambdaS3LangSmithMLflow

System Architecture Steps

  • 01Real ClinicalTrials.gov dataset ingestion (or your domain equivalent)
  • 02Hybrid knowledge layer: Pinecone for unstructured PDFs + Neo4j for trial-drug-condition relationships
  • 03Multi-hop relationship queries ("what other trials used drug X for condition Y?")
  • 04Full three-layer guardrails β€” disclaimer auto-injection, contradiction checks, action limits
  • 05Evidence-backed answers β€” every claim cites the source chunk
  • 06Deployed on AWS with monitoring, regression tests in CI, semantic cache, cost dashboard

Hiring Proof Statement

"You can ship an agent into a regulated domain without it killing anyone (or your career)."

🎯 Scope Guardrails

Out of scope (and why)

What this curriculum explicitly excludes. Every topic below is valid β€” but inserting them into the core 26 weeks creates distraction without improving your hiring outcomes.

01

Fine-tuning foundation models

Deferred
β›” Why it's deferred

RAG, prompting, and tool use solve 95% of business problems faster, cheaper, and with no infra overhead. Fine-tuning earns its weight only when you have a narrow domain, lots of clean labelled data, and prompting has hit a wall β€” which almost never happens before you've shipped your first agent.

🎯 Recommended alternative

Start with LoRA + a 7B open model (Llama, Mistral, Qwen) on a single A10/L4 once you have a real motivating use case.

02

Voice agents

Deferred
β›” Why it's deferred

A whole sub-discipline β€” STT, TTS, turn-taking, latency budgets, barge-in. Worth its own track, not a side note. You can graft it on top of any agent you build in this roadmap.

🎯 Recommended alternative

OpenAI Realtime API, Deepgram + ElevenLabs + LiveKit, or pipecat β€” pick after you've shipped one text agent.

03

ML fundamentals

Deferred
β›” Why it's deferred

Lovely to know. Not required to be an excellent agent engineer in 2026. The Karpathy series is there when you're curious β€” don't let it block you from shipping.

🎯 Recommended alternative

Andrej Karpathy's "Neural Networks: Zero to Hero" + the "Let's build GPT" video, on weekends.

04

Frontend frameworks

Deferred
β›” Why it's deferred

You need enough to ship a Streamlit or basic chat UI for capstones. Beyond that, partner with a frontend engineer or a design system. Don't get lost in framework wars.

🎯 Recommended alternative

Streamlit for internal tools, Vercel AI SDK + Next.js when you need a real product UI.

πŸš€ Career Execution Plan

After the roadmap: From Code to Offers

You built three production systems. Here is how to package them so recruiters reach out to you directly.

1
Step 01

Portfolio: Three repos, three READMEs

The capstones are your portfolio. For each one: a clean GitHub repo with a README that explains the problem, the architecture, the trade-offs, and the eval numbers; a 90-second Loom walking through it; one screenshot of the trace UI showing it actually working.

2
Step 02

LinkedIn: Headline that says what you can ship

Don't write "AI Engineer" in your headline β€” write "AI Engineer Β· production RAG, multi-agent systems, AWS Bedrock + LangGraph Β· shipping in regulated domains." Specific gets interviews. Generic gets ignored.

3
Step 03

60-second pitch

"I spent six months building three production-grade AI systems end-to-end: a distributed RAG pipeline that ingests thousands of PDFs, a multi-agent NL→SQL system with read-only enforcement, and a clinical-trials knowledge base with three-layer guardrails. I can show you the traces, the eval numbers, and the cost dashboard for any of them." That's the whole pitch. Numbers and artefacts beat adjectives.

4
Step 04

Keep learning: What to read once you're shipping

Anthropic's "Building effective agents" essay, the Latent Space podcast, the LangChain blog, Eugene Yan's writing on production ML, and the original papers when something keeps confusing you. Skim, don't drown.

πŸŽ“

"The journey ends where the real work begins."

26 Weeksβ€’9 Phasesβ€’60 Modulesβ€’3 Capstones