> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Lab Walkthrough Your First Agent Loop

> Guide to implementing a minimal Python AI agent loop that checks model finish_reason and repeats until completion, demonstrating single-turn and multi-turn handling without external tools

Time to build your first AI agent loop.

In this lesson you'll implement the minimal control loop that drives every AI agent: a while loop that calls the chat completion endpoint, inspects the model's `finish_reason`, and repeats until the model has finished. This example intentionally avoids tools and external actions — it focuses on the core loop logic.

## Environment

* Python 3.11 (virtual environment recommended)
* OpenAI Python SDK pre-installed
* Working directory: `/root/code`
* Ensure these environment variables are set: `OPENAI_API_KEY`, `OPENAI_API_BASE`

## Create `agent_loop.py`

Start by creating a new file named `agent_loop.py`. Import `os` and `OpenAI`, instantiate the client using environment variables, and initialize the conversation `messages` with a single system message:

```python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url=os.getenv("OPENAI_API_BASE"),
)

messages = [
    {"role": "system", "content": "You are a helpful assistant."}
]
```

This setup gives the model a system-level instruction and a client object you can use to call the chat completions API.

## A minimal agent loop

The essential agent pattern is:

1. Call the model.
2. Inspect `finish_reason` on the first choice.
3. If `finish_reason == "stop"`, print the assistant's answer and exit.
4. Otherwise, handle non-terminal signals (e.g., function calls, token limits) in the `else` branch.

Example minimal loop:

```python theme={null}
while True:
    response = client.chat.completions.create(
        model="openai/gpt-4.1-mini",
        messages=messages,
    )

    finish_reason = response.choices[0].finish_reason
    if finish_reason == "stop":
        print(response.choices[0].message.content)
        break
    else:
        # Non-terminal finish reasons (e.g., "function_call" or "length")
        # should be handled here when integrating tools or function calls.
        print("Non-terminal finish_reason:", finish_reason)
        break
```

Note: The `else` branch is intentionally simple here. When you add tools, function calling, or streaming, extend that branch to interpret the model signal, invoke tools, and feed results back into `messages`.

## Add a user message and run it

Append a user message before the loop and run the script. For example:

```python theme={null}
messages.append({
    "role": "user",
    "content": "What are three things an AI agent can do that a regular chatbot cannot?"
})
```

Run the script from the shell:

```bash theme={null}
python3 agent_loop.py
```

Example console output:

```text theme={null}
1. Take autonomous actions
2. Use tools
3. Plan multi-step tasks
```

One call, one answer, one exit — the simplest working agent loop.

## Multi-turn conversation (handling multiple questions)

Real agents often handle multiple related questions in sequence. To preserve context across turns, append the assistant's reply to `messages` after each response so subsequent calls see the full conversation history.

Replace the single user message with a list of questions and iterate over them. For each question:

* Append the user message
* Enter the same loop and call the model
* If `finish_reason == "stop"`, print the reply and append the assistant reply to `messages`

Example:

```python theme={null}
questions = [
    "What is an agent?",
    "How is that different from a chatbot?",
    "Give me one example.",
]

for question in questions:
    messages.append({"role": "user", "content": question})

    while True:
        response = client.chat.completions.create(
            model="openai/gpt-4.1-mini",
            messages=messages,
        )

        if response.choices[0].finish_reason == "stop":
            reply = response.choices[0].message.content
            print(f"Q: {question}")
            print(f"A: {reply}\n")

            # Add the assistant's reply to the conversation history.
            messages.append({"role": "assistant", "content": reply})
            break
        else:
            # As before: handle non-terminal signals here (tools, function calls, streaming, etc.)
            print("Non-terminal finish_reason:", response.choices[0].finish_reason)
            break
```

Run the script again. You should see each question answered in turn, with each answer informed by previous context. This demonstrates multi-turn memory implemented simply with a Python list.

<Callout icon="lightbulb" color="#1CB2FE">
  The `finish_reason` field indicates why the model stopped generating. Common values include `"stop"` (generation finished normally), `"length"` (truncated due to token limits), and `"function_call"` (model is invoking a function/tool). The `else` branch in the loop is where you'd implement handling for these non-terminal signals when integrating tools or function calls.
</Callout>

## Common finish\_reason values

| finish\_reason | Meaning | Typical action |
| - | - | - |
| `stop` | Model finished generating normally | Print reply, append to history, or continue with next user turn |
| `length` | Response truncated due to token limits | Optionally increase max tokens, re-prompt, or stream remaining output |
| `function_call` | Model is requesting a function / tool invocation | Parse function call, execute tool, feed the result back into `messages` |
| other | Any other non-terminal signal | Inspect and handle according to your tool integration |

## Wrapping up

The while-loop that checks `finish_reason == "stop"` is the core control structure for simple AI agents. As you add tools, function calling, or streaming, extend the `else` branch to interpret model signals, perform actions, and feed results back into the conversation loop. This pattern scales from the simplest chat to powerful, tool-enabled agents.

## Links and references

* [Kubernetes Basics](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/) (example resource)
* [OpenAI Python SDK documentation](https://platform.openai.com/docs)

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/ai-agents-for-beginner-openclaw-case-study/module/d77598d4-d1d3-4768-97da-03ead60bf984/lesson/7e9328ea-53b4-4feb-ad5b-5ff9a7cdc67a" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.