Repository field guide · 2026 edition

From an LLM call to an agent system.

This manual explains the ideas, code, and learning sequence in the Agentic AI Crash Course. Use it as a map of src/, a setup guide, and a vocabulary for comparing agent architectures.

18runnable Python lessons
1 loopobserve → decide → act → repeat
3 layersmodel · agent · harness
4 themestools · state · control · evaluation

01 · Orientation

What this repository teaches

The course grows one idea at a time. A model first answers text. Then a loop gives it repeated chances to work; tools let it affect or inspect the world; memory carries state across turns; graphs coordinate specialists; reflection and planning organize longer work; a harness adds policy, permissions, monitoring, and evaluation.

ObserveReceive a user message, tool result, file, image, or state.
DecideThe model chooses a response, action, route, or plan step.
ActReturn text or invoke a tool in the surrounding program.
RepeatFeed the result back until the task reaches a stop condition.
The central lesson: the language model is only the decision-making component. The agent is the model plus its instructions, tools, state, and loop. The harness is the control system around that agent.

02 · Quick start

Install once, run lessons directly

The examples are intentionally script-like. Create a virtual environment at the repository root, install the shared dependencies, set credentials for your model provider, and run any lesson with Python.

1. Install

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

2. Configure

export OPENAI_API_KEY="your-api-key"
export LITELLM_MODEL="gpt-5-mini"

python src/basic_llm_call.py
VariablePurposeTypical default in this repo
OPENAI_API_KEYAuthenticates OpenAI-backed examples. Use the corresponding provider key when choosing another LiteLLM provider.Required at runtime; never store it in the repository.
LITELLM_MODELSelects the model without editing source.gpt-5-mini for most scripts; gpt-4.1-mini in graph examples.
LITELLM_MAX_TOKENSCaps generated output per model call.Varies by lesson: commonly 16,384; smaller in graph, multimodal, and harness-style demos.
Vision model required: use a model that accepts images for the multimodal lesson. The repository example uses gpt-4o-mini by default:
export LITELLM_MODEL="gpt-4o-mini"
python src/multimodal_image_ingestion.py

03 · Mental model

The layers that turn generation into agency

Model

Consumes messages and predicts a response. It can propose an action, but it cannot execute Python, read a file, or query a database by itself.

Agent runtime

Defines tools, parses or receives tool calls, executes them, stores messages, and decides when another model turn is needed.

Harness

Constrains the runtime with permissions, path boundaries, policy gates, budgets, telemetry, approvals, verification, and termination rules.

Tool calling

A tool has a name, description, input contract, implementation, and result. The model chooses the tool and arguments; application code validates and executes the request. The early examples ask the model for JSON, while later examples use native structured tool calls and framework-managed dispatch.

Memory and state

Memory is not something a model silently “has.” This repository makes it concrete: a Python message list, a LangGraph checkpointer keyed by thread ID, a shared plan namespace, or a JSON state file.

Planning and reflection

Planning looks forward by decomposing a goal and ordering dependencies. Reflection looks backward by examining output or errors and proposing an improvement. Strong systems commonly combine both.

Evaluation

Agent quality includes both outcome and process: whether the final answer is correct, whether the intended tool was used with sensible arguments, and whether open-ended output satisfies a rubric.

04 · Learning path

Follow the rising abstraction

Read the scripts in this order if you want each new file to answer a question raised by the previous one.

  1. Generation

    How do I call a model, normalize its response, and keep an interaction alive?

  2. Action

    How can the model choose deterministic functions, and how is the result returned?

  3. State

    How does context survive another turn, and what changes when a framework owns that state?

  4. Orchestration

    How do graphs make routing visible, and when should control be centralized or peer-to-peer?

  5. Deliberation

    How can an agent plan, execute, inspect, repair, and retry longer tasks?

  6. Production concerns

    How do permissions, policy, observability, protocols, multimodality, and evals change the design?

05 · Source guide

Every element in src/

Each card states the file’s role and the implementation detail worth studying. Click a filename to open the source.

Foundations

Model calls and control loops

basic_llm_call.py

LiteLLMMessages

The smallest complete example: read one prompt, call litellm.completion(), normalize object/dictionary response shapes with extract_text(), and print the answer.

Start herepython src/basic_llm_call.py

llm_with_loop.py

REPLErrors

Wraps calls in an input loop with empty-input handling, a quit stop condition, and per-turn error recovery. It deliberately sends no history, so repeated interaction is not yet memory.

Loop, no memorypython src/llm_with_loop.py

Tools and memory by hand

See the plumbing before using frameworks

agent_with_tool_calling.py

ToolsJSON routing

