Loading lesson...
Loading lesson...
The Foundations stage builds the vocabulary and the working environment that everything later in the course assumes. It separates three nested fields that public coverage routinely treats as one, places the current generation of systems on a seventy-year trajectory so that their reliability can be judged rather than guessed at, names the limits that are properties of how these systems work rather than defects awaiting a patch, explains the architecture that made them capable and the addition that turns a text predictor into something that acts, and then puts a terminal, an isolated project and a first traceable API call under your hands.
One argument runs through all five modules. A language model produces probable text, not verified fact, and every useful property an agent appears to have is supplied by the system around the model. It gets current information because somebody gave it a tool. It behaves consistently because somebody set a sampling parameter rather than accepting a default. It remembers the conversation because the application resends the history on every call. It stops because somebody wrote a stop condition. Two of the cases in this stage, an airline held to what its chatbot told a customer and a legal filing built on citations that did not exist, are the same failure twice: fluent output was treated as retrieved fact, and nothing in the system checked it.
The sections below follow the stage's teaching order, so the page can be read straight through to rebuild the stage in your head, or used to reach one concept quickly. Each section links back to its module for the full treatment, including the worked commands, the interactive tools and the dated detail that this summary deliberately leaves with the source.
Artificial intelligence is the field concerned with building systems that perform tasks normally requiring human judgement, and the word normally carries most of the weight in that sentence. The boundary moves. Once we understand exactly how a system reaches a result, we tend to stop calling the result intelligent, which is why chess, image recognition and translation each stopped counting as artificial intelligence soon after they were solved. This drift, sometimes called the AI effect, is the reason public expectation consistently runs ahead of what deployed systems actually do, and it is the first thing to correct in any conversation about what a proposed system will be able to handle.
The three terms are concentric rings rather than synonyms. The outer ring, artificial intelligence, covers any technique that produces aspects of intelligent behaviour, including the rule-based systems of the 1970s that contained no learning whatsoever. The middle ring, machine learning, covers systems that infer patterns from examples instead of following rules somebody wrote by hand: rather than encoding the instruction that an email mentioning a prize is spam, the system is shown thousands of examples and derives the pattern itself. The inner ring, deep learning, uses neural networks of many layers that learn hierarchical representations, so that pixels become edges, edges become shapes and shapes become objects. What changed the economics of that inner ring was hardware, when graphics processing units made training large networks affordable.
The distinction is practical rather than academic, because each ring has a different failure profile. A hand-written rule is auditable and brittle: you can read exactly why it fired, and it collapses the moment reality steps outside the case somebody anticipated. A learned model tolerates messy, unanticipated input and cannot tell you why it produced a particular answer. Module 1 quotes John McCarthy, who coined the term, defining the goal as making intelligent machines while deliberately declining to claim that those machines think as people do. Keeping that framing, useful goal-directed behaviour rather than replicated consciousness, is what stops a design conversation drifting into speculation.
Capability rises with the data each class learns from, but no row in that stack says whether an output is usable. The four NIST AI RMF 1.0 gates below settle that: measure error, check deployment context, manage residual risk, document limits. A good error score is not clearance.
Capability comes from pattern recognition over data. Usability comes from verification, not from the model. NIST AI RMF 1.0 names verification as the deployment gate.
Modern systems did not appear suddenly. They are the product of decades of research, two extended funding collapses known as AI winters, and a series of empirical breakthroughs that arrived when more computing power and more data made previously impractical methods work. Knowing the trajectory is not trivia. It is how you calibrate a claim: a capability that has held under pressure for twenty years deserves more trust than one demonstrated last quarter, and a field that has twice overpromised into a funding collapse is one whose current promises deserve the same scrutiny.
Module 1 sets out the anchor points. In 1950 Turing replaced the unanswerable question of whether machines can think with an observable test, judging a machine on whether its written responses could be told apart from a person's. Between roughly 1974 and 1980 the first AI winter arrived when rule-based systems proved brittle outside the narrow topics they were built for, and funding fell sharply in both the United Kingdom and the United States. In 1997 IBM's Deep Blue defeated the world chess champion using search and evaluation functions rather than machine learning, which demonstrated that superhuman capability in a well-defined domain does not require learning at all. In 2012 a deep convolutional network called AlexNet, from the University of Toronto, won the ImageNet challenge by a margin that made deep learning the dominant approach to perception. In 2017 the transformer architecture was published, and scaling that architecture on very large text corpora produced the broadly capable language systems that this course builds agents on.
The methodological lesson from the 1950 paper outlasts the specific test it proposed. Replacing a philosophical question with a measurable performance criterion is what made the field empirical, and it is still the right instinct when somebody asks whether an agent is good enough. Do not argue about whether the agent understands the task. Define what a correct outcome looks like, define how you would observe it, and measure that. The module carries the specific figures for the AlexNet margin and for later adoption; treat any such number as belonging to the date it was measured on.
Three ideas get conflated in coverage and must be kept apart. Narrow artificial intelligence is built and trained for a specific task, can be superhuman at that task and is useless outside it. Every system in commercial use today is narrow: the model that scores a card transaction for fraud, the assistant that sets a timer, the recommender that picks what to show next. Artificial general intelligence, a hypothetical system that could apply reasoning across domains without task-specific training, does not exist, and researchers disagree sharply about whether it is decades away or impossible in principle. Superintelligence, exceeding human capability across all domains, is a further hypothetical and a topic of speculation rather than an engineering specification. A conversational system that answers well across many subjects can feel general; the breadth comes from the breadth of text it was trained on, not from general intelligence.
Four limits follow from how these systems work, and treating them as bugs awaiting a patch is the most expensive mistake available at this stage. The first is fabrication: a model asked about a topic thinly represented in its training data fills the gap with confident, plausible, invented detail, because it produces statistically likely continuations and holds no concept of truth or falsehood. The second is the absence of causal reasoning: a correlation in the training data is represented as a correlation, so a model that has seen ice cream sales and drowning incidents rise together in summer carries that association and not the fact that neither causes the other. The third is run to run variation: the same prompt can produce different output on different calls, which matters wherever a downstream system parses the result. The fourth is that there is no persistent memory by default, so a conversation begins with nothing carried over unless the application stores it and sends it back.
Each limit maps to a system-level control that the rest of the course builds. Fabrication is answered by retrieval and by validating an assertion against a source before acting on it. Absent causal reasoning is answered by keeping arithmetic, lookups and anything with a right answer in a tool rather than in the weights. Variation is answered by a sampling parameter set deliberately and by an output format the application can validate and reject. Absent memory is answered by explicit state management in your code. None of the four is fixed by choosing a different model, and a design that assumes a future model will fix them is a design with no control at all.
A transformer processes a sequence by computing a relationship between every element and every other element at once. The attention mechanism is best understood as a learned relevance function: for each position, it weights how much every other position should influence the output there. That is what earlier left to right processing struggled with, because information separated by many words had to survive every intervening step to matter. Module 2 uses a sentence in which the word bank appears twice with different senses, and the mechanism learns that one occurrence should attend to depositing and a cheque while the other attends to a river. A model does not read characters or words but tokens, sub-word units for which a rule of thumb of a few characters each is good enough for planning, and the context window that bounds a call is measured in tokens. This matters for agents specifically, because the system prompt, every message in the conversation and every tool result all consume the same budget.
A plain model receives text and returns text. It cannot check today's weather, query a database, send a message or run code, and everything it knows was fixed when its training data was fixed. Tool use, also called function calling, changes that by giving the model a set of tool descriptions in a structured schema. When the model judges that a tool would help, it emits a structured request naming the tool and its arguments instead of a conversational reply. The application code executes the tool and feeds the result back into the context. The boundary is the point most often misread: the model never touches the network or the database itself, so input validation, error handling and consistent result structure are ordinary software engineering obligations that sit on your side of the line. Tool use does not make a model cleverer. It routes the work that statistical text prediction is unsuited to, such as arithmetic and lookups, to systems that are reliable at it.
ReAct, introduced by Yao and colleagues, interleaves reasoning traces with actions, so the model writes out a thought, chooses an action, observes the result and repeats. The point is not that the visible thought is proof of anything; a fluent rationale can accompany a wrong answer. The point is traceability: when the agent fails you can see whether it misread the goal, chose the wrong tool or misinterpreted an observation, instead of guessing. That produces the loop every agent runs regardless of framework. Perceive reads the current context, the system prompt, the history, the tool descriptions and any memory. Think reasons about the goal and the state. Act either calls a tool or produces a final answer. Observe injects the tool result back into the context, and the loop returns to Think.
The design decision beginners miss is where the loop ends. Without a stop condition an agent can circle through reasoning it has already tried, exhaust the context window and accumulate cost with nothing to show. Define a success condition, a failure condition, a maximum step count and a fallback behaviour before deployment rather than after the first incident. The stage's opening case makes the whole chain concrete: an airline chatbot told a bereaved customer about a bereavement discount route that the published policy did not offer, the tribunal held the airline responsible for what its chatbot had said, and the chatbot had no tool with which to read the live policy. Nothing in that system was broken. Something was missing.
The runtime band on the right owns steps, budget and approvals, and the left column closes on a card that owns no exit at all, so an agent whose runtime does not hold the stop condition has nothing that can end the loop.
An agent is an LLM plus a runtime that owns state, tools, stop conditions, and the final output type. ReAct v3 (2023) and the OpenAI Agents guide both teach this distinction.
A terminal is a text interface to the operating system, usually bash or zsh on macOS and Linux and PowerShell on Windows. Agent frameworks are installed and run from it, language runtimes are managed from it and credentials are supplied to processes through it, so fluency here is not optional and the module deliberately covers only what agent work requires. Four commands carry most daily navigation: pwd prints the current working directory, ls lists what is there, ls -la adds hidden dot files such as .env and .gitignore along with permissions, and clear resets the screen. cd moves you, with cd .. going up one level and cd ~ returning home from anywhere. mkdir creates a directory and touch creates an empty file, which together are how every project starts.
Two things on the command line delete or expose work permanently, and both deserve a deliberate habit. rm removes files with no recycle bin, and rm -rf removes a directory and everything inside it without asking, where -r means recursive and -f means force. Being in the right directory is necessary and not sufficient, because the path you pass may be relative or absolute and a mistyped one is still obeyed. Print the path first and read it before you run the command. The second is credentials. An environment variable is a named value in the operating system environment that any process in that session can read, set with export for the current session only and made permanent by adding the line to a shell profile such as ~/.zshrc or ~/.bashrc. PATH is a colon-separated list of directories searched in order for an executable, which is exactly why a machine with several Python installations runs the one you did not expect, and echo $PATH is how you find out.
Secrets belong in a .env file at the project root holding simple key and value pairs, and that file must be added to .gitignore before any credential is written into it, not afterwards. The python-dotenv README makes the same point in its own words, advising that .env be added to .gitignore especially where it holds secrets, and load_dotenv reads each pair into the process environment. Once a key has been committed it exists in the repository history and must be treated as compromised and rotated, whatever you do next. Finally, learn to read failure. Python tracebacks read from the bottom upwards: the last line names the error type and cause, and the lines above are the call stack that led there. An authentication error about an invalid key is a credentials problem, and ModuleNotFoundError means the package is not installed in the environment that is actually running, which is the single most common beginner error and the reason the next module exists.
Every command has a location, an action, a target and observable output, so pwd, cd and ls each leave a confirmation the next one depends on. Running a script at the fourth step without those three means acting on a directory you have only assumed you are in.
Every shell command has a location, an action, a target, and observable output. POSIX.1-2024 names this contract; GNU Coreutils implements it.
A Python virtual environment is an isolated installation for one project, with its own interpreter reference and its own installed packages, so that changing one project cannot break another. The official documentation states that venv creates lightweight virtual environments each with an independent set of packages in their own site directories, built on top of an existing base Python and isolated from the base environment's packages by default. Create one with python3 -m venv .venv inside the project folder, activate it with source .venv/bin/activate on macOS and Linux or the Scripts activation script on Windows, and confirm with which python that the interpreter now resolves inside .venv. Activation works by prepending the environment's binary directory to PATH, which is the same PATH mechanism from the previous module doing ordinary work. Record what you installed with pip freeze into requirements.txt and commit that file; never commit the .venv directory, which is large, platform-specific and rebuildable in seconds.
Node projects reach the same outcome differently. Dependencies live in a node_modules directory inside the project, so each project carries its own copy and conflicts between projects do not arise. package.json describes the project and package-lock.json pins the exact resolved version tree. Commit both, add node_modules to .gitignore, and manage runtime versions with a version manager rather than a single system-wide install. The general principle is worth stating plainly because it survives any change of tooling: the environment directory itself is disposable and the file that describes it is the artefact, because that file is what lets a colleague or a build server reconstruct what you had.
Credentials get the same treatment everywhere. Keep the key in .env, keep .env out of version control, load it at startup, and then validate it before any other code runs. A clear startup failure naming the missing variable is far cheaper to diagnose than an authentication error surfacing deep in a call stack twenty minutes into a run, and the check costs three lines. The recurring anti-pattern the module names is hardcoding a key with the intention of removing it before deployment: the value has by then been written into every autosave, every editor search index and every commit, and the intention does not survive contact with a deadline. Complete the environment by pointing the editor at the same interpreter the code will run under, so that a missing import is flagged while you type rather than discovered at runtime.
The language runtime, the virtual environment, the model client and configuration each hold a separate boundary, so a pinned dependency survives a move between machines and a secret written into source has crossed the one boundary configuration exists to keep.
Runtime, virtual environment, model client and configuration each own a separate boundary. The Twelve-Factor App calls this 'config in the environment, not in the code'.
Every call to a modern language model has the same shape. You send a model identifier, a limit on how many tokens may be generated, and a list of messages each carrying a role and content; the model returns generated content and an accounting of what it consumed. The Anthropic Messages API reference confirms the required parameters as messages, model and max_tokens, describes max_tokens as the maximum number of tokens to generate before stopping while noting that generation may stop sooner, and states that the models are trained to operate on alternating user and assistant turns. It also records the design point that trips people up: the system prompt is supplied through a separate top-level parameter and there is no system role inside the input message list. Other providers differ in naming while keeping the same conceptual shape, which is why understanding the structure transfers better than memorising one software development kit.
Tokens are the unit of both cost and capacity, and both directions are billed. The response carries a usage object with input_tokens and output_tokens, so the honest way to calibrate an agent's economics is to log both during development rather than to estimate them afterwards. The arithmetic that surprises teams is not the single call, which is negligible, but the loop: an agent that takes twenty steps resends the system prompt, the whole conversation and every accumulated tool result on each one, so the input side of the bill grows step after step even when the model says very little. A system prompt is not free either; it is resent on every call and belongs in the budget. The context window bounds a single call, and an agent that accumulates long tool results will reach it, which is why the later modules on memory and context exist.
Temperature controls how much randomness is injected into token selection. The Messages API reference documents the range as 0.0 to 1.0 with a default of 1.0, and advises values closer to 0.0 for analytical work and closer to 1.0 for creative and generative work. The operational rule for agents is narrower than the range suggests: use the lowest setting for any step whose output another program will parse, which means tool selection and structured output, because there variation is a defect that shows up as a missing field, a stray sentence outside the object or an unparseable response. Save the higher settings for prose a person will read. Set the value explicitly in every call rather than inheriting a default that may differ between providers and between models.
The last mechanic is statelessness. The interface has no memory between calls, so a multi-turn conversation exists only because your code appends the model's reply and the next user message to a list and resends the whole list every time. That is a deliberate design choice: it makes the service simple to scale and gives the application complete control over what the model sees, at the price of managing that state yourself. Keeping the history explicit and printable is what makes an agent debuggable, because you can always show exactly what the model received. The stage's closing case is the cost of skipping all of this: lawyers filed a brief built on precedent cases produced by a chatbot, the cases did not exist, and asking the same system to confirm them returned a confident confirmation, because a plausible confirmation is exactly what next-token prediction produces. A low temperature reduces variance and does not make a claim true. Only retrieval from a verified source, and a check against it before acting, does that.
Prompt, model call, response and token budget should be visible from the first exchange, and the fourth step is where you record what you checked. Skip that record and the next change to the prompt has no earlier result to be measured against.
Treat the first interaction as an observable system call. Save the prompt, token count, response, and verdict so the next change has a baseline to beat.
Reading fluency as understanding, and concluding that a system which answers well across many subjects is close to general intelligence.
Instead: Breadth of training text produces breadth of plausible answers, not general reasoning. Every system in commercial use is narrow AI. Judge it the way the 1950 paper taught: define the observable outcome you need, define how you would measure it, and test that, rather than arguing about whether the system understands the task.
Treating fabrication as a defect that a newer model will fix.
Instead: A model produces statistically likely continuations and has no concept of truth, so thin evidence produces confident invention rather than an admission of ignorance. The control is architectural: retrieve the fact with a tool, require the answer to be drawn from what was retrieved, and validate the assertion against the source before anything acts on it. Both cases in this stage failed at exactly that step.
Calling a chatbot an agent because it holds a good conversation, or expecting a chatbot to behave like one.
Instead: The difference is structural. A chatbot generates text. An agent runs a perceive, think, act and observe loop, calls tools that reach real systems, carries state across steps and executes plans spanning several calls. Ask what tools it holds and what its stop condition is; if there are no tools and no loop, it is a chatbot, and it will invent rather than look things up.
Shipping an agent loop without a stop condition, on the argument that with enough steps it will eventually succeed.
Instead: An agent with no limit circles through reasoning it has already tried, fills the context window and accumulates cost until something else stops it. Define a success condition, a failure condition, a maximum step count and a fallback behaviour, such as returning a best-effort answer or handing over to a person, before the agent is deployed rather than after the first bill.
Running pip install without an activated virtual environment, on the basis that it only downloads a package.
Instead: It modifies whichever Python environment is active, which without a virtual environment means the system or user installation shared by every other project. Create and activate the environment first, confirm with which python that the interpreter resolves inside it, and only then install. Every project gets one, however small, because two packages are enough to produce a version conflict.
Hardcoding an API key while developing, intending to move it to configuration before deployment.
Instead: By the time the intention is acted on, the value exists in autosaves, editor search indexes and commit history. Create .env and add it to .gitignore before writing the first credential, load it at startup, and validate its presence with an error that names the missing variable. If a key has already reached version control history, treat it as compromised and rotate it rather than deleting the line.
Accepting whichever sampling temperature the provider defaults to.
Instead: The Messages API reference documents a default of 1.0, the creative end of its range, which is the wrong setting for any step whose output another program parses. Set temperature explicitly in every call: the lowest value for tool selection and structured output, higher values only for prose a person will read. Defaults differ between providers and between models, so inheriting one is a decision you did not make.
Reading a Python traceback from the top, or scanning it for the first familiar file name.
Instead: Tracebacks read from the bottom upwards. The last line names the error type and the cause; the lines above are the call stack that reached it. Start at the bottom, read the error type, then walk up to the first frame that is in your own code rather than in a library, which is almost always where the fix belongs.
Treating rm -rf as safe because you checked that you are in the right directory.
Instead: The command deletes the path you pass it, which may be relative or absolute, so the current directory only partly constrains the damage and there is no recycle bin to undo it. Print the target path and read it before running the command, and prefer naming the directory explicitly over shorthand that resolves to something wider than you meant.
That is the Foundations stage in one place. Three nested fields that are not synonyms, a seventy-year trajectory with two collapses in it that tells you how much weight a fresh claim can bear, narrow AI with four limits that are properties rather than defects and a system-level control for each, attention as a learned relevance function and tool use as the addition that lets a predictor act, the perceive, think, act and observe loop with a stop condition written before deployment, a terminal fluent enough to install and debug agent code and keep a credential out of version control, an isolated environment whose describing file is the real artefact, and a first API call understood well enough to read its token accounting, choose its sampling temperature and carry its conversation state yourself. The scenario practice now puts that under pressure with realistic situations, so that the confusions surface here rather than in the core concepts stage, where reasoning patterns, memory, tool design and the protocols that connect agents to real systems all assume you can already tell a model from an agent, a training boundary from a design boundary, and a missing tool from a bad prompt without stopping to look it up.