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.
Your Progress
Loading...Mark phases as complete as you finish each module.
Curriculum Journey12 Items
Modules in this phase
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
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"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."
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
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"]]"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."
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
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'])"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."
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
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}")"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."
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
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())"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."
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
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"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."
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
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()"You can build an endpoint that saves an agent's interaction history to a database asynchronously, without blocking other requests."
Modules in this phase
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
"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."
How an LLM thinks
Reasoning models vs base models
Reading model evals & benchmarks
How to choose the models for your task
Modules in this phase
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
"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."
Prompt Engineering
Context Engineering
Applied prompt patterns
Advanced reasoning techniques
Prompt management & cost in production
Modules in this phase
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
"You can build a RAG system, measure why it's wrong, and fix it with data instead of vibes."
Embeddings
Document ingestion pipeline
Chunking strategies
Chunk enrichment
Vector databases
Hybrid retrieval & next-gen retrievers
Graph-augmented RAG
RAG evaluation β the part most courses skip
Tech Stack
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
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
"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."
Tool design principles
MCP β Model Context Protocol
The ReAct pattern
LangChain agents
Human in the loop
Tool security
Computer use & app SDKs β agents with eyes and a mouse
Modules in this phase
The context window as working memory
- βWhy agents "forget" mid-conversation
- βToken budgeting per section
- βThe lost-in-the-middle problem
- βRecency bias
"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."
Context structure β SYSTEM / CONTEXT / USER separation
Short-term memory β session history
Semantic caching
Episodic memory
Context compression
Long-term memory
Modules in this phase
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
"You can design a multi-step agent workflow on a whiteboard, build it in LangGraph, and debug it when one node loops infinitely."
LangGraph fundamentals
Common patterns
Agent-as-tool β the lightweight alternative
State management
A2A β Agent-to-Agent Protocol
Frameworks compared (briefly)
Debugging multi-agent systems
Tech Stack
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
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
"You can put a number on how often your agent fails, and ship it anyway with confidence."
AWS Bedrock Guardrails
LLMOps β observability
LLMOps β evaluation in production
Modules in this phase
Storage & data
- βS3 β durable object storage, document lakes
- βRDS PostgreSQL β managed relational DB for agent state
- βDynamoDB β KV state for ingestion pipelines
"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."
Compute
Networking & access
AI-specific services (and other clouds)
Deployment & realtime delivery
Cost & capacity control
Tech Stack
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)."
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.
Fine-tuning foundation models
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.
Start with LoRA + a 7B open model (Llama, Mistral, Qwen) on a single A10/L4 once you have a real motivating use case.
Voice agents
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.
OpenAI Realtime API, Deepgram + ElevenLabs + LiveKit, or pipecat β pick after you've shipped one text agent.
ML fundamentals
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.
Andrej Karpathy's "Neural Networks: Zero to Hero" + the "Let's build GPT" video, on weekends.
Frontend frameworks
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.
Streamlit for internal tools, Vercel AI SDK + Next.js when you need a real product UI.
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.
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.
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.
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.
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."