Defines calculator, simulated weather, date, and time functions. A system prompt asks the model to emit a JSON action; Python parses it and dispatches the tool. This is educational prompt-based routing, not native tool calling.

Decision → dispatchpython src/agent_with_tool_calling.py

agent_with_memory.py

HistoryContext

Adds a list of user/assistant messages to the custom tool agent. Every turn extends and resends that history, making the cost and mechanics of conversational memory explicit.

In-process memorypython src/agent_with_memory.py

LangChain and LangGraph

Framework-managed tools, state, and routing

langchain_basic_agent.py

LangChain@tool

Rebuilds the assistant with @tool, ChatOpenAI, and create_agent(). The framework creates schemas, handles native tool messages, and runs the model/tool loop.

Framework baselinepython src/langchain_basic_agent.py

langchain_agent_with_memory.py

CheckpointThread ID

Adds LangGraph’s InMemorySaver. Reusing thread_id="1" lets the agent recover the conversation state, which the script prints after each turn for inspection.

Checkpoint memorypython src/langchain_agent_with_memory.py

langgraph_single_agent.py

GraphMath tools

Introduces graph-backed execution with one named math agent, Sami. The graph runtime chooses among add, multiply, and divide tools for a compound expression.

One graph agentpython src/langgraph_single_agent.py

langgraph_supervisor_agent.py

SupervisorDelegation

Creates three narrow math agents and a central supervisor that routes work. visualize_agent_flow() reports agent actions, transfers, and cumulative token usage.

Central controlpython src/langgraph_supervisor_agent.py

langgraph_swarm_agent.py

SwarmHandoffs

Gives each specialist explicit handoff tools so peers route tasks directly. A checkpointer preserves graph state, while the same flow reporter makes the distributed path visible.

Peer-to-peerpython src/langgraph_swarm_agent.py

Reflection and planning

Generate, execute, inspect, improve

reflection_pattern_code_execution.py

Reflectionexec()

ReflectionAgent generates Python, SafeExecutor captures output/errors, and repeated model calls refine the solution. The shared namespace supports testing generated functions across iterations.

Iterative repairpython src/reflection_pattern_code_execution.py

reflection_pattern_database.py

SQLiteSQL reflection

Builds an in-memory commerce database, asks the model for SQLite queries, executes them, and reflects on errors, row counts, performance, nulls, sorting, and completeness before refining.

Data agentpython src/reflection_pattern_database.py

planning_pattern_code_execution.py

PlanningDependencies

Models steps and statuses explicitly. The LLM returns a JSON plan; ExecutionPlan finds ready steps, shares variables, records timing, and asks PlanningAgent to adapt failed code.

Plan → execute → adaptpython src/planning_pattern_code_execution.py

Harnesses and assistant systems

Control planes and more complete runtimes

agent_harness_example.py

PolicyMonitoringGovernance

A teaching model of a production control plane: typed action requests/results, risk levels, path policy, approval requirements, a tool registry, audit logs, metrics, a temporary sandbox, and a plan–execute–verify loop.

Abstract harness patternpython src/agent_harness_example.py

mini_claude_code.py

Coding agentPermissions

A runnable coding-agent REPL using native tool calls. It offers list/read/write/edit/bash/grep tools, path-prefix confinement, interactive approvals, conversation history, a shell timeout, and a 20-step cap.

Concrete harnesspython src/mini_claude_code.py

openclaw_simple.py

ChannelsSkillsState

Reduces a multi-channel personal assistant to three pieces: normalized Message adapters, a decorator-based skills registry, and JSON-backed local state for reminders, notes, and todos.

Assistant architecturepython src/openclaw_simple.py

Interfaces, multimodality, and quality

Connect, perceive, and measure

multimodal_image_ingestion.py

VisionBase64JSON

Accepts a remote URL or validates and base64-encodes a local PNG/JPEG/GIF/WEBP. It demonstrates mixed text/image message parts and both free-form and structured visual analysis.

Image-aware workflowpython src/multimodal_image_ingestion.py

mcp_simple_example.py

MCPFastMCPasyncio

Exposes two tools, a templated greeting resource, and a reusable prompt. --demo starts the same file as a stdio server and drives it with an asynchronous MCP client session.

Protocol boundarypython src/mcp_simple_example.py --demo

evaluation_example.py

EvalsLLM judge

Runs a tiny agent over an inline dataset and records traces. It scores numeric tolerance, required substrings, expected tool/arguments, and rubric-based open-ended answers, then aggregates a report.

Outcome + process metricspython src/evaluation_example.py

06 · Architecture choices

Compare the patterns, not just the APIs

