this second installment of the Arms-On with Brokers SDK sequence, we’ll discover the fundamentals of multi-agent techniques and the way brokers can collaborate utilizing the OpenAI Brokers SDK framework.
In the event you haven’t learn the primary article, I extremely advocate checking it out right here: Your First API‑Calling Agent. In that put up, we began by constructing a easy agent and enhanced it right into a instrument‑utilizing agent able to retrieving actual‑time climate information. We additionally wrapped the agent in a minimal Streamlit interface for person interplay.
Now, we take the following step. As a substitute of counting on a single climate specialist agent, we’ll introduce one other agent and learn to make them work collectively to grasp and fulfill person queries extra successfully.
Intro to Multi-Agent Techniques
Let’s begin with a elementary query: why do we’d like a number of brokers when a single agent—just like the one we constructed within the earlier article—already appears highly effective sufficient to deal with the duty?
There are a number of sensible and theoretical causes for adopting a multi-agent system [1]. Every agent can concentrate on a selected area and make the most of its personal instruments, which might result in higher efficiency and higher-quality outcomes. In real-world purposes, enterprise processes are sometimes advanced. A multi-agent setup is usually extra modular, manageable, and maintainable. For instance, if a selected perform must be up to date, we are able to modify only one agent as an alternative of altering your complete system.
The OpenAI Brokers SDK gives two core patterns for enabling agent collaboration: handoff and agent-as-tools. On this article, we’ll discover each of those patterns, talk about when to make use of them, and present how one can customise them to realize higher outcomes.
Handoff
Handoff is without doubt one of the key options of the Brokers SDK framework. With handoff, an agent can delegate a process to a different agent [2]. To make this idea clearer, think about a typical course of in a hospital.
Let’s say you’re experiencing a well being concern and go to the hospital for a check-up. The primary particular person you normally meet will not be the physician, however a triage nurse. The triage nurse collects related data from you after which directs you to the suitable division or specialist.
This analogy intently mirrors how handoff works within the Brokers SDK. In our case, we’ll have a triage agent that “examines” the person’s question. After evaluating it, the triage agent routes the question to a extra appropriate specialist agent. Identical to a triage nurse, it fingers off the total context (like your collected well being information) to that specialist agent.
This sample is usually utilized in real-world purposes similar to customer support workflows, the place a basic agent receives an preliminary request after which routes it to a domain-specific skilled agent for decision. In our climate assistant instance, we’ll implement an identical setup.
As a substitute of getting just one climate specialist agent, we are going to introduce one other agent: an air high quality specialist. Because the identify suggests, this agent will give attention to answering air quality-related queries for a given location and might be outfitted with a instrument to fetch real-time air high quality information.
Fundamental Handoffs
Let’s dive into the code by creating a brand new file named 04-basic-handoff-app.py
. First, we’ll import the required packages, identical to we did within the earlier article.
from brokers import Agent, Runner, function_tool
import asyncio
import streamlit as st
from dotenv import load_dotenv
import requests
load_dotenv()
Subsequent, we outline the perform instrument and the climate specialist agent utilizing the identical construction as within the earlier article:
@function_tool
def get_current_weather(latitude: float, longitude: float) -> dict:
...
weather_specialist_agent = Agent(
identify="Climate Specialist Agent",
...
)
On this script, as mentioned above, we are going to outline a brand new Air High quality Specialist agent with a instrument named get_current_air_quality
. This instrument makes use of a special API endpoint and metrics from Open-Meteo, but it surely takes the identical parameters—latitude and longitude.
The agent itself is outlined equally to the earlier Climate Specialist agent, with the important thing distinction being within the directions—to make sure relevance to air high quality queries. Under is the code snippet for the Air High quality Specialist agent.
@function_tool
def get_current_air_quality(latitude: float, longitude: float) -> dict:
"""Fetch present air high quality information for the given latitude and longitude."""
url = "https://air-quality-api.open-meteo.com/v1/air-quality"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "european_aqi,us_aqi,pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,sulphur_dioxide,ozone",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
air_quality_specialist_agent = Agent(
identify="Air High quality Specialist Agent",
directions="""
You might be an air high quality specialist agent.
Your position is to interpret present air high quality information and talk it clearly to customers.
For every question, present:
1. A concise abstract of the air high quality situations in plain language, together with key pollution and their ranges.
2. Sensible, actionable recommendation or precautions for out of doors actions, journey, and well being, tailor-made to the air high quality information.
3. If poor or hazardous air high quality is detected (e.g., excessive air pollution, allergens), clearly spotlight really useful security measures.
Construction your response in two sections:
Air High quality Abstract:
- Summarize the air high quality situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the air high quality.
""",
instruments=[get_current_air_quality],
tool_use_behavior="run_llm_again"
)
Now that we now have two brokers—the Climate Specialist and the Air High quality Specialist—the following step is to outline the Triage Agent, which can consider the person’s question and resolve which agent handy off the duty to.
The Triage Agent will be outlined merely as follows:
triage_agent = Agent(
identify="Triage Agent",
directions="""
You're a triage agent.
Your process is to find out which specialist agent (Climate Specialist or Air High quality Specialist) is greatest suited to deal with the person's question based mostly on the content material of the query.
For every question, analyze the enter and resolve:
- If the question is about climate situations, route it to the Climate Specialist Agent.
- If the question is about air high quality, route it to the Air High quality Specialist Agent.
- If the question is ambiguous or doesn't match both class, present a clarification request.
""",
handoffs=[weather_specialist_agent, air_quality_specialist_agent]
)
Within the directions
argument, we offer a transparent directive for this agent to find out which specialist agent is greatest suited to deal with the person’s question.
A very powerful parameter right here is handoffs
, the place we go an inventory of brokers that the duty could also be delegated to. Since we at the moment have solely two brokers, we embrace each within the checklist.
Lastly, we outline our run_agent
and foremost
features to combine with the Streamlit parts. (Be aware: For an in depth rationalization of those features, please consult with the primary article.)
async def run_agent(user_input: str):
consequence = await Runner.run(triage_agent, user_input)
return consequence.final_output
def foremost():
st.title("Climate and Air High quality Assistant")
user_input = st.text_input("Enter your question about climate or air high quality:")
if st.button("Get Replace"):
with st.spinner("Pondering..."):
if user_input:
agent_response = asyncio.run(run_agent(user_input))
st.write(agent_response)
else:
st.write("Please enter a query in regards to the climate or air high quality.")
if __name__ == "__main__":
foremost()
Full script for our handoff script will be seen right here.
from brokers import Agent, Runner, function_tool
import asyncio
import streamlit as st
from dotenv import load_dotenv
import requests
load_dotenv()
@function_tool
def get_current_weather(latitude: float, longitude: float) -> dict:
"""Fetch present climate information for the given latitude and longitude."""
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation,weathercode,windspeed_10m,winddirection_10m",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
weather_specialist_agent = Agent(
identify="Climate Specialist Agent",
directions="""
You're a climate specialist agent.
Your process is to investigate present climate information, together with temperature, humidity, wind pace and route, precipitation, and climate codes.
For every question, present:
1. A transparent, concise abstract of the present climate situations in plain language.
2. Sensible, actionable options or precautions for out of doors actions, journey, well being, or clothes, tailor-made to the climate information.
3. If extreme climate is detected (e.g., heavy rain, thunderstorms, excessive warmth), clearly spotlight really useful security measures.
Construction your response in two sections:
Climate Abstract:
- Summarize the climate situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the climate.
""",
instruments=[get_current_weather],
tool_use_behavior="run_llm_again"
)
@function_tool
def get_current_air_quality(latitude: float, longitude: float) -> dict:
"""Fetch present air high quality information for the given latitude and longitude."""
url = "https://air-quality-api.open-meteo.com/v1/air-quality"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "european_aqi,us_aqi,pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,sulphur_dioxide,ozone",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
air_quality_specialist_agent = Agent(
identify="Air High quality Specialist Agent",
directions="""
You might be an air high quality specialist agent.
Your position is to interpret present air high quality information and talk it clearly to customers.
For every question, present:
1. A concise abstract of the air high quality situations in plain language, together with key pollution and their ranges.
2. Sensible, actionable recommendation or precautions for out of doors actions, journey, and well being, tailor-made to the air high quality information.
3. If poor or hazardous air high quality is detected (e.g., excessive air pollution, allergens), clearly spotlight really useful security measures.
Construction your response in two sections:
Air High quality Abstract:
- Summarize the air high quality situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the air high quality.
""",
instruments=[get_current_air_quality],
tool_use_behavior="run_llm_again"
)
triage_agent = Agent(
identify="Triage Agent",
directions="""
You're a triage agent.
Your process is to find out which specialist agent (Climate Specialist or Air High quality Specialist) is greatest suited to deal with the person's question based mostly on the content material of the query.
For every question, analyze the enter and resolve:
- If the question is about climate situations, route it to the Climate Specialist Agent.
- If the question is about air high quality, route it to the Air High quality Specialist Agent.
- If the question is ambiguous or doesn't match both class, present a clarification request.
""",
handoffs=[weather_specialist_agent, air_quality_specialist_agent]
)
async def run_agent(user_input: str):
consequence = await Runner.run(triage_agent, user_input)
return consequence.final_output
def foremost():
st.title("Climate and Air High quality Assistant")
user_input = st.text_input("Enter your question about climate or air high quality:")
if st.button("Get Replace"):
with st.spinner("Pondering..."):
if user_input:
agent_response = asyncio.run(run_agent(user_input))
st.write(agent_response)
else:
st.write("Please enter a query in regards to the climate or air high quality.")
if __name__ == "__main__":
foremost()
Run the script in your terminal utilizing the next command:
streamlit run 04-basic-handoff-app.py
Now that we now have a model new air high quality specialist agent, let’s ask in regards to the air high quality in Jakarta.

