Use this file to discover all available pages before exploring further.
Function calling lets chat models interact with your code. You define one or more functions as tools using JSON schema, pass them to the model alongside a user message, and the model decides whether to call a function — and if so, with what arguments. Your application then executes the function and returns the result. The model incorporates that result into its final response. This round-trip between your code and the model is the fundamental building block of every agent.
Each tool is a JSON object with a type of "function" and a function description that includes a name, a description the model uses to decide when to call it, and a parameters schema in JSON Schema format.
from openai import OpenAIimport jsonclient = OpenAI()tools = [ { "type": "function", "function": { "name": "get_weather", "description": "Get the current weather for a location", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "City and state, e.g. 'San Francisco, CA'" } }, "required": ["location"] } } }]
Write clear, specific descriptions. The model uses the description — not the function name — to decide when to call the tool. Be explicit about what the function does and what format the arguments should be in.
This example shows the full loop: define a function, call the model, detect the tool call, execute the function, return the result, and get the final answer.
from openai import OpenAIimport jsonclient = OpenAI()# Step 1: Define the tooltools = [ { "type": "function", "function": { "name": "get_weather", "description": "Get the current weather for a location", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "City and state, e.g. 'San Francisco, CA'" } }, "required": ["location"] } } }]# Step 2: Your actual function implementationdef get_weather(location: str) -> str: # Replace with a real weather API call return f"Sunny, 68°F in {location}"messages = [{"role": "user", "content": "What's the weather in Boston?"}]# Step 3: Call the modelresponse = client.chat.completions.create( model="gpt-4o", messages=messages, tools=tools,)assistant_message = response.choices[0].messagemessages.append(assistant_message)# Step 4: Check if the model wants to call a functionif assistant_message.tool_calls: for tool_call in assistant_message.tool_calls: # Step 5: Execute the function args = json.loads(tool_call.function.arguments) result = get_weather(**args) # Step 6: Return the result to the model messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result, }) # Step 7: Get the final response final_response = client.chat.completions.create( model="gpt-4o", messages=messages, tools=tools, ) print(final_response.choices[0].message.content) # "The current weather in Boston is sunny and 68°F."
You can define multiple tools and the model will choose the most appropriate one — or call several in a single turn.
tools = [ { "type": "function", "function": { "name": "get_current_weather", "description": "Get the current weather", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA", }, "format": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "The temperature unit. Infer from the location.", }, }, "required": ["location", "format"], }, } }, { "type": "function", "function": { "name": "get_n_day_weather_forecast", "description": "Get an N-day weather forecast", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA", }, "format": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "The temperature unit. Infer from the location.", }, "num_days": { "type": "integer", "description": "The number of days to forecast", } }, "required": ["location", "format", "num_days"], }, } },]
When the model identifies multiple independent function calls it can make, it returns them all in a single response. You should execute all of them and return all results before the next model call.
response = client.chat.completions.create( model="gpt-4o", messages=[ { "role": "user", "content": "What's the current weather in Glasgow and the 5-day forecast?" } ], tools=tools,)message = response.choices[0].message# message.tool_calls may contain two entries:# - get_current_weather(location="Glasgow, Scotland", format="celsius")# - get_n_day_weather_forecast(location="Glasgow, Scotland", format="celsius", num_days=5)messages.append(message)if message.tool_calls: for tool_call in message.tool_calls: args = json.loads(tool_call.function.arguments) # Dispatch to the right function if tool_call.function.name == "get_current_weather": result = get_current_weather(**args) elif tool_call.function.name == "get_n_day_weather_forecast": result = get_n_day_weather_forecast(**args) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": str(result), })
Always return a tool result for every tool call ID in the response. If you skip one, the model will be confused about the missing result.
Use the tool_choice parameter to control whether and how the model uses tools.
# Default: model decidesresponse = client.chat.completions.create( model="gpt-4o", messages=messages, tools=tools, tool_choice="auto", # model chooses (default))# Force a specific functionresponse = client.chat.completions.create( model="gpt-4o", messages=messages, tools=tools, tool_choice={ "type": "function", "function": {"name": "get_weather"} },)# Prevent any function callsresponse = client.chat.completions.create( model="gpt-4o", messages=messages, tools=tools, tool_choice="none",)
When tool_choice is set to a specific function, the model will always generate arguments for it even if the user’s question doesn’t require it. Use forced tool choice only when you are certain the function applies.
Mark parameters as required when the function cannot run without them. Optional parameters can be omitted from the required array — the model will only include them in arguments when it has enough context to fill them in.
"parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "City and state" }, "units": { "type": "string", "enum": ["metric", "imperial"], "description": "Unit system. Defaults to metric if not specified." } }, "required": ["location"] # units is optional}