3. Phase 1 — Python & Backend Foundation
Estimated time: 2–4 weeks depending on current Python comfort.
3.1 Why This Phase Comes Before Any AI Topic
Intuition. An AI feature is, mechanically, just another API call inside a backend service — one with unusual failure modes (non-deterministic output, high latency, token costs) layered on top of ordinary backend concerns (auth, validation, persistence, concurrency). If the ordinary concerns are shaky, every AI bug becomes indistinguishable from a backend bug, and debugging becomes guesswork.
✅ Exit Criteria for This Phase
Build a non-AI FastAPI service with PostgreSQL, authentication, CRUD, validation, tests, migrations, Docker and documented endpoints. If this layer is weak, AI features will only make debugging harder.
3.2 Python Topics You Must Know
- Core syntax, functions, comprehensions, collections, modules and packages.
- Classes, dataclasses, protocols/interfaces, inheritance only where appropriate.
- Type hints:
list[str], dict[str, Any], Optional, Union, Literal, TypedDict, Generics basics.
- Exceptions, custom exceptions, logging and predictable error boundaries.
- File I/O, JSON, CSV, environment variables and configuration.
- HTTP clients (httpx/requests), timeouts, retries and connection reuse.
async/await, tasks, concurrency vs parallelism, async HTTP and database calls.
- Iterators, generators, decorators and context managers.
- Virtual environments and dependency management (uv/pip/poetry style workflows).
- Pydantic models, validators, settings and JSON Schema.
pytest, fixtures, mocking and integration tests.
Prerequisite Concept — Type Hints and Why They Matter for AI Systems
Definition. A type hint is an annotation that declares the expected type of a variable, parameter, or return value, e.g. def get_user(id: int) -> User. Python does not enforce these at runtime by itself — they are checked by external tools (mypy, pyright) or by libraries like Pydantic that validate at the boundary.
Why it matters here specifically. Later phases ask a language model to return structured output that must match a schema before it can safely reach a database or another service. That schema is, in practice, a Pydantic model built from type hints. Fluency with type hints now is what makes "structured outputs" in Chapter 5 feel like an extension of normal Python rather than a new discipline.
@dataclass
class Invoice:
id: str
total: float
vendor: str
line_items: list["LineItem"]
# Pydantic version (validates at runtime)
class Invoice(BaseModel):
id: str
total: float = Field(gt=0)
vendor: str
line_items: list[LineItem]
Fig 3.1 — A dataclass declares shape; a Pydantic model declares shape and enforces it at runtime. AI-generated data must always pass through the Pydantic form.
Prerequisite Concept — async/await, Concurrency vs Parallelism
Definition. async/await lets a single thread cooperatively switch between many in-flight operations (like waiting on network calls) instead of blocking on each one sequentially.
Concurrency vs parallelism (comparison).
| Aspect | Concurrency | Parallelism |
| Definition | Multiple tasks make progress by interleaving, often on one core | Multiple tasks execute literally at the same instant, on multiple cores |
| Python mechanism | async/await, event loop | Multiprocessing, or C-extension code that releases the GIL |
| Best for | I/O-bound work: network calls, DB queries, model API calls | CPU-bound work: heavy computation, embedding batches on GPU |
Why it matters here specifically. Calling an LLM API is an I/O-bound operation that can take several seconds. A synchronous FastAPI endpoint would block a worker thread for that entire duration; an async endpoint frees the thread to serve other requests while waiting. Every model call, tool call, and retrieval call in this roadmap should be written as an async function.
⚠️ Common Mistake
Mixing blocking calls (e.g. the synchronous requests library or a blocking DB driver) inside an async def route. This blocks the entire event loop, not just the one request — every concurrent user's request stalls. Use httpx.AsyncClient and an async database driver instead.
3.3 FastAPI and Production Backend Topics
- Routing, dependency injection, request/response models and OpenAPI.
- Authentication, authorization and role/permission checks.
- PostgreSQL integration and ORM/query layer; understand raw SQL too.
- Database transactions, migrations and indexes.
- Streaming responses / Server-Sent Events where appropriate.
- Background work: when to use an in-process task vs a real queue.
- Middleware, CORS, rate limiting, structured logging and correlation/request IDs.
- API versioning, idempotency, pagination and robust error formats.
- Dockerize the service and run it with PostgreSQL locally.
Under the Hood — Anatomy of a FastAPI Request
HTTP request
│
▼
Middleware (CORS, logging, request-ID)
│
▼
Route matching
│
▼
Dependency injection (auth, DB session, settings)
│
▼
Pydantic request-model validation
│
▼
Route handler (business logic — may call an AI model here)
│
▼
Pydantic response-model validation
│
▼
HTTP response
Fig 3.2 — Every request passes through validation twice: once coming in, once going out. This is the same pattern later reused for validating AI-generated output.
Prerequisite Concept — Authentication vs Authorization
⚠️ Common Mistake
Do not confuse Authentication with Authorization.
Authentication asks: Who are you?
Authorization asks: What are you allowed to do?
A system can correctly authenticate a user (verify their identity) and still fail if it does not separately authorize the specific action they're requesting. This distinction becomes critical again in Chapter 12 (AI Security), where "the model is authenticated as a valid API caller" does not mean "the model is authorized to run this specific tool."
Prerequisite Concept — Database Transactions and Indexes
Definition. A transaction groups multiple database operations so that they either all succeed (commit) or all fail together (rollback), preserving data consistency. An index is an auxiliary data structure (commonly a B-tree) that lets the database locate matching rows without scanning the entire table.
Why it matters here. Without an index, the database may need to inspect many or all rows to find matching records. As chunk and embedding tables grow into the hundreds of thousands of rows in Phase 4–5, missing indexes on foreign keys and filter columns (tenant ID, document ID) silently turn a fast query into a slow one — this is one of the most common causes of "the RAG API is slow" bug reports.
3.4 Mini-Project: Production API Foundation
FastAPI
-> Authentication / RBAC
-> PostgreSQL
-> SQLAlchemy or SQLModel
-> Alembic migrations
-> Pydantic schemas
-> pytest
-> Docker Compose
Fig 3.3 — The Phase 1 deliverable pipeline. Every later phase adds AI capability on top of this exact stack.
Practical Example
A realistic version of this project: a small task-management API with users, roles (admin/member), projects, and tasks. Endpoints support CRUD with role checks (only admins can delete a project), pagination on list endpoints, and structured error responses (e.g. {"error": "not_found", "detail": "..."}). This project has zero AI in it — that is intentional. It proves the foundation is solid before Chapter 5 adds a model call to one endpoint.
Common Questions
Q: Why not skip straight to building an AI chatbot?
Because most production bugs in AI features turn out to be ordinary backend bugs — a missing await, an unindexed query, a broken auth check — wearing an "AI" costume. Fixing them requires the same skills as fixing any backend bug, so those skills need to be solid first.
Q: Is an ORM required, or is raw SQL acceptable?
Either is fine in production, but you should be comfortable with both. ORMs (SQLAlchemy/SQLModel) speed up common CRUD patterns; raw SQL is often clearer and faster for the complex filtered/vector queries used in Phase 4 onward.
Q: What's the difference between a background task and a real queue?
An in-process background task (e.g. FastAPI's BackgroundTasks) runs in the same process and is lost if the process restarts. A real queue (e.g. Redis-backed) persists jobs, supports retries, and can be processed by separate worker processes — required once ingestion jobs (Chapter 7) can take minutes and must survive restarts.
Interview / Viva Questions
Q: Why should model API calls be made with async functions rather than synchronous ones?
Model calls are I/O-bound and can take seconds; async code frees the worker to handle other requests while waiting, dramatically improving throughput under concurrent load.
Q: What problem do database indexes solve, and what is the trade-off?
They avoid full table scans by letting the database jump directly to matching rows, at the cost of extra storage and slower writes (each index must also be updated on insert/update).
Q: Explain idempotency and why it matters for API design.
An operation is idempotent when performing it multiple times produces the same final state as performing it once. It matters because network retries are common — a client that times out and retries a "create order" request should not create two orders if the request is idempotent (e.g. via an idempotency key).
Q: What is the difference between authentication and authorization?
Authentication verifies identity ("who are you"); authorization determines permitted actions ("what are you allowed to do"). Both are required and neither substitutes for the other.
Q: Why does the roadmap insist on Pydantic models for both requests and responses?
Because validating both directions catches malformed client input and prevents the service from ever returning malformed or unexpected data — the same discipline is reused to validate AI-generated output later.
Chapter Summary
- Phase 1 builds an ordinary, non-AI backend service to establish the foundation everything else depends on.
- Typed Python (type hints + Pydantic) is the same mechanism later used to validate model output.
async/await is essential because model calls are I/O-bound and slow.
- Authentication ≠ authorization — this distinction reappears throughout the security chapter.
- Indexes and transactions matter more, not less, once vector and chunk tables grow large in RAG phases.
- Exit criteria: a working FastAPI + PostgreSQL + auth + tests + Docker service with no AI in it yet.