Sadly, on the time of writing this text (and very often, really), the report exhibits an unhealthy air high quality stage, together with some options for coping with the situation.
Checking Hint Dashboard
Recall that within the first article, I briefly shared in regards to the built-in tracing characteristic within the Brokers SDK. In multi-agent collaboration, this characteristic turns into much more helpful in comparison with after we had been nonetheless working with a easy, single agent.
Let’s check out the hint dashboard for the question we simply ran.

We are able to see that the method concerned two brokers: the triage agent and the air high quality specialist agent. The triage agent took a complete of 1,690 ms, whereas the air high quality agent took 7,182 ms to course of and return the consequence.
If we click on on the triage agent’s response part, we are able to view detailed LLM properties, as proven under. Discover that for the triage agent, the LLM views the handoff choices as features: transfer_to_weather_specialist_agent()
and transfer_to_air_quality_specialist_agent()
. That is how the handoff works below the hood—the LLM decides which perform most accurately fits the person’s question.

For the reason that instance requested about air high quality, the perform triggered by the triage agent was transfer_to_air_quality_specialist_agent()
, which seamlessly transferred management to the Air High quality Specialist agent.

You possibly can strive asking in regards to the climate as an alternative of air high quality and examine the hint dashboard to see the distinction.
Personalized Handoffs
We perceive already that below the hood handoffs are seen by LLM as perform, this implies additionally that we are able to customise handoffs for some elements.
To customise a handoff, we are able to create a handoff object utilizing handoff()
perform and specify half the place we need to customise within the arguments, together with; customizing instrument identify and outline, operating further logic instantly on handoff, and passing a structured enter to the specialist agent.
Let’s see the way it works on our use-case under. For a cleaner reference, let’s duplicate earlier script of handoff and identify the brand new file as 05-customized-handoff-app.py
.
Since we are going to create a handoff object utilizing handoff()
perform, we have to add handoff
and RunContextWrapper
perform from brokers
bundle as under:
from brokers import Agent, Runner, function_tool, handoff, RunContextWrapper
import asyncio
import streamlit as st
from dotenv import load_dotenv
import requests
load_dotenv()
After we imported the required bundle, subsequent is to outline perform instruments and brokers as newest script:
@function_tool
def get_current_weather(latitude: float, longitude: float) -> dict:
...
weather_specialist_agent = Agent(
identify="Climate Specialist Agent",
...
)
@function_tool
def get_current_air_quality(latitude: float, longitude: float) -> dict:
...
air_quality_specialist_agent = Agent(
...
)
Now let’s add two handoff objects. We’ll add customization step-by-step from the only one.
Device Identify and Description Override
weather_handoff = handoff(
agent=weather_specialist_agent,
tool_name_override="handoff_to_weather_specialist",
tool_description_override="Deal with queries associated to climate situations"
)
air_quality_handoff = handoff(
agent=air_quality_specialist_agent,
tool_name_override="handoff_to_air_quality_specialist",
tool_description_override="Deal with queries associated to air high quality situations"
)
Above code exhibits the primary customization that we apply for each of brokers the place we modify the instrument identify and outline for LLM visibility. Typically this variation not affecting how the LLM response the question however solely present us a approach to have a transparent and extra particular instrument identify and outline slightly then the default transfer_to_
.
Add Callback Operate
Probably the most use-case for callback perform with handoff
is to log the handoff occasion or displaying it within the UI. Let’s say on the app you need to let the person know at any time when the triage agent handoffs the question to one of many specialist agent.
First let’s outline the callback perform with the intention to name Streamlit’s data element that inform handoff occasion then add this perform in on_handoff
properties on each of the handoff objects.
def on_handoff_callback(ctx):
st.data(f"Handing off to specialist agent for additional processing...")
weather_handoff = handoff(
agent=weather_specialist_agent,
tool_name_override="get_current_weather",
tool_description_override="Deal with queries associated to climate situations",
on_handoff=on_handoff_callback
)
air_quality_handoff = handoff(
agent=air_quality_specialist_agent,
tool_name_override="get_current_air_quality",
tool_description_override="Deal with queries associated to air high quality situations",
on_handoff=on_handoff_callback
)
Let’s take a look at out this, however earlier than operating the script, we have to change the handoffs checklist in triage agent utilizing handoff objects that we simply outlined.
triage_agent = Agent(
identify="Triage Agent",
directions="""
...
""",
handoffs=[weather_handoff, air_quality_handoff]
)
Full script together with Streamlit foremost perform will be seen right here.
from brokers import Agent, Runner, function_tool, handoff, RunContextWrapper
import asyncio
import streamlit as st
from dotenv import load_dotenv
import requests
load_dotenv()
@function_tool
def get_current_weather(latitude: float, longitude: float) -> dict:
"""Fetch present climate information for the given latitude and longitude."""
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation,weathercode,windspeed_10m,winddirection_10m",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
weather_specialist_agent = Agent(
identify="Climate Specialist Agent",
directions="""
You're a climate specialist agent.
Your process is to investigate present climate information, together with temperature, humidity, wind pace and route, precipitation, and climate codes.
For every question, present:
1. A transparent, concise abstract of the present climate situations in plain language.
2. Sensible, actionable options or precautions for out of doors actions, journey, well being, or clothes, tailor-made to the climate information.
3. If extreme climate is detected (e.g., heavy rain, thunderstorms, excessive warmth), clearly spotlight really useful security measures.
Construction your response in two sections:
Climate Abstract:
- Summarize the climate situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the climate.
""",
instruments=[get_current_weather],
tool_use_behavior="run_llm_again"
)
@function_tool
def get_current_air_quality(latitude: float, longitude: float) -> dict:
"""Fetch present air high quality information for the given latitude and longitude."""
url = "https://air-quality-api.open-meteo.com/v1/air-quality"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "european_aqi,us_aqi,pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,sulphur_dioxide,ozone",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
air_quality_specialist_agent = Agent(
identify="Air High quality Specialist Agent",
directions="""
You might be an air high quality specialist agent.
Your position is to interpret present air high quality information and talk it clearly to customers.
For every question, present:
1. A concise abstract of the air high quality situations in plain language, together with key pollution and their ranges.
2. Sensible, actionable recommendation or precautions for out of doors actions, journey, and well being, tailor-made to the air high quality information.
3. If poor or hazardous air high quality is detected (e.g., excessive air pollution, allergens), clearly spotlight really useful security measures.
Construction your response in two sections:
Air High quality Abstract:
- Summarize the air high quality situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the air high quality.
""",
instruments=[get_current_air_quality],
tool_use_behavior="run_llm_again"
)
def on_handoff_callback(ctx):
st.data(f"Handing off to specialist agent for additional processing...")
weather_handoff = handoff(
agent=weather_specialist_agent,
tool_name_override="handoff_to_weather_specialist",
tool_description_override="Deal with queries associated to climate situations",
on_handoff=on_handoff_callback
)
air_quality_handoff = handoff(
agent=air_quality_specialist_agent,
tool_name_override="handoff_to_air_quality_specialist",
tool_description_override="Deal with queries associated to air high quality situations",
on_handoff=on_handoff_callback
)
triage_agent = Agent(
identify="Triage Agent",
directions="""
You're a triage agent.
Your process is to find out which specialist agent (Climate Specialist or Air High quality Specialist) is greatest suited to deal with the person's question based mostly on the content material of the query.
For every question, analyze the enter and resolve:
- If the question is about climate situations, route it to the Climate Specialist Agent.
- If the question is about air high quality, route it to the Air High quality Specialist Agent.
- If the question is ambiguous or doesn't match both class, present a clarification request.
""",
handoffs=[weather_handoff, air_quality_handoff]
)
async def run_agent(user_input: str):
consequence = await Runner.run(triage_agent, user_input)
return consequence.final_output
def foremost():
st.title("Climate and Air High quality Assistant")
user_input = st.text_input("Enter your question about climate or air high quality:")
if st.button("Get Replace"):
with st.spinner("Pondering..."):
if user_input:
agent_response = asyncio.run(run_agent(user_input))
st.write(agent_response)
else:
st.write("Please enter a query in regards to the climate or air high quality.")
if __name__ == "__main__":
foremost()
Run the app from the terminal and ask a query in regards to the climate or air high quality. (Within the instance under, I deliberately requested in regards to the air high quality in Melbourne to supply a distinction with the air high quality in Jakarta.)
streamlit run 05-customized-handoff-app.py

