Building Multi-Agent Systems with OpenAI Agents SDK v2.0

OpenAIAgents SDKMulti-AgentTutorialv2.0

Build production-ready multi-agent systems with OpenAI Agents SDK v2.0, covering handoffs, guardrails, tool caching, and TypeScript support.

Building Multi-Agent Systems with OpenAI Agents SDK v2.0

Overview

OpenAI Agents SDK v2.0, released in June 2026, represents a significant leap forward in multi-agent orchestration. Building on the v1.0 foundation, v2.0 introduces advanced guardrails, enhanced TypeScript support, new orchestration patterns, and improved tool calling with automatic retry and caching.

This tutorial walks you through building production-ready multi-agent systems using OpenAI Agents SDK v2.0, from basic agent handoffs to complex multi-agent teams with guardrails and observability.


What's New in v2.0

Featurev1.0v2.0
GuardrailsBasicAdvanced with policy engine
TypeScriptBetaFull parity with Python
HandoffsManualStructured with context passing
Tool CachingNoneAutomatic LRU cache
ObservabilityLogsTraces + metrics + dashboards
Session StateIn-memoryPersistent with Redis/SQLite backends

Installation

# Python
pip install openai-agents>=2.0.0

# TypeScript
npm install @openai/agents@2.0.0

Core Concepts

1. Agents and Handoffs

Agents are the building blocks. In v2.0, agents can hand off to each other with structured context:

from openai.agents import Agent, handoff, RunContextWrapper

class ResearchAgent(Agent):
    def __init__(self):
        super().__init__(
            name="researcher",
            instructions="You research topics thoroughly.",
            handoffs=[WriterAgent()],
        )

class WriterAgent(Agent):
    def __init__(self):
        super().__init__(
            name="writer",
            instructions="You write clear, engaging content based on research findings.",
        )

async def research_and_write(topic: str):
    result = await ResearchAgent().run(
        user_input=f"Research this topic: {topic}"
    )
    return result.final_output

2. Guardrails

v2.0 introduces policy-based guardrails for input validation, output filtering, and tool access control:

from openai.agents.guardrails import Guardrail, GuardrailPolicy

class ContentGuardrail(Guardrail):
    async def run(self, context, input_text):
        if "internal" in input_text.lower():
            return GuardrailResult(
                action="block",
                message="Access denied: internal content detected."
            )
        return GuardrailResult(action="allow")

policy = GuardrailPolicy(
    input_guardrails=[ContentGuardrail()],
    output_guardrails=[ContentGuardrail()],
)

agent = Agent(
    name="safe-agent",
    guardrail_policy=policy,
)

3. Tool Caching

Tools are automatically cached based on their arguments, reducing redundant API calls:

from openai.agents import Agent, tool, ToolCache

@tool(cache_ttl=300)  # 5-minute cache
async def fetch_weather(city: str):
    response = await http_get(f"https://api.weather.com/{city}")
    return response.json()

agent = Agent(
    name="weather-agent",
    tools=[fetch_weather],
)

Building a Multi-Agent Research System

Let's build a system with three agents: Researcher, Analyst, and Writer.

from openai.agents import Agent, handoff, Runner, TetherResult

class ResearchAgent(Agent):
    def __init__(self):
        super().__init__(
            name="researcher",
            instructions=(
                "You search the web and gather information. "
                "When you have enough information, hand off to the analyst."
            ),
            handoffs=[AnalystAgent()],
            tools=[search_web],
        )

class AnalystAgent(Agent):
    def __init__(self):
        super().__init__(
            name="analyst",
            instructions=(
                "You analyze the research findings and extract key insights. "
                "When analysis is complete, hand off to the writer."
            ),
            handoffs=[WriterAgent()],
        )

class WriterAgent(Agent):
    def __init__(self):
        super().__init__(
            name="writer",
            instructions="You write a comprehensive report based on the analysis.",
        )

async def run_research_pipeline(topic: str):
    result = await Runner.run(
        first_agent=ResearchAgent(),
        user_input=f"Research: {topic}",
        max_handoffs=3,
    )
    return result.final_output

Advanced Patterns

1. Conditional Handoffs

Route to different agents based on input:

async def router_handoff(context, input_text):
    if "code" in input_text:
        return CodeAgent()
    if "data" in input_text:
        return DataAgent()
    return GeneralAgent()

main_agent = Agent(
    name="router",
    handoffs=[router_handoff],
)

2. Parallel Agent Execution

Run agents concurrently with v2.0's parallel_run:

from openai.agents import parallel_run

results = await parallel_run(
    agents=[SummarizerAgent(), TranslatorAgent(), FactCheckerAgent()],
    user_input=article,
)

3. Persistent Session State

v2.0 supports persistent session state across runs:

from openai.agents import Runner, SessionState, RedisStateStore

state_store = RedisStateStore(url="redis://localhost:6379")

result = await Runner.run(
    first_agent=Agent(name="stateful-agent"),
    user_input="hello",
    session_state=SessionState(
        id="user-123",
        store=state_store,
    ),
)

TypeScript Support

v2.0 brings full TypeScript parity with Python:

import { Agent, Runner, tool } from "@openai/agents";

const weatherTool = tool({
  name: "getWeather",
  parameters: { type: "object", properties: { city: { type: "string" } } },
  execute: async ({ city }) => {
    const res = await fetch(`https://api.weather.com/${city}`);
    return res.json();
  },
  cache: { ttl: 300 },
});

const agent = new Agent({
  name: "weather-agent",
  tools: [weatherTool],
});

const result = await Runner.run({
  firstAgent: agent,
  userInput: "What's the weather in Tokyo?",
});

Observability & Debugging

v2.0 integrates with OpenAI's observability dashboard:

from openai.agents import Runner, TraceConfig

result = await Runner.run(
    first_agent=ResearchAgent(),
    user_input="Research AGI",
    trace_config=TraceConfig(
        record_tool_calls=True,
        record_handoffs=True,
        log_level="debug",
    ),
)

Pros

  • ✅ Advanced guardrails with policy engine
  • ✅ Full TypeScript parity with Python
  • ✅ Automatic tool caching reduces costs
  • ✅ Persistent session state with Redis/SQLite
  • ✅ Built-in observability with traces and metrics
  • ✅ Official OpenAI support with guaranteed API compatibility

Cons

  • ❌ OpenAI ecosystem lock-in
  • ❌ v2.0 is still new with less community content
  • ❌ Advanced features require paid OpenAI tier
  • ❌ No native multi-provider support (unlike PydanticAI)

When to Use

  • Building production multi-agent systems
  • Need OpenAI's latest model capabilities
  • Want built-in observability and guardrails
  • Team prefers TypeScript or Python

Resources