Every team is wiring an LLM into production, and most of the guidance is written for product managers. Tonight is the engineer's mental model: what's ordinary distributed-systems work, what genuinely breaks, and the few decisions that decide whether it survives real traffic.
The hype is written for the people who buy, not the people who page. So strong engineers wire an LLM into a flow, it demos beautifully, and then it meets real traffic. An agent is not a new kind of magic. It's a service with an unusually weird dependency.
You already know how to build reliable systems around a slow, expensive, flaky dependency. An LLM is exactly that, plus one new twist: it can be confidently wrong. Most of tonight is naming which of your existing instincts still apply, and the few places they don't.
Retrieval-Augmented Generation. Fetch the relevant text at query time and put it in the context, so the model answers from your data instead of its training.
the answer lives in your docs or database, not the model's weights. The default first LLM system, and retrieval quality is the whole game.
flowchart LR
rgQ["User question"]:::in --> rgEMB["Embed query"]:::step
rgEMB --> rgVDB[("Vector store")]:::store
rgVDB --> rgK["Top matches"]:::step
rgQ --> rgP["Prompt plus context"]:::win
rgK --> rgP
rgP --> rgLLM["LLM"]:::model
rgLLM --> rgA["Grounded answer"]:::out
classDef in fill:#DCEBFE,stroke:#0D1B33,color:#0D1B33;
classDef step fill:#ffffff,stroke:#0D1B33,color:#0D1B33;
classDef store fill:#EDE9FE,stroke:#0D1B33,color:#0D1B33;
classDef win fill:#FEF3C7,stroke:#0D1B33,color:#0D1B33;
classDef model fill:#D6F5E3,stroke:#0D1B33,color:#0D1B33;
classDef out fill:#FEE4E2,stroke:#0D1B33,color:#0D1B33;
The model thinks, calls a tool, reads the result, and loops until the task is done. This is the ReAct pattern, and the core of most agents.
the task needs live data or real actions, not just generated text. Always bound the loop with a step cap.
flowchart LR
taU["Task"]:::in --> taM["LLM reasons"]:::model
taM -->|needs data| taT["Call a tool"]:::step
taT --> taO["Observation"]:::win
taO --> taM
taM -->|done| taANS["Answer"]:::out
classDef in fill:#DCEBFE,stroke:#0D1B33,color:#0D1B33;
classDef step fill:#ffffff,stroke:#0D1B33,color:#0D1B33;
classDef win fill:#FEF3C7,stroke:#0D1B33,color:#0D1B33;
classDef model fill:#D6F5E3,stroke:#0D1B33,color:#0D1B33;
classDef out fill:#FEE4E2,stroke:#0D1B33,color:#0D1B33;
A cheap classifier reads the request first, then dispatches it to the handler that fits: a small model, a large model, or a tool.
inputs vary a lot in difficulty or kind. The easiest win on cost and latency without hurting quality.
flowchart LR
rtIN["Request"]:::in --> rtR{"Router"}:::q
rtR -->|simple| rtS["Small model"]:::model
rtR -->|hard| rtL["Large model"]:::model
rtR -->|lookup| rtK["RAG or tool"]:::step
rtS --> rtOUT["Response"]:::out
rtL --> rtOUT
rtK --> rtOUT
classDef in fill:#DCEBFE,stroke:#0D1B33,color:#0D1B33;
classDef q fill:#FEF3C7,stroke:#0D1B33,color:#0D1B33;
classDef step fill:#ffffff,stroke:#0D1B33,color:#0D1B33;
classDef model fill:#D6F5E3,stroke:#0D1B33,color:#0D1B33;
classDef out fill:#FEE4E2,stroke:#0D1B33,color:#0D1B33;
A lead agent splits the job into subtasks, runs specialized workers (often in parallel), and synthesizes their output into one result.
the task is too big or varied for a single prompt. The common multi-agent shape, but reach for it last, the coordination is the cost.
flowchart LR
orO["Orchestrator"]:::model --> orA["Research"]:::step
orO --> orB["Draft"]:::step
orO --> orC["Review"]:::step
orA --> orS["Synthesize"]:::win
orB --> orS
orC --> orS
orS --> orOUT["Result"]:::out
classDef step fill:#ffffff,stroke:#0D1B33,color:#0D1B33;
classDef win fill:#FEF3C7,stroke:#0D1B33,color:#0D1B33;
classDef model fill:#D6F5E3,stroke:#0D1B33,color:#0D1B33;
classDef out fill:#FEE4E2,stroke:#0D1B33,color:#0D1B33;
Strip the word "AI" and look at the shape. A request comes in, you call a downstream that takes seconds and sometimes errors, you handle that, you return. Every tool you already reach for still applies.
| Property | Normal service | LLM in the path |
|---|---|---|
| Same input, same output | yes, deterministic | no, varies every call |
| How it signals failure | throws an error you catch | returns plausible text, no error |
| Cost driver | per request | per token, on every turn |
| Latency | milliseconds | seconds |
| Correctness | testable with assertions | probabilistic, must be evaluated |
The model has no memory between turns. Everything it knows for this request is what you assemble into the window: the system prompt, the history, what you retrieve, and the tools you expose.
The context window is the model's whole desk for this one task. What you put on the desk, and what you sweep off when it gets full, is a design decision, not a default.
flowchart LR stSP["System prompt"]:::in --> stCTX["Context window
all the model sees this turn"]:::win stHIS["Conversation history"]:::in --> stCTX stRET["Retrieved context"]:::in --> stCTX stTOOL["Tool definitions"]:::in --> stCTX stCTX --> stM["LLM"]:::model stM --> stOUT["Response or tool call"]:::out classDef in fill:#DCEBFE,stroke:#0D1B33,color:#0D1B33; classDef win fill:#FEF3C7,stroke:#0D1B33,color:#0D1B33; classDef model fill:#D6F5E3,stroke:#0D1B33,color:#0D1B33; classDef out fill:#FEE4E2,stroke:#0D1B33,color:#0D1B33;
flowchart LR
trA["Model output"]:::out --> trB{"Can code verify it"}:::q
trB -->|yes| trC["Validate vs schema or rules"]:::ok
trC --> trE["Proceed"]:::ok
trB -->|no| trD{"High blast radius"}:::q
trD -->|yes| trF["Human in the loop"]:::warn
trD -->|no| trG["Guardrail and fallback"]:::ok
classDef q fill:#FEF3C7,stroke:#0D1B33,color:#0D1B33;
classDef ok fill:#D6F5E3,stroke:#0D1B33,color:#0D1B33;
classDef warn fill:#FEE4E2,stroke:#0D1B33,color:#0D1B33;
classDef out fill:#DCEBFE,stroke:#0D1B33,color:#0D1B33;
Most of it is skills you already have. The leverage is in four decisions: boundaries, state, failure modes, evaluation, plus treating non-determinism, retries, latency, and token cost as first-class. Name those out loud and you're designing, not guessing.
Production-Ready Systems with LLMs and Agents: An Intensive for Engineers. Six weeks, twelve live sessions (Tue/Thu), five graded projects where you ship real agent systems, not notebooks. Jul 13 to Aug 23.