I’ve included a display recording right here to display the aim of the on_handoff
property we outlined. As proven above, proper after the triage agent initiates a handoff to a specialist agent, an data part seems earlier than the ultimate response is returned within the app. This habits will be additional custom-made — for instance, by enriching the data displayed or including further logic to execute throughout the handoff.
Specify Enter Sort
The earlier instance of a callback perform didn’t present a lot significant data—it solely indicated {that a} handoff had occurred.
To go extra helpful information to the callback perform, we are able to use the input_type
parameter within the handoff object to explain the anticipated construction of the enter.
Step one is to outline the enter sort. Usually, we use a Pydantic mannequin class[3] to specify the construction of the info we need to go.
Suppose we wish the triage agent to supply the next data: the explanation for the handoff (to grasp the logic behind the choice) and the latitude and longitude of the situation talked about within the person question. To outline this enter sort, we are able to use the next code:
from pydantic import BaseModel, Area
class HandoffRequest(BaseModel):
specialist_agent: str = Area(..., description="Identify of the specialist agent handy off to")
handoff_reason: str = Area(..., description="Cause for the handoff")
latitude: float = Area(..., description="Latitude of the situation")
longitude: float = Area(..., description="Longitude of the situation")
First, we import the required lessons from the Pydantic library. BaseModel
is the bottom class that gives information validation capabilities, whereas Area
permits us so as to add metadata to every mannequin subject.
Subsequent, we outline a category known as HandoffRequest
, which incorporates the construction and validation guidelines for the info we wish. The specialist_agent
subject shops the identify of the receiving agent on this handoff. The handoff_reason
subject is a string explaining why the handoff is occurring. The latitude
and longitude
fields are outlined as floats, representing the geographic coordinates.
As soon as the structured enter is outlined, the following step is to switch the callback perform to accommodate this data.
async def on_handoff_callback(ctx: RunContextWrapper, user_input: HandoffRequest):
st.data(f"""
Handing off to {user_input.specialist_agent} for additional processing...n
Handoff purpose: {user_input.handoff_reason} n
Location : {user_input.latitude}, {user_input.longitude} n
""")
Lastly, let’s add this parameter to each of our handoff objects
weather_handoff = handoff(
agent=weather_specialist_agent,
tool_name_override="handoff_to_weather_specialist",
tool_description_override="Deal with queries associated to climate situations",
on_handoff=on_handoff_callback,
input_type=HandoffRequest
)
air_quality_handoff = handoff(
agent=air_quality_specialist_agent,
tool_name_override="handoff_to_air_quality_specialist",
tool_description_override="Deal with queries associated to air high quality situations",
on_handoff=on_handoff_callback,
input_type=HandoffRequest
)
The remainder of the script stays unchanged. Now, let’s strive operating it utilizing the next command:
streamlit run 05-customized-handoff-app.py

