Back
intermediate

Agentic AI Frameworks

OpenAI Agents SDK: inspect the runner loop

Use a narrow tool, bound model turns, and distinguish handoffs, history, and tracing.

Lesson 29 of 44About 30 min with practice

What happens between an agent asking for a tool and the user receiving an answer? The OpenAI Agents SDK makes that loop explicit enough to inspect without writing every message exchange yourself.

Before you begin: Complete the ADK example or understand Python functions, API keys, and the agent loop.

Give each part one job

An Agent describes instructions, a model, and available capabilities. A Runner executes the interaction. A tool connects the run to an application function. The SDK can manage the sequence, but a tool description does not enforce authorization or establish that returned text is true.

We will reuse the fictional workshop catalog. This time, focus on the runner: a model turn can produce a final answer, a tool request, or a handoff to another agent. A handoff changes which agent continues the conversation. Calling an agent as a tool can leave the original agent responsible for the final answer. These are different control flows, not different levels of intelligence.

Run one read-only experiment

This complete integration script follows the official SDK documentation reviewed on September 10, 2026. Install openai-agents in an isolated Python environment supported by its current package requirements. Set OPENAI_API_KEY and OPENAI_MODEL to an available model with tool support. External model execution is not claimed as tested here.

The current quickstart uses tool from agents.decorators. If you maintain an older installation, follow that installed version's API rather than mixing imports from tutorials written for different releases.

python
import asyncio
import os
from agents import Agent, Runner
from agents.decorators import tool

@tool
def read_capacity(workshop_id: str) -> dict:
    """Read fixed capacity from a fictional catalog; no availability data."""
    if workshop_id != "W1":
        return {"status": "not_found"}
    return {"status": "found", "id": "W1", "capacity": 12}

async def main():
    agent = Agent(
        name="Catalog reader",
        model=os.environ["OPENAI_MODEL"],
        instructions=(
            "Use the catalog tool for capacity. Cite the workshop ID. "
            "Do not infer remaining seats from capacity."
        ),
        tools=[read_capacity],
    )
    result = await Runner.run(
        agent, "What is the capacity of W1?", max_turns=3
    )
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())

Three model turns are a limit for this experiment, not a recommended universal setting. Exceeding the limit raises an SDK error. It is not a count of every tool call or a total currency budget. A real service also needs a deadline, tool-specific timeouts, and an intelligible failure response.

Decide what the next request can remember

Run the script twice. The second process does not automatically inherit the first conversation. You must deliberately pass previous input items, configure a session, or choose an appropriate provider-managed continuation mechanism. Bind stored conversations to the authenticated user in your application.

Tracing records how a run unfolded. The SDK documents tracing as enabled by default and offers controls, including OPENAI_AGENTS_DISABLE_TRACING=1. Decide which data may enter traces before using real learner conversations. A trace is for diagnosis; it is not your product's durable lesson-progress record.

Predict the failure boundary

Change the question to “Book every remaining seat.” The only tool reads capacity. What outcome is acceptable? What evidence would reveal a bug?

Inspect the expected behavior

The answer should explain that neither availability nor booking is supported. A claim that a booking was completed is a failure even if the run ended normally. Check actual tool events and the response together. The absence of a write tool limits what the program can do, but it does not prevent the model from making an unsupported claim.

Now lower max_turns to one and ask the capacity question. A tool lookup may require a later model turn to turn its result into an answer. Handle that limit as an incomplete run. This experiment shows why budgets must match the intended path.

Next, examine a framework that organizes work into named tasks and roles, and ask whether that extra structure helps this same problem.

Sources

SDK quickstart, runner lifecycle, and tracing controls document the APIs and distinctions used here.

Continue to the next lesson.

Practice for this lesson

Predict the runner loop's failure boundary

Give each part one job and decide what the next request remembers.

About 10 min55 points3 checks and one written task
Loading your lesson progress...