Building AI Agents from Scratch

The Agent Loop

Build the think → act → observe → repeat loop from scratch and decide when it stops.

One completion is a thought. An agent is a while that may think again after it acts. You own the loop. The vendor SDK does not.

The four steps

  • Think — call the model with the current messages (and later, tools).
  • Act — if the model asked for a tool, run your Python.
  • Observe — append the tool result as a message the model can read.
  • Repeat — until the model returns plain text, or you hit a cap.

This lesson implements think and stop only. Act arrives in Giving Your Agent Tools. The shape of run() should not change.

A loop with a hard stop

import os

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["OPENAI_API_KEY"],
    base_url=os.environ.get("OPENAI_BASE_URL") or None,
)
MODEL = os.environ.get("OPENAI_MODEL", "gpt-4.1-mini")


def think(messages: list[dict]) -> object:
    return client.chat.completions.create(model=MODEL, messages=messages).choices[0].message


def run(user_text: str, max_steps: int = 8) -> str:
    messages = [
        {"role": "system", "content": "Solve the user's request. Be brief."},
        {"role": "user", "content": user_text},
    ]
    for step in range(max_steps):
        message = think(messages)
        messages.append({"role": "assistant", "content": message.content or ""})
        # No tools yet: the first assistant message is the answer.
        return message.content or ""
    return "stopped: max steps"


if __name__ == "__main__":
    print(run("Name three Linux commands that show disk use."))

The for is the loop. max_steps is a fuse. Returning on the first assistant message is correct until tools exist — otherwise you would call the model forever on the same prompt.

When to stop

  • The model returned content and no tool calls (final answer).
  • max_steps hit — return a structured “stopped” string, not silence.
  • Later: a human rejected an action, or a budget ran out.

Run the file. You should see a short list, then the process exits. Next: let the model request a tool.