On this instance, I didn’t use the phrase “climate” straight—as an alternative, I requested about “temperature.” From the blue data part, we are able to see {that a} handoff occurred to the Climate Specialist agent. We additionally get the explanation why the triage agent made this resolution: the question was in regards to the present temperature, which is taken into account a weather-related matter. Moreover, the geographical location (Tokyo) is supplied for additional reference.
The complete script of custom-made handoffs will be discovered right here:
from brokers import Agent, Runner, function_tool, handoff, RunContextWrapper
import asyncio
import streamlit as st
from dotenv import load_dotenv
import requests
load_dotenv()
@function_tool
def get_current_weather(latitude: float, longitude: float) -> dict:
"""Fetch present climate information for the given latitude and longitude."""
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation,weathercode,windspeed_10m,winddirection_10m",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
weather_specialist_agent = Agent(
identify="Climate Specialist Agent",
directions="""
You're a climate specialist agent.
Your process is to investigate present climate information, together with temperature, humidity, wind pace and route, precipitation, and climate codes.
For every question, present:
1. A transparent, concise abstract of the present climate situations in plain language.
2. Sensible, actionable options or precautions for out of doors actions, journey, well being, or clothes, tailor-made to the climate information.
3. If extreme climate is detected (e.g., heavy rain, thunderstorms, excessive warmth), clearly spotlight really useful security measures.
Construction your response in two sections:
Climate Abstract:
- Summarize the climate situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the climate.
""",
instruments=[get_current_weather],
tool_use_behavior="run_llm_again"
)
@function_tool
def get_current_air_quality(latitude: float, longitude: float) -> dict:
"""Fetch present air high quality information for the given latitude and longitude."""
url = "https://air-quality-api.open-meteo.com/v1/air-quality"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "european_aqi,us_aqi,pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,sulphur_dioxide,ozone",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
air_quality_specialist_agent = Agent(
identify="Air High quality Specialist Agent",
directions="""
You might be an air high quality specialist agent.
Your position is to interpret present air high quality information and talk it clearly to customers.
For every question, present:
1. A concise abstract of the air high quality situations in plain language, together with key pollution and their ranges.
2. Sensible, actionable recommendation or precautions for out of doors actions, journey, and well being, tailor-made to the air high quality information.
3. If poor or hazardous air high quality is detected (e.g., excessive air pollution, allergens), clearly spotlight really useful security measures.
Construction your response in two sections:
Air High quality Abstract:
- Summarize the air high quality situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the air high quality.
""",
instruments=[get_current_air_quality],
tool_use_behavior="run_llm_again"
)
from pydantic import BaseModel, Area
class HandoffRequest(BaseModel):
specialist_agent: str = Area(..., description="Identify of the specialist agent handy off to")
handoff_reason: str = Area(..., description="Cause for the handoff")
latitude: float = Area(..., description="Latitude of the situation")
longitude: float = Area(..., description="Longitude of the situation")
async def on_handoff_callback(ctx: RunContextWrapper, user_input: HandoffRequest):
st.data(f"""
Handing off to {user_input.specialist_agent} for additional processing...n
Handoff purpose: {user_input.handoff_reason} n
Location : {user_input.latitude}, {user_input.longitude} n
""")
weather_handoff = handoff(
agent=weather_specialist_agent,
tool_name_override="handoff_to_weather_specialist",
tool_description_override="Deal with queries associated to climate situations",
on_handoff=on_handoff_callback,
input_type=HandoffRequest
)
air_quality_handoff = handoff(
agent=air_quality_specialist_agent,
tool_name_override="handoff_to_air_quality_specialist",
tool_description_override="Deal with queries associated to air high quality situations",
on_handoff=on_handoff_callback,
input_type=HandoffRequest
)
triage_agent = Agent(
identify="Triage Agent",
directions="""
You're a triage agent.
Your process is to find out which specialist agent (Climate Specialist or Air High quality Specialist) is greatest suited to deal with the person's question based mostly on the content material of the query.
For every question, analyze the enter and resolve:
- If the question is about climate situations, route it to the Climate Specialist Agent.
- If the question is about air high quality, route it to the Air High quality Specialist Agent.
- If the question is ambiguous or doesn't match both class, present a clarification request.
""",
handoffs=[weather_handoff, air_quality_handoff]
)
async def run_agent(user_input: str):
consequence = await Runner.run(triage_agent, user_input)
return consequence.final_output
def foremost():
st.title("Climate and Air High quality Assistant")
user_input = st.text_input("Enter your question about climate or air high quality:")
if st.button("Get Replace"):
with st.spinner("Pondering..."):
if user_input:
agent_response = asyncio.run(run_agent(user_input))
st.write(agent_response)
else:
st.write("Please enter a query in regards to the climate or air high quality.")
if __name__ == "__main__":
foremost()
Brokers-as-Instruments
We’ve already explored the handoff technique and how you can customise it. When a handoff is invoked, the duty is totally transferred to the following agent.
With the Brokers-as-Instruments sample, as an alternative of transferring full conversational management to a different agent, the primary agent—known as the orchestrator agent—retains management of the dialog. It might seek the advice of different specialist brokers as callable instruments. On this state of affairs, the orchestrator agent can mix responses from completely different brokers to assemble an entire reply.

