First AI Agent - Python (full implementation)

Full runnable agent example with the "Act -> Check -> Retry" loop and a step limit.
On this page
  1. What this example demonstrates
  2. Project structure
  3. How to run
  4. Code
  5. main.py - agent loop
  6. llm.py - model call
  7. evaluator.py - result validation
  8. requirements.txt
  9. Example output
  10. Why this is an "agent", not just a function
  11. Where to dig next
  12. πŸ’» Full code on GitHub

This is the full implementation of the example from Build Your First AI Agent.

If you have not read it yet, start there. Here we focus on the code.


What this example demonstrates

  • Agent goal: get a number greater than 10 from the model
  • Loop: Act -> Check -> Retry (up to MAX_STEPS times)
  • Validation: the model can return text, an empty string, or a non-numeric value - the agent handles it
  • Stop condition: the agent stops either on success or when steps are exhausted

Project structure

TEXT
examples/
└── start-here/
    └── write-your-first-agent/
        └── python/
            β”œβ”€β”€ main.py           # agent loop
            β”œβ”€β”€ llm.py            # LLM call (integration isolation)
            β”œβ”€β”€ evaluator.py      # result validation
            └── requirements.txt

Why three files instead of one? Because in a real agent, generation and evaluation are almost always separated. If you want to change the model or validation logic, you change one file without touching the rest.


How to run

1. Clone the repository and move to the folder:

BASH
git clone https://github.com/AgentPatterns-tech/agentpatterns.git
cd examples/start-here/write-your-first-agent/python

2. Install dependencies:

BASH
pip install -r requirements.txt

3. Set API key:

BASH
export OPENAI_API_KEY="sk-..."

4. Run:

BASH
python main.py

Code

main.py - agent loop

PYTHON
from llm import generate_number
from evaluator import parse_int, is_goal_reached

GOAL = 10
MAX_STEPS = 5

def run():
    for step in range(1, MAX_STEPS + 1):
        print(f"\nπŸ€– Step {step}: Agent is trying...")

        output = generate_number()
        print(f"πŸ’¬ Model generated: {output}")

        number = parse_int(output)
        if number is None:
            print("❌ Not a number. Trying again...")
            continue

        if is_goal_reached(number, GOAL):
            print(f"βœ… Goal reached! {number} > {GOAL}")
            return

        print(f"❌ Not enough. {number} ≀ {GOAL}. Trying again...")

    print("\n⚠️ Max steps reached without success")

if __name__ == "__main__":
    run()

main.py knows nothing about OpenAI. It does not know how to parse numbers. It only controls the loop - that is the agent's role.


llm.py - model call

PYTHON
import os
from openai import OpenAI

api_key = os.environ.get("OPENAI_API_KEY")

client = OpenAI(api_key=api_key)

PROMPT = "Write ONLY a random number between 1 and 20. No text, no explanation."

def generate_number() -> str:
    resp = client.responses.create(
        model="gpt-4.1-mini",
        input=PROMPT,
    )
    return resp.output_text.strip()

The model gets a task and returns text. It does not know there is an agent, a goal, or a step limit. It simply generates.


evaluator.py - result validation

PYTHON
def parse_int(text: str) -> int | None:
    """Returns int or None if text is not an integer."""
    try:
        return int(text.strip())
    except (ValueError, AttributeError):
        return None

def is_goal_reached(number: int, goal: int) -> bool:
    """Returns True if the number satisfies the condition."""
    return number > goal

Two small questions with clear answers: "is it a number?" and "is the goal reached?". That is all.


requirements.txt

TEXT
openai>=1.0.0

Example output

TEXT
πŸ€– Step 1: Agent is trying...
πŸ’¬ Model generated: 7
❌ Not enough. 7 ≀ 10. Trying again...

πŸ€– Step 2: Agent is trying...
πŸ’¬ Model generated: 3
❌ Not enough. 3 ≀ 10. Trying again...

πŸ€– Step 3: Agent is trying...
πŸ’¬ Model generated: 14
βœ… Goal reached! 14 > 10

Why this is an "agent", not just a function

FunctionAgent
Number of attempts1up to MAX_STEPS
Checks resultβŒβœ…
Decides whether to continue or stopβŒβœ…
Needs human involvement between stepsβ€”βŒ

One model call is not an agent.
A loop with validation and the decision "try again or stop" is an agent.


Where to dig next

Try modifying the example yourself:

  • Change GOAL = 10 to GOAL = 19 - how often will the agent reach the goal within MAX_STEPS?
  • Remove MAX_STEPS and use while True - what will happen?
  • Change the prompt so the model generates numbers from 1 to 100 - how will that affect agent behavior?
  • Add a counter of total API calls and print it at the end

πŸ’» Full code on GitHub

-> View on GitHub

⏱️ 4 min read β€’ Updated Mar, 2026Difficulty: β˜…β˜†β˜†
Integrated: production controlOnceOnly
Add guardrails to tool-calling agents
Ship this pattern with governance:
  • Budgets (steps / spend caps)
  • Tool permissions (allowlist / blocklist)
  • Kill switch & incident stop
  • Idempotency & dedupe
  • Audit logs & traceability
Integrated mention: OnceOnly is a control layer for production agent systems.
Author

This documentation is curated and maintained by engineers who ship AI agents in production.

The content is AI-assisted, with human editorial responsibility for accuracy, clarity, and production relevance.

Patterns and recommendations are grounded in post-mortems, failure modes, and operational incidents in deployed systems, including during the development and operation of governance infrastructure for agents at OnceOnly.