C.W.K.
Stream
Lesson 04 of 07 · published

The Tool Loop

~22 min · tool-loop, multi-turn

Level 0Tokenizer
0 XP0/54 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

The tool loop is the core pattern for agentic behavior: the model calls tools, you execute them and return results, and the model continues until it has enough information to respond.

The full loop, one phase per call

Phase 1: send the user message + tool definitions. Model returns either text (loop ends) or one-or-more tool_calls. Phase 2: for each tool_call, run the handler and capture the result. Phase 3: send the tool results back as a new turn (Chat Completions: tool-role messages with tool_call_id; Responses: input list with function_call_output items). Model returns either text or another tool_call. Loop until text.

Production loops always have a max_iterations cap (8-12 is typical). Without it, a model can ping-pong tools forever under bad prompting and burn through your budget in minutes. The cap is a circuit breaker, not a soft limit — when hit, abort with a clear error rather than 'maybe one more turn'.

Code

Full tool loop (Responses)·python
import json
from openai import OpenAI

client = OpenAI()

def get_weather(location, units="celsius"):
    return {"location": location, "temperature": 22, "condition": "sunny", "units": units}

def search_news(query):
    return [{"title": f"News about {query}", "url": "https://news.example.com"}]

TOOLS_MAP = {"get_weather": get_weather, "search_news": search_news}

tools = [
    {"type": "function", "name": "get_weather", "description": "Get current weather",
     "parameters": {"type": "object", "properties": {"location": {"type": "string"},
     "units": {"type": ["string", "null"], "enum": ["celsius", "fahrenheit"]}},
     "required": ["location"], "additionalProperties": False}, "strict": True},
    {"type": "function", "name": "search_news", "description": "Search recent news",
     "parameters": {"type": "object", "properties": {"query": {"type": "string"}},
     "required": ["query"], "additionalProperties": False}, "strict": True},
]

input_items = [{"role": "user", "content": "Weather in Tokyo and any AI news?"}]

while True:
    response = client.responses.create(model="gpt-5.4", tools=tools, input=input_items)
    input_items.extend(response.output)
    tool_calls = [i for i in response.output if i.type == "function_call"]
    if not tool_calls:
        print(response.output_text)
        break
    for tc in tool_calls:
        result = TOOLS_MAP[tc.name](**json.loads(tc.arguments))
        input_items.append({
            "type": "function_call_output",
            "call_id": tc.call_id,
            "output": json.dumps(result),
        })

External links

Exercise

Build a tool loop with 3 fake tools: get_weather, get_news, get_calendar. Cap iterations at 5. Log the iteration index, the tool called, and the model's reasoning text at each step.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.