Flip an Agent right into a Device with a Easy Technique
Now, let’s get into the code. We are able to flip an agent right into a callable instrument just by utilizing the agent.as_tool()
perform. This perform requires two parameters: tool_name
and tool_description
.
We are able to apply this technique straight throughout the instruments
checklist of our new orchestrator_agent
, as proven under:
orchestrator_agent = Agent(
identify="Orchestrator Agent",
directions="""
You might be an orchestrator agent.
Your process is to handle the interplay between the Climate Specialist Agent and the Air High quality Specialist Agent.
You'll obtain a question from the person and can resolve which agent to invoke based mostly on the content material of the question.
If each climate and air high quality data is requested, you'll invoke each brokers and mix their responses into one clear reply.
""",
instruments=[
weather_specialist_agent.as_tool(
tool_name="get_weather_update",
tool_description="Get current weather information and suggestion including temperature, humidity, wind speed and direction, precipitation, and weather codes."
),
air_quality_specialist_agent.as_tool(
tool_name="get_air_quality_update",
tool_description="Get current air quality information and suggestion including pollutants and their levels."
)
]
)
Within the instruction
, we information the agent to handle interactions between two specialist brokers. It might invoke both one or each brokers relying on the question. If each specialist brokers are invoked, the orchestrator agent should mix their responses.
Right here is the total script to display the agents-as-tools sample.
from brokers import Agent, Runner, function_tool
import asyncio
import streamlit as st
from dotenv import load_dotenv
import requests
load_dotenv()
@function_tool
def get_current_weather(latitude: float, longitude: float) -> dict:
"""Fetch present climate information for the given latitude and longitude."""
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation,weathercode,windspeed_10m,winddirection_10m",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
weather_specialist_agent = Agent(
identify="Climate Specialist Agent",
directions="""
You're a climate specialist agent.
Your process is to investigate present climate information, together with temperature, humidity, wind pace and route, precipitation, and climate codes.
For every question, present:
1. A transparent, concise abstract of the present climate situations in plain language.
2. Sensible, actionable options or precautions for out of doors actions, journey, well being, or clothes, tailor-made to the climate information.
3. If extreme climate is detected (e.g., heavy rain, thunderstorms, excessive warmth), clearly spotlight really useful security measures.
Construction your response in two sections:
Climate Abstract:
- Summarize the climate situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the climate.
""",
instruments=[get_current_weather],
tool_use_behavior="run_llm_again"
)
@function_tool
def get_current_air_quality(latitude: float, longitude: float) -> dict:
"""Fetch present air high quality information for the given latitude and longitude."""
url = "https://air-quality-api.open-meteo.com/v1/air-quality"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "european_aqi,us_aqi,pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,sulphur_dioxide,ozone",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
air_quality_specialist_agent = Agent(
identify="Air High quality Specialist Agent",
directions="""
You might be an air high quality specialist agent.
Your position is to interpret present air high quality information and talk it clearly to customers.
For every question, present:
1. A concise abstract of the air high quality situations in plain language, together with key pollution and their ranges.
2. Sensible, actionable recommendation or precautions for out of doors actions, journey, and well being, tailor-made to the air high quality information.
3. If poor or hazardous air high quality is detected (e.g., excessive air pollution, allergens), clearly spotlight really useful security measures.
Construction your response in two sections:
Air High quality Abstract:
- Summarize the air high quality situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the air high quality.
""",
instruments=[get_current_air_quality],
tool_use_behavior="run_llm_again"
)
orchestrator_agent = Agent(
identify="Orchestrator Agent",
directions="""
You might be an orchestrator agent.
Your process is to handle the interplay between the Climate Specialist Agent and the Air High quality Specialist Agent.
You'll obtain a question from the person and can resolve which agent to invoke based mostly on the content material of the question.
If each climate and air high quality data is requested, you'll invoke each brokers and mix their responses into one clear reply.
""",
instruments=[
weather_specialist_agent.as_tool(
tool_name="get_weather_update",
tool_description="Get current weather information and suggestion including temperature, humidity, wind speed and direction, precipitation, and weather codes."
),
air_quality_specialist_agent.as_tool(
tool_name="get_air_quality_update",
tool_description="Get current air quality information and suggestion including pollutants and their levels."
)
],
tool_use_behavior="run_llm_again"
)
async def run_agent(user_input: str):
consequence = await Runner.run(orchestrator_agent, user_input)
return consequence.final_output
def foremost():
st.title("Climate and Air High quality Assistant")
user_input = st.text_input("Enter your question about climate or air high quality:")
if st.button("Get Replace"):
with st.spinner("Pondering..."):
if user_input:
agent_response = asyncio.run(run_agent(user_input))
st.write(agent_response)
else:
st.write("Please enter a query in regards to the climate or air high quality.")
if __name__ == "__main__":
foremost()
Save this file as 06-agents-as-tools-app.py
and run it within the terminal utilizing the command under:
streamlit run 06-agents-as-tools-app.py
How the Orchestrator Makes use of Brokers
Let’s start with a question that triggers just one agent. On this instance, I requested in regards to the climate in Jakarta.

