Agent definitions
An agent is the core unit of an SDK-based workflow. It packages a model, instructions, and optional runtime behavior such as tools, guardrails, MCP servers, handoffs, and structured outputs.
What belongs on an agent
Use agent configuration for decisions that are intrinsic to that specialist:
| Property | Use it for | Read next |
|---|---|---|
name | Human-readable identity in traces and tool/handoff surfaces | This page |
instructions | The job, constraints, and style for that agent | This page |
prompt | Stored prompt configuration for Responses-based runs | Models and providers |
model and model settings | Choosing the model and tuning behavior | Models and providers |
tools | Capabilities the agent can call directly | Using tools |
| Hinting when another agent should delegate here | Orchestration and handoffs | |
handoffs | Delegating to another agent | Orchestration and handoffs |
| Returning structured output instead of plain text | This page | |
| Guardrails and approvals | Validation, blocking, and review flows | Guardrails and human review |
| MCP servers and hosted MCP tools | Attaching MCP-backed capabilities | Integrations and observability |
Start with one focused agent
Define the smallest agent that can own a clear task. Add more agents only when you need separate ownership, different instructions, different tool surfaces, or different approval policies.
Define a single agent
import { Agent, tool } from "@openai/agents";
import { z } from "zod";
const getWeather = tool({
name: "get_weather",
description: "Return the weather for a given city.",
parameters: z.object({ city: z.string() }),
async execute({ city }) {
return \`The weather in \${city} is sunny.\`;
},
});
const agent = new Agent({
name: "Weather bot",
instructions: "You are a helpful weather bot.",
model: "gpt-5.4",
tools: [getWeather],
});
from agents import Agent, function_tool
@function_tool
def get_weather(city: str) -> str:
"""Return the weather for a given city."""
return f"The weather in {city} is sunny."
agent = Agent(
name="Weather bot",
instructions="You are a helpful weather bot.",
model="gpt-5.4",
tools=[get_weather],
)
Shape instructions, handoffs, and outputs
Three configuration choices deserve extra care:
- Start with static
instructions. When the guidance depends on the current user, tenant, or runtime context, switch to a dynamic instructions callback instead of stitching strings together at the call site. - Keep short and concrete so routing agents know when to pick this specialist.
- Use when downstream code needs typed data rather than free-form prose.
Return structured output
import { Agent, run } from "@openai/agents";
import { z } from "zod";
const calendarEvent = z.object({
name: z.string(),
date: z.string(),
participants: z.array(z.string()),
});
const agent = new Agent({
name: "Calendar extractor",
instructions: "Extract calendar events from text.",
outputType: calendarEvent,
});
const result = await run(
agent,
"Dinner with Priya and Sam on Friday.",
);
console.log(result.finalOutput);
import asyncio
from pydantic import BaseModel
from agents import Agent, Runner
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
agent = Agent(
name="Calendar extractor",
instructions="Extract calendar events from text.",
output_type=CalendarEvent,
)
async def main() -> None:
result = await Runner.run(
agent,
"Dinner with Priya and Sam on Friday.",
)
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
Use prompt when you want to reference a stored prompt configuration from the Responses API instead of embedding the entire system prompt in code.
Keep local context separate from model context
The SDK lets you pass application state and dependencies into a run without sending them to the model. Use this for data like authenticated user info, database clients, loggers, and helper functions.
Pass local context to tools
import { Agent, RunContext, run, tool } from "@openai/agents";
import { z } from "zod";
interface UserInfo {
name: string;
uid: number;
}
const fetchUserAge = tool({
name: "fetch_user_age",
description: "Return the age of the current user.",
parameters: z.object({}),
async execute(_args, runContext?: RunContext<UserInfo>) {
return \`User \${runContext?.context.name} is 47 years old\`;
},
});
const agent = new Agent<UserInfo>({
name: "Assistant",
tools: [fetchUserAge],
});
const result = await run(agent, "What is the age of the user?", {
context: { name: "John", uid: 123 },
});
console.log(result.finalOutput);
import asyncio
from dataclasses import dataclass
from agents import Agent, RunContextWrapper, Runner, function_tool
@dataclass
class UserInfo:
name: str
uid: int
@function_tool
async def fetch_user_age(wrapper: RunContextWrapper[UserInfo]) -> str:
"""Fetch the age of the current user."""
return f"The user {wrapper.context.name} is 47 years old."
agent = Agent[UserInfo](
name="Assistant",
tools=[fetch_user_age],
)
async def main() -> None:
result = await Runner.run(
agent,
"What is the age of the user?",
context=UserInfo(name="John", uid=123),
)
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
The important boundary is:
- Conversation history is what the model sees.
- Run context is what your code sees.
If the model needs a fact, put it in instructions, input, retrieval, or a tool. If only your runtime needs it, keep it in local context.
When to split one agent into several
Split an agent when one specialist shouldn't own the full reply or when separate capabilities are materially different. Common reasons are:
- A specialist needs a different tool or MCP surface.
- A specialist needs a different approval policy or guardrail.
- One branch of the workflow needs a different model or output style.
- You want explicit routing in traces rather than a single large prompt.
Next steps
Once one specialist is defined cleanly, move to the guide that matches the next design question.
<div class="not-prose mt-4 grid gap-3"> <a href="/api/docs/guides/agents/models" class="block no-underline hover:no-underline" > <span slot="icon"> </span> Choose models, defaults, and transport strategy for this agent. </a> <a href="/api/docs/guides/tools#usage-in-the-agents-sdk" class="block no-underline hover:no-underline" > <span slot="icon"> </span> Add capabilities the agent can call directly. </a> <a href="/api/docs/guides/agents/orchestration" class="block no-underline hover:no-underline" > <span slot="icon"> </span> Choose how specialists collaborate once one agent is no longer enough. </a> <a href="/api/docs/guides/agents/running-agents" class="block no-underline hover:no-underline" > <span slot="icon"> </span> Understand the runtime loop, state, and streaming behavior. </a> </div>