← Back to DevBytes

OpenAI Swarm: Lightweight Multi-Agent Orchestration Explained

Introduction to OpenAI Swarm

OpenAI Swarm is an experimental, lightweight framework designed to orchestrate multiple AI agents in a coordinated manner. Released as an open-source research project, Swarm focuses on simplicity and developer ergonomics, providing a minimal abstraction layer over the OpenAI API for building multi-agent systems. Unlike heavier frameworks that impose rigid workflows, Swarm embraces a minimalist philosophy: agents are just functions with instructions, and coordination happens through handoffs.

At its core, Swarm is not a production-grade framework but rather an educational tool that demonstrates how multi-agent orchestration can be both powerful and simple. It ships as a single Python file, making it easy to read, understand, and extend. The framework introduces two primary concepts — Agent and Swarm — and relies on the idea of routine: a combination of instructions and a set of available tools that define what an agent can do.

Why Multi-Agent Orchestration Matters

As language models take on increasingly complex tasks, single-agent architectures begin to show their limitations. A single agent trying to handle customer support, billing inquiries, technical troubleshooting, and account management will inevitably produce bloated, conflicting instructions and degraded performance. Multi-agent orchestration solves this by decomposing complex workflows into specialized agents, each focused on a narrow domain.

Key Benefits of Multi-Agent Systems

Swarm addresses these benefits with an intentionally minimal design. It does not enforce a particular architecture or workflow engine. Instead, it provides the building blocks — agents, handoffs, and context variables — and lets developers compose them freely.

Core Concepts of OpenAI Swarm

The Agent

An Agent in Swarm is a simple data structure that bundles together a name, instructions, and a list of functions it can call. There is no complex state machine or graph. The agent's behavior is entirely determined by its instructions and the tools available to it.

from swarm import Agent

def get_weather(location):
    return f"The weather in {location} is sunny and 72°F."

weather_agent = Agent(
    name="Weather Agent",
    instructions="You are a helpful weather assistant. Always use the get_weather function to answer weather-related questions.",
    functions=[get_weather],
)

The Swarm Client

The Swarm client is the execution engine. It manages the conversation loop, handles function calling, and processes handoffs between agents. It wraps the OpenAI Chat Completions API and adds the orchestration logic on top.

from swarm import Swarm

client = Swarm()

response = client.run(
    agent=weather_agent,
    messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
)

print(response.messages[-1]["content"])

Handoffs

Handoffs are the heart of Swarm's orchestration model. When an agent determines that another agent is better suited to handle the user's request, it returns a different Agent object from one of its functions. The Swarm client detects this and seamlessly switches the active agent, transferring the conversation context.

def transfer_to_billing():
    return billing_agent

support_agent = Agent(
    name="Support Agent",
    instructions="""You are a front-line customer support agent.
    For billing questions, transfer to the billing agent using transfer_to_billing.""",
    functions=[transfer_to_billing],
)

Context Variables

Context variables are a shared state mechanism that allows data to flow between agents and function calls. They act like a mutable dictionary that persists across the conversation and can be read or updated by any function in the swarm.

def update_user_preference(preference, context_variables):
    context_variables["preference"] = preference
    return f"Updated preference to {preference}."

agent = Agent(
    name="Settings Agent",
    instructions="You manage user preferences.",
    functions=[update_user_preference],
)

Installation and Setup

Swarm is distributed via GitHub and can be installed directly using pip. Since it is an experimental framework, it requires Python 3.10 or higher and an OpenAI API key.

# Install from GitHub
pip install git+ssh://git@github.com/openai/swarm.git

# Or via HTTPS
pip install git+https://github.com/openai/swarm.git

Set your OpenAI API key as an environment variable before running any Swarm code:

import os

os.environ["OPENAI_API_KEY"] = "sk-your-api-key-here"

Alternatively, you can export it in your shell:

export OPENAI_API_KEY="sk-your-api-key-here"

Building Your First Multi-Agent System

Let's build a practical customer service system with three agents: a triage agent that routes requests, a billing agent that handles payment issues, and a technical agent that handles product troubleshooting.

Step 1: Define the Specialized Agents

from swarm import Agent, Swarm

client = Swarm()

# --- Billing Agent ---
def process_refund(order_id, context_variables):
    context_variables["last_refund_order"] = order_id
    return f"Refund of ${context_variables.get('refund_amount', '50')} processed for order {order_id}."

