Skip to main content
Lesson 5 of 25 · Building OpenAI Agents

SDK Anatomy: Agent, Runner, Tool, Guardrail

Lesson 5 of 25 Updated November 2, 2026 Developer
On this page
  1. SDK Anatomy: Agent, Runner, Tool, Guardrail
  2. Agent: Configuration
  3. Runner: Execution
  4. Tool: Capabilities
  5. Guardrail: Safety
  6. How these pieces interact
  7. Key takeaways

SDK Anatomy: Agent, Runner, Tool, Guardrail

The Agents SDK rests on four core concepts: Agent, Runner, Tool, and Guardrail. Each has a single responsibility. Their interplay—who decides, who executes, who acts, who controls—is what makes the SDK readable once you internalize it.

1

Agent — The brain

Defines instructions, model, tools, and guardrails. This is your agent's configuration.

2

Runner — The execution engine

Orchestrates the reasoning loop: sends requests, executes tools, and handles handoffs.

3

Tool — Capabilities

Functions the agent can call: web search, code execution, API calls, and more.

4

Guardrail — Safety

Validates agent inputs and outputs. Blocks dangerous or off-topic requests.

Agent: Configuration

The Agent class is purely declarative: it doesn’t run anything; it describes. Everything that defines your agent’s behavior lives in one place.

from agents import Agent, function_tool, WebSearchTool

@function_tool
def get_price(product: str) -> str:
    """Retrieves the price of a product."""
    prices = {"widget": "€29.99", "gadget": "€49.99"}
    return prices.get(product, "Unknown product")

agent = Agent(
    name="Sales Agent",
    instructions="""You are a sales agent for an online store.
    Help customers find products and learn their prices.
    Always respond in French with a professional tone.""",
    model="gpt-5.6-terra",
    tools=[get_price, WebSearchTool()],
    handoff_description="Agent specialized in selling products",
    output_type=None,  # or a Pydantic type to enforce an output format
)

Key Agent parameters:

  • name: Human-readable identifier for the agent
  • instructions: The system prompt that defines behavior
  • model: The model to use (gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna)
  • tools: The list of available tools
  • handoff_description: Description used for handoffs between agents
  • output_type: Pydantic type to structure the output

Runner: Execution

The Runner is the engine that runs your agent. It manages the full loop and comes in three modes depending on your calling context.

from agents import Runner

# Synchronous mode (development)
result = Runner.run_sync(agent, "What is the price of the widget?")

# Asynchronous mode (production)
result = await Runner.run(agent, "What is the price of the widget?")

# Streaming mode (real time)
result = Runner.run_streamed(agent, "What is the price of the widget?")

Regardless of mode, you get back a RunResult, which contains far more than the displayable response. The full history lets you resume a conversation, and last_agent becomes essential as soon as multiple agents hand off to one another.

result = Runner.run_sync(agent, "What is the price of the widget?")

# The agent's final response
print(result.final_output)

# The complete conversation history
print(result.to_input_list())

# The last active agent (useful with handoffs)
print(result.last_agent.name)

Tool: Capabilities

The SDK supports three ways to declare tools, from most common to most architectural.

1. Function tools (most common)

A decorated Python function becomes a tool; the SDK infers the schema from the signature and docstring.

from agents import function_tool

@function_tool
def send_email(recipient: str, subject: str, body: str) -> str:
    """Sends an email to a recipient."""
    # Your sending logic here
    return f"Email sent to {recipient}"

2. Tools hosted by OpenAI

These tools run on OpenAI’s side: you don’t write the search logic or the Python sandbox.

from agents import WebSearchTool, FileSearchTool, CodeInterpreterTool

tools = [
    WebSearchTool(),                               # Web search
    FileSearchTool(vector_store_ids=["vs_123"]),   # File search
    CodeInterpreterTool(tool_config={"type": "code_interpreter", "container": {"type": "auto"}}),                          # Code execution
]

3. Agents as tools

One agent can use another as a tool. The coordinator below delegates research without ever ceding control of the conversation, which distinguishes this from a handoff.

search_agent = Agent(
    name="Researcher",
    instructions="You look up precise information.",
    tools=[WebSearchTool()],
)

primary_agent = Agent(
    name="Coordinator",
    instructions="You coordinate research.",
    tools=[search_agent.as_tool(
        tool_name="search",
        tool_description="Performs in-depth research"
    )],
)

Guardrail: Safety

A guardrail is a control agent placed in front of your business agent. Here, a verifier checks whether the request falls within sales before the sales agent responds.

from agents import Agent, InputGuardrail, GuardrailFunctionOutput, Runner

guardrail_agent = Agent(
    name="Verifier",
    instructions="Determine whether the request concerns sales. Respond true or false.",
    output_type=bool,
)

async def verify_topic(ctx, agent, input_data):
    result = await Runner.run(guardrail_agent, input_data, context=ctx)
    return GuardrailFunctionOutput(
        output_info=result.final_output,
        tripwire_triggered=not result.final_output,
    )

protected_agent = Agent(
    name="Protected Sales Agent",
    instructions="You are a sales agent.",
    input_guardrails=[
        InputGuardrail(guardrail_function=verify_topic),
    ],
)

If the guardrail trips (tripwire_triggered=True), execution stops and an InputGuardrailTripwireTriggered exception is raised. Plan to catch this in your application; otherwise, you’ll return a 500 error to a user who simply asked an off-topic question.

How these pieces interact

The full flow runs as follows:

  1. You call Runner.run(agent, message)
  2. The Runner checks input guardrails
  3. The Runner sends the message to the Agent’s model
  4. If the model requests a tool, the Runner executes it
  5. The Runner returns the result to the model (back to step 3)
  6. When the model produces a final response, the Runner checks output guardrails
  7. The RunResult is returned

Key takeaways

  • Agent defines behavior (instructions, model, tools)
  • Runner orchestrates the agent loop execution
  • Declare tools with @function_tool, built-in classes, or .as_tool()
  • Guardrails validate inputs and outputs for safety
  • RunResult holds the final response and the complete history