Run a deterministic troubleshooting agent, inspect every action, and verify success, validation, and bounded-failure paths before adding a model.
- Python 3.12 or newer
- A terminal and an empty working directory
- No model account or API key
What you will build
You will build the runtime around an agent rather than a language-model call. A deterministic planner classifies a Python problem, chooses a reviewed troubleshooting playbook, records a trace, and returns an answer.
The planner is deliberately predictable so you can inspect and test every action without credentials or network access. Later, you can replace only decide() with a provider call while keeping validation, tools, deadlines, trace, and tests under application control.
You are done when the example returns the network troubleshooting playbook, records its action sequence, and the complete test suite passes.
Download the reviewed example
Create a directory and download the exact source and tests published with this guide:
mkdir flypython-agent-loop
cd flypython-agent-loop
curl -O https://flypython.com/examples/agent-loop/agent_loop.py
curl -O https://flypython.com/examples/agent-loop/test_agent_loop.py
You can also inspect agent_loop.py and test_agent_loop.py before downloading them.
The runtime exposes only narrow tools. Before execution, it checks the planner output, the requested tool, and the argument values. Every accepted action is appended to a trace.
Run it and inspect the trace
Run the example:
python3 agent_loop.py
The final answer is only one part of the result. Inspect the trace to confirm that the planner classified the request, retrieved one bounded playbook, and finished explicitly.
A model can propose an action, but the application still owns the action schema, runtime validation, tool allowlist, deadlines, observations, completion rules, and audit trace.
Verify success and failure paths
Run the tests from the same directory:
python3 -m unittest -v
Verification command: python3 -m unittest -v. Treat a non-zero result as a failed guide verification rather than continuing to model integration. Important failure paths include an invalid action, unknown tool, wrong argument type, exhausted step budget, wall-clock deadline, and side effects without review.
A step counter protects against excessive iterations. It is not a timeout; calls that can block also need a wall-clock deadline.
Add a model only where judgment is useful
When ready, replace the deterministic planner with a provider adapter that returns the same validated Action contract. Do not move tool authorization, execution, or completion decisions inside an untrusted prompt.
Use a framework when you need provider adapters, typed parsing, traces, handoffs, state graphs, or durable execution:
- OpenAI Agents SDK for tools, handoffs, guardrails, and tracing.
- Pydantic AI for typed dependencies and model portability.
- LangGraph for explicit state and durable execution.
- Model Context Protocol for reusable tool and data-source boundaries.
Sources
The example uses Python dataclasses and unittest. The framework descriptions link to maintained primary documentation.
Change the request, add one narrow read-only tool, and write its failure tests before connecting a model. For the surrounding reliability model, continue to Build safe Python automation that can be retried.
Verification record
Python 3.14.7 runtime on macOS; Python 3.12 syntax compatibility checked. Verified 2026-08-31. Command: python3 -m unittest discover -s public/examples/agent-loop -p 'test_*.py' -v.
About the author
Practical Python guides researched, tested, and maintained by the FlyPython editorial team. Editorial standards and contact details →