def check_balance(context_variables):
    user_id = context_variables.get("user_id", "unknown")
    return f"User {user_id} has a balance of $120.50."

billing_agent = Agent(
    name="Billing Agent",
    instructions="""You are a billing specialist.
    Help customers with refunds, balances, and payment issues.
    Always be professional and confirm actions before processing.""",
    functions=[process_refund, check_balance],
)

Step 2: Define the Technical Agent

def search_kb(query):
    # Simulated knowledge base search
    kb = {
        "login issue": "Try clearing your browser cache and cookies, then attempt to log in again.",
        "slow performance": "Check your internet connection and try disabling browser extensions.",
        "error 500": "This is a server-side issue. Our team has been notified. Please try again in 10 minutes.",
    }
    for key, value in kb.items():
        if key in query.lower():
            return value
    return "No matching article found. Escalating to human support."

technical_agent = Agent(
    name="Technical Agent",
    instructions="""You are a technical support specialist.
    Use search_kb to find solutions to technical problems.
    Provide clear, step-by-step instructions.""",
    functions=[search_kb],
)

Step 3: Define the Triage Agent with Handoffs

def transfer_to_billing():
    return billing_agent

def transfer_to_technical():
    return technical_agent

triage_agent = Agent(
    name="Triage Agent",
    instructions="""You are the first point of contact for customer support.
    Analyze the customer's request and route them to the appropriate specialist:
    - For billing, payments, refunds, or balance questions: use transfer_to_billing
    - For technical issues, bugs, or product problems: use transfer_to_technical
    - For general questions: answer directly.
    Always greet the customer warmly.""",
    functions=[transfer_to_billing, transfer_to_technical],
)

Step 4: Run the Swarm

context_variables = {
    "user_id": "USR-12345",
    "refund_amount": "75",
}

messages = []

# First interaction
messages.append({"role": "user", "content": "Hi, I need a refund for my last order."})
response = client.run(
    agent=triage_agent,
    messages=messages,
    context_variables=context_variables,
)
messages = response.messages
print(f"Active Agent: {response.agent.name}")
print(f"Response: {messages[-1]['content']}")
print(f"Context: {context_variables}")

The response object contains several useful fields:

Step 5: Continue the Conversation

# Continue with the active agent from the previous response
messages.append({"role": "user", "content": "The order ID is ORD-98765."})
response = client.run(
    agent=response.agent,
    messages=messages,
    context_variables=context_variables,
)
messages = response.messages
print(f"Active Agent: {response.agent.name}")
print(f"Response: {messages[-1]['content']}")
print(f"Context: {context_variables}")

Advanced Patterns

Function Returning Another Function (Nested Tool Calls)

Swarm supports agents whose functions return other functions, enabling dynamic tool selection. This is useful when an agent needs to decide which sub-tool to use based on runtime conditions.

def get_shipping_info(order_id):
    return f"Order {order_id} shipped via FedEx. Tracking: 123456789."

def get_order_status(order_id):
    return f"Order {order_id} is currently in transit."

def order_lookup(order_id, query_type):
    if query_type == "shipping":
        return get_shipping_info(order_id)
    elif query_type == "status":
        return get_order_status(order_id)
    return "Unknown query type."

orders_agent = Agent(
    name="Orders Agent",
    instructions="You help customers with order lookups. Use order_lookup with the appropriate query_type.",
    functions=[order_lookup],
)

Streaming Responses

Swarm supports streaming, which is essential for responsive user interfaces. The stream=True parameter returns a generator that yields events as they occur.

stream = client.run(
    agent=triage_agent,
    messages=[{"role": "user", "content": "Hello!"}],
    stream=True,
)

for event in stream:
    if "content" in event:
        print(event["content"], end="", flush=True)
    elif "tool_call" in event:
        print(f"\n[Tool call: {event['tool_call']['name']}]")
    elif "agent" in event:
        print(f"\n[Transferred to: {event['agent'].name}]")

Using Different Models Per Agent

Each agent can use a different model, allowing you to balance cost and capability. Simple routing agents can use a cheaper, faster model while specialized agents use more capable ones.

triage_agent = Agent(
    name="Triage Agent",
    model="gpt-4o-mini",
    instructions="Route customers to the right agent.",
    functions=[transfer_to_billing, transfer_to_technical],
)

billing_agent = Agent(
    name="Billing Agent",
    model="gpt-4o",
    instructions="You handle sensitive billing operations with precision.",
    functions=[process_refund, check_balance],
)

Best Practices

Write Clear, Specific Instructions

Agent instructions are the primary mechanism for controlling behavior. Be explicit about when to use tools, when to hand off, and how to format responses. Vague instructions lead to unpredictable agent behavior.

# Poor instructions
instructions="Help customers."

# Better instructions
instructions="""You are a billing specialist for an e-commerce platform.
- Always verify the order ID before processing any refund.
- Use process_refund for refund requests.
- Use check_balance when customers ask about their account balance.
- If a customer asks a non-billing question, explain that you can only help with billing.
- Be concise but friendly. Confirm all actions before executing them."""

Keep Agents Focused

Resist the temptation to give an agent too many responsibilities. If an agent's instruction set grows beyond a page, consider splitting it into multiple agents with handoffs. Focused agents produce more reliable results.

Use Context Variables for Shared State

Context variables are the recommended way to share information between agents. Avoid encoding state in the conversation history, as this is fragile and can be lost during handoffs.

def authenticate_user(email, context_variables):
    # Simulated authentication
    user_id = "USR-" + email.split("@")[0].upper()
    context_variables["user_id"] = user_id
    context_variables["authenticated"] = True
    return f"User authenticated. ID: {user_id}"

def get_account_info(context_variables):
    if not context_variables.get("authenticated"):
        return "User not authenticated. Please authenticate first."
    return f"Account info for {context_variables['user_id']}: Premium plan, 3 active subscriptions."

Design Handoffs Carefully

Handoffs should be unidirectional and intentional. Avoid circular handoffs where agents bounce a user back and forth. Include clear conditions in the triage agent's instructions about when to transfer, and make sure specialized agents know not to transfer back unless absolutely necessary.

Test with Real Scenarios

Multi-agent systems can behave unpredictably when agents misinterpret user intent. Build a test suite of realistic conversation flows and verify that the triage agent routes correctly, context variables propagate properly, and handoffs complete without losing information.

test_cases = [
    {"input": "I want a refund", "expected_agent": "Billing Agent"},
    {"input": "The app keeps crashing", "expected_agent": "Technical Agent"},
    {"input": "What are your business hours?", "expected_agent": "Triage Agent"},
]

for test in test_cases:
    response = client.run(
        agent=triage_agent,
        messages=[{"role": "user", "content": test["input"]}],
    )
    assert response.agent.name == test["expected_agent"], \
        f"Expected {test['expected_agent']}, got {response.agent.name}"
    print(f"PASS: '{test['input']}' -> {response.agent.name}")

Handle Errors Gracefully

Function calls can fail. Wrap tool functions in try-except blocks and return user-friendly error messages. Swarm will pass the function result back to the agent, which can then decide how to respond.

def fetch_order(order_id):
    try:
        # Simulated API call
        if not order_id.startswith("ORD-"):
            return "Invalid order ID format. Order IDs start with 'ORD-'."
        return f"Order {order_id}: 2 items, total $89.99, status: delivered."
    except Exception as e:
        return f"Unable to fetch order: {str(e)}. Please try again."

Limitations and Considerations

It is important to understand that Swarm is explicitly an experimental framework. OpenAI states that it is intended for educational purposes and is not recommended for production use. Some key limitations include:

For production systems, consider more mature frameworks like OpenAI's Assistants API, LangGraph, or CrewAI, which offer persistence, guardrails, and more sophisticated orchestration patterns. However, Swarm remains an excellent learning tool for understanding the fundamentals of multi-agent coordination.

Conclusion

OpenAI Swarm demonstrates that multi-agent orchestration does not have to be complex. By combining simple agents with handoff functions and shared context variables, developers can build sophisticated conversational systems that decompose complex tasks into manageable pieces. The framework's minimalist design makes it an ideal starting point for understanding multi-agent patterns, even if you eventually move to a more robust solution for production. The key takeaways are clear: keep agents focused, write explicit instructions, use handoffs for routing, leverage context variables for shared state, and test thoroughly with realistic scenarios. Whether you use Swarm directly or apply its concepts within another framework, the principles of lightweight orchestration it teaches will make you a more effective builder of AI-powered applications.

— Ad —

Google AdSense will appear here after approval

← Back to all articles