The result’s just like what we get utilizing the handoff sample. The climate specialist agent responds with the present temperature and gives options based mostly on the API information.
As talked about earlier, one of many key benefits of utilizing the agents-as-tools sample is that it permits the orchestrator agent to seek the advice of multiple agent for a single question. The orchestrator intelligently plans based mostly on the person’s intent.
For instance, let’s ask about each the climate and air high quality in Jakarta. The consequence seems like this:

The orchestrator agent first returns separate summaries from the climate and air high quality specialist brokers, together with their particular person options. Lastly, it combines the insights and gives an total conclusion—for instance, recommending warning when spending time open air attributable to poor air high quality.
Exploring the Hint Dashboard
Right here’s an outline of the hint construction. We are able to see that the primary department solely entails the Orchestrator Agent — not like within the handoff sample, the place the Triage Agent transfers management to the following specialist agent.

Within the first LLM response, the Orchestrator Agent calls two features: get_weather_update()
and get_air_quality_update()
. These features had been initially brokers that we reworked into instruments. Each features obtain the identical enter: “Jakarta”.

After receiving the outputs from each instruments, the Orchestrator Agent calls the LLM once more to mix the responses and generate a remaining abstract.
Customizing Brokers-as-Instruments
The strategy we used earlier is a fast approach to flip brokers into instruments. Nevertheless, as we noticed within the hint dashboard, it doesn’t give us management over the enter of every perform.
In our instance, the Orchestrator Agent known as the features with “Jakarta” because the enter. This implies the duty of changing that into exact geographical coordinates is left to the LLMs of the specialist brokers. This method will not be at all times dependable—I encountered instances the place the specialist brokers known as the API utilizing completely different latitude and longitude values.
This concern will be addressed by customizing agents-as-tools with structured inputs. As urged within the documentation, we are able to use Runner.run()
throughout the instrument implementation.
@function_tool
async def get_weather_update(latitude: float, longitude: float) -> str:
consequence = await Runner.run(
weather_specialist_agent,
enter="Get the present climate situation and suggestion for this location (latitude: {}, longitude: {})".format(latitude, longitude)
)
return consequence.final_output
@function_tool
async def get_air_quality_update(latitude: float, longitude: float) -> str:
consequence = await Runner.run(
air_quality_specialist_agent,
enter="Get the present air high quality situation and suggestion for this location (latitude: {}, longitude: {})".format(latitude, longitude)
)
return consequence.final_output
These two features are adorned with @function_tool
, just like how we outlined our API-call instruments—turning each brokers into instruments that may be invoked by the Orchestrator Agent.
Every perform now takes latitude
and longitude
as arguments, not like the earlier technique the place we couldn’t management the enter values.
Since we’re operating the agent inside these features, we additionally have to outline the enter explicitly as a formatted string that features latitude and longitude.
This technique gives a extra dependable method: the Orchestrator Agent determines the precise coordinates and passes them to the instruments, slightly than counting on every specialist agent to resolve the situation—eliminating inconsistencies in API calls.
A full script of this implementation will be discovered right here.
from brokers import Agent, Runner, function_tool
import asyncio
import streamlit as st
from dotenv import load_dotenv
import requests
load_dotenv()
@function_tool
def get_current_weather(latitude: float, longitude: float) -> dict:
"""Fetch present climate information for the given latitude and longitude."""
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation,weathercode,windspeed_10m,winddirection_10m",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
weather_specialist_agent = Agent(
identify="Climate Specialist Agent",
directions="""
You're a climate specialist agent.
Your process is to investigate present climate information, together with temperature, humidity, wind pace and route, precipitation, and climate codes.
For every question, present:
1. A transparent, concise abstract of the present climate situations in plain language.
2. Sensible, actionable options or precautions for out of doors actions, journey, well being, or clothes, tailor-made to the climate information.
3. If extreme climate is detected (e.g., heavy rain, thunderstorms, excessive warmth), clearly spotlight really useful security measures.
Construction your response in two sections:
Climate Abstract:
- Summarize the climate situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the climate.
""",
instruments=[get_current_weather],
tool_use_behavior="run_llm_again"
)
@function_tool
def get_current_air_quality(latitude: float, longitude: float) -> dict:
"""Fetch present air high quality information for the given latitude and longitude."""
url = "https://air-quality-api.open-meteo.com/v1/air-quality"
params = {
"latitude": latitude,
"longitude": longitude,
"present": "european_aqi,us_aqi,pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,sulphur_dioxide,ozone",
"timezone": "auto"
}
response = requests.get(url, params=params)
return response.json()
air_quality_specialist_agent = Agent(
identify="Air High quality Specialist Agent",
directions="""
You might be an air high quality specialist agent.
Your position is to interpret present air high quality information and talk it clearly to customers.
For every question, present:
1. A concise abstract of the air high quality situations in plain language, together with key pollution and their ranges.
2. Sensible, actionable recommendation or precautions for out of doors actions, journey, and well being, tailor-made to the air high quality information.
3. If poor or hazardous air high quality is detected (e.g., excessive air pollution, allergens), clearly spotlight really useful security measures.
Construction your response in two sections:
Air High quality Abstract:
- Summarize the air high quality situations in easy phrases.
Options:
- Checklist related recommendation or precautions based mostly on the air high quality.
""",
instruments=[get_current_air_quality],
tool_use_behavior="run_llm_again"
)
@function_tool
async def get_weather_update(latitude: float, longitude: float) -> str:
consequence = await Runner.run(
weather_specialist_agent,
enter="Get the present climate situation and suggestion for this location (latitude: {}, longitude: {})".format(latitude, longitude)
)
return consequence.final_output
@function_tool
async def get_air_quality_update(latitude: float, longitude: float) -> str:
consequence = await Runner.run(
air_quality_specialist_agent,
enter="Get the present air high quality situation and suggestion for this location (latitude: {}, longitude: {})".format(latitude, longitude)
)
return consequence.final_output
orchestrator_agent = Agent(
identify="Orchestrator Agent",
directions="""
You might be an orchestrator agent with two instruments: `get_weather_update` and `get_air_quality_update`.
Analyze the person's question and invoke:
- `get_weather_update` for weather-related requests (temperature, humidity, wind, precipitation).
- `get_air_quality_update` for air quality-related requests (pollution, AQI).
If the question requires each, name each instruments and merge their outputs.
Return a single, clear response that addresses the person's query with concise summaries and actionable recommendation.
""",
instruments=[get_weather_update, get_air_quality_update],
tool_use_behavior="run_llm_again"
)
async def run_agent(user_input: str):
consequence = await Runner.run(orchestrator_agent, user_input)
return consequence.final_output
def foremost():
st.title("Climate and Air High quality Assistant")
user_input = st.text_input("Enter your question about climate or air high quality:")
if st.button("Get Replace"):
with st.spinner("Pondering..."):
if user_input:
agent_response = asyncio.run(run_agent(user_input))
st.write(agent_response)
else:
st.write("Please enter a query in regards to the climate or air high quality.")
if __name__ == "__main__":
foremost()
Conclusion
We have now demonstrated two elementary patterns of multi-agent collaboration: the handoff sample and the agents-as-tools sample.
A handoff is appropriate to be used instances the place the primary agent can delegate your complete dialog to a specialist agent. However, the agents-as-tools sample is highly effective when the primary agent wants to take care of management over the duty.
Though the use instances on this article are comparatively easy, they illustrate how brokers can work and collaborate successfully. From right here after understanding when to make use of handoff or agents-as-tools, you may proceed your exploration on constructing specialize agent with extra challanging process and instruments.
We’ll proceed the journey on my subsequent installment of Arms-On with Brokers SDK quickly.
Reference
[1] Bornet, P., Wirtz, J., Davenport, T. H., De Cremer, D., Evergreen, B., Fersht, P., Gohel, R., Khiyara, S., Sund, P., & Mullakara, N. (2025). Agentic Synthetic Intelligence: Harnessing AI Brokers to Reinvent Enterprise, Work, and Life. World Scientific Publishing Co.
[2] OpenAI. (2025). OpenAI Brokers SDK documentation. Retrieved August 1, 2025, from https://openai.github.io/openai-agents-python/handoffs/
[3] Pydantic. (n.d.). Fashions. Pydantic Documentation. Retrieved August 1, 2025, from https://docs.pydantic.dev/latest/concepts/models/
Learn the primary article right here:
Yow will discover the whole supply code used on this article within the following repository: agentic-ai-weather | GitHub Repository. Be at liberty to discover, clone, or fork the challenge to observe alongside or construct your individual model.
In the event you’d prefer to see the app in motion, I’ve additionally deployed it right here: Weather Assistant Streamlit
Lastly, let’s join on LinkedIn!