PatternControlStateBest lessonMain tradeoff
Single callApplication calls onceNonebasic_llm_call.pySimple and predictable, but cannot act or iterate.
Custom tool agentHand-written parser and dispatcherOptional message listagent_with_tool_calling.pyTransparent and flexible; prompt-formatted JSON is brittle.
Framework agentLangChain/LangGraph runtimeMessages or checkpointslangchain_basic_agent.pyLess plumbing, but control flow is more abstract.
SupervisorCentral router delegatesShared workflow messageslanggraph_supervisor_agent.pyClear governance; the supervisor adds cost and a bottleneck.
SwarmPeers hand off directlyCheckpointed active-agent statelanggraph_swarm_agent.pyAdaptive routing; emergent paths are harder to predict.
ReflectionGenerate–execute–critique loopExecution/query historyreflection_pattern_code_execution.pyCan repair failures; costs extra calls and may repeat mistakes.
PlanningDependency-aware executorStep statuses and shared namespaceplanning_pattern_code_execution.pyProgress is inspectable; plans can become stale after failures.
Harnessed agentPolicy and permissions wrap executionAudit logs, metrics, sessionsagent_harness_example.pySafer and observable; more engineering around every action.
Framework names are secondary. When reading a file, ask who owns the loop, where state lives, how actions are represented, which component may execute them, and what ends the run. Those questions transfer across libraries.

07 · Repository map

Files outside src/

agentic-ai-crash-course/ ├── README.md # concise setup, script index, references ├── requirements.txt # shared Python dependencies ├── CLAUDE.md # guidance for coding assistants ├── src/ # 18 runnable course lessons ├── resources/ │ ├── README.md # supported image formats and examples │ └── vision_sample.png # default multimodal input └── docs/ ├── index.html # this GitHub Pages entry point ├── .nojekyll # publish the static files as-is └── notes/ └── asyncio/ ├── asyncio.md └── asyncio_example.py

Resources

Put local image inputs in resources/. The multimodal script accepts PNG, JPEG, WEBP, and GIF, and defaults to vision_sample.png.

python src/multimodal_image_ingestion.py \
  --path resources/your_image.png

python src/multimodal_image_ingestion.py \
  --path resources/your_image.png --json

Notes

The notes now live with the manual. Read the asyncio note for the event-loop model used by the MCP client, then run its small companion:

python docs/notes/asyncio/asyncio_example.py

Dependency groups in requirements.txt cover LiteLLM and pandas, LangChain/LangGraph packages, and mcp[cli]. The MCP extra provides the mcp dev inspector command.

08 · Safety and limits

These are teaching artifacts

Several scripts deliberately expose the mechanism instead of providing a hardened production boundary.

  • Generated code executes locally. The reflection and planning lessons use Python exec(). Despite educational naming and output capture, this is not secure isolation and the apparent timeout parameter in the reflection executor is not enforced.
  • The calculator also uses eval(). It strips non-mathematical characters first, but production code should prefer a real expression parser and explicit resource limits.
  • Prompt JSON is not a guarantee. The custom tool agents recover JSON from model text. Native tool schemas improve structure, but inputs still need validation and authorization.
  • Example data is simulated. Weather lookup tables, generated commerce data, fake inboxes, and report/analyzer tools demonstrate control flow; they are not live integrations.
  • In-memory state is temporary. Message lists, SQLite :memory:, and InMemorySaver disappear when the process ends. The OpenClaw-style example is the one that demonstrates JSON persistence.
  • Path checks are not OS sandboxes. mini_claude_code.py says this explicitly. Permission prompts, prefix checks, and a working-directory boundary are useful controls, not a replacement for container or operating-system isolation.
  • Evaluators need evaluation. LLM judges have biases. Pin judge versions, log rubrics, compare against human review, and track regressions over time.
  • Protect credentials. Export provider keys in your environment. Do not paste them into source, prompts, notes, screenshots, or commits.

09 · Suggested routes

Choose a route through the course

I’m new to agents

  1. basic_llm_call.py
  2. llm_with_loop.py
  3. agent_with_tool_calling.py
  4. agent_with_memory.py
  5. langchain_basic_agent.py

I’m designing systems

  1. langgraph_single_agent.py
  2. langgraph_supervisor_agent.py
  3. langgraph_swarm_agent.py
  4. planning_pattern_code_execution.py
  5. agent_harness_example.py

I’m shipping agents

  1. evaluation_example.py
  2. mini_claude_code.py
  3. mcp_simple_example.py
  4. multimodal_image_ingestion.py
  5. openclaw_simple.py

10 · References

Where the course continues

The repository README recommends two complementary courses:

For the short repository overview, return to the README. For implementation details, the source files themselves contain extensive module docstrings and inline commentary.