AI agents

Build a testable Python agent loop without an API key

Build a small troubleshooting agent with bounded tools, validated actions, a complete trace, and automated tests using only the Python standard library.

Outcome

Run a deterministic troubleshooting agent, inspect every action, and verify success, validation, and bounded-failure paths before adding a model.

Prerequisites
  • 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:

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

Code verification

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 →