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.
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.
01 · Orientation
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.
02 · Quick start
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.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
export OPENAI_API_KEY="your-api-key"
export LITELLM_MODEL="gpt-5-mini"
python src/basic_llm_call.py
| Variable | Purpose | Typical default in this repo |
|---|---|---|
OPENAI_API_KEY | Authenticates OpenAI-backed examples. Use the corresponding provider key when choosing another LiteLLM provider. | Required at runtime; never store it in the repository. |
LITELLM_MODEL | Selects the model without editing source. | gpt-5-mini for most scripts; gpt-4.1-mini in graph examples. |
LITELLM_MAX_TOKENS | Caps generated output per model call. | Varies by lesson: commonly 16,384; smaller in graph, multimodal, and harness-style demos. |
gpt-4o-mini by default:
export LITELLM_MODEL="gpt-4o-mini"
python src/multimodal_image_ingestion.py
03 · Mental 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.
Defines tools, parses or receives tool calls, executes them, stores messages, and decides when another model turn is needed.
Constrains the runtime with permissions, path boundaries, policy gates, budgets, telemetry, approvals, verification, and termination rules.
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 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 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.
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
Read the scripts in this order if you want each new file to answer a question raised by the previous one.
How do I call a model, normalize its response, and keep an interaction alive?
How can the model choose deterministic functions, and how is the result returned?
How does context survive another turn, and what changes when a framework owns that state?
How do graphs make routing visible, and when should control be centralized or peer-to-peer?
How can an agent plan, execute, inspect, repair, and retry longer tasks?
How do permissions, policy, observability, protocols, multimodality, and evals change the design?
05 · Source guide
src/Each card states the file’s role and the implementation detail worth studying. Click a filename to open the source.
The smallest complete example: read one prompt, call litellm.completion(), normalize object/dictionary response shapes with extract_text(), and print the answer.
python src/basic_llm_call.pyWraps 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.
python src/llm_with_loop.pyDefines 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.
python src/agent_with_tool_calling.pyAdds 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.
python src/agent_with_memory.pyRebuilds the assistant with @tool, ChatOpenAI, and create_agent(). The framework creates schemas, handles native tool messages, and runs the model/tool loop.
python src/langchain_basic_agent.pyAdds LangGraph’s InMemorySaver. Reusing thread_id="1" lets the agent recover the conversation state, which the script prints after each turn for inspection.
python src/langchain_agent_with_memory.pyIntroduces graph-backed execution with one named math agent, Sami. The graph runtime chooses among add, multiply, and divide tools for a compound expression.
python src/langgraph_single_agent.pyCreates three narrow math agents and a central supervisor that routes work. visualize_agent_flow() reports agent actions, transfers, and cumulative token usage.
python src/langgraph_supervisor_agent.pyGives 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.
python src/langgraph_swarm_agent.pyReflectionAgent generates Python, SafeExecutor captures output/errors, and repeated model calls refine the solution. The shared namespace supports testing generated functions across iterations.
python src/reflection_pattern_code_execution.pyBuilds 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.
python src/reflection_pattern_database.pyModels 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.
python src/planning_pattern_code_execution.pyA 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.
python src/agent_harness_example.pyA 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.
python src/mini_claude_code.pyReduces 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.
python src/openclaw_simple.pyAccepts 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.
python src/multimodal_image_ingestion.pyExposes 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.
python src/mcp_simple_example.py --demoRuns 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.
python src/evaluation_example.py06 · Architecture choices
| Pattern | Control | State | Best lesson | Main tradeoff |
|---|---|---|---|---|
| Single call | Application calls once | None | basic_llm_call.py | Simple and predictable, but cannot act or iterate. |
| Custom tool agent | Hand-written parser and dispatcher | Optional message list | agent_with_tool_calling.py | Transparent and flexible; prompt-formatted JSON is brittle. |
| Framework agent | LangChain/LangGraph runtime | Messages or checkpoints | langchain_basic_agent.py | Less plumbing, but control flow is more abstract. |
| Supervisor | Central router delegates | Shared workflow messages | langgraph_supervisor_agent.py | Clear governance; the supervisor adds cost and a bottleneck. |
| Swarm | Peers hand off directly | Checkpointed active-agent state | langgraph_swarm_agent.py | Adaptive routing; emergent paths are harder to predict. |
| Reflection | Generate–execute–critique loop | Execution/query history | reflection_pattern_code_execution.py | Can repair failures; costs extra calls and may repeat mistakes. |
| Planning | Dependency-aware executor | Step statuses and shared namespace | planning_pattern_code_execution.py | Progress is inspectable; plans can become stale after failures. |
| Harnessed agent | Policy and permissions wrap execution | Audit logs, metrics, sessions | agent_harness_example.py | Safer and observable; more engineering around every action. |
07 · Repository map
src/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
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
Several scripts deliberately expose the mechanism instead of providing a hardened production boundary.
exec(). Despite educational naming and output capture, this is not secure isolation and the apparent timeout parameter in the reflection executor is not enforced.eval(). It strips non-mathematical characters first, but production code should prefer a real expression parser and explicit resource limits.:memory:, and InMemorySaver disappear when the process ends. The OpenClaw-style example is the one that demonstrates JSON persistence.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.09 · Suggested routes
basic_llm_call.pyllm_with_loop.pyagent_with_tool_calling.pyagent_with_memory.pylangchain_basic_agent.pylanggraph_single_agent.pylanggraph_supervisor_agent.pylanggraph_swarm_agent.pyplanning_pattern_code_execution.pyagent_harness_example.pyevaluation_example.pymini_claude_code.pymcp_simple_example.pymultimodal_image_ingestion.pyopenclaw_simple.py10 · References
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.