What Function Calling Is
Function calling (also called "tool use") allows an LLM to respond with a structured call to a function you define, rather than free text. The model inspects available tools, decides which to call, and returns a JSON object with the function name and arguments — you execute the function and return the result, then the model synthesises a final answer.
This is the foundation of AI agents: the model picks tools, you run them, the cycle continues until the task is complete.
OpenAI Tool Definition
from openai import OpenAI
client = OpenAI()
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["city"],
},
},
}
]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "What is the weather in Tokyo?"}],
tools=tools,
tool_choice="auto",
)
tool_call = response.choices[0].message.tool_calls[0]
print(tool_call.function.name) # get_weather
print(tool_call.function.arguments) # {"city": "Tokyo", "unit": "celsius"}
Handling Tool Results
import json
# Execute your function
args = json.loads(tool_call.function.arguments)
result = {"temperature": 22, "condition": "Partly cloudy"}
# Send result back to the model
messages = [
{"role": "user", "content": "What is the weather in Tokyo?"},
response.choices[0].message, # assistant message with tool_call
{
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result),
},
]
final = client.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
print(final.choices[0].message.content) # "Tokyo is currently 22°C and partly cloudy."
Parallel Function Calls (OpenAI)
GPT-4o supports calling multiple tools in one turn:
# If the user asks "Weather in Tokyo AND London?"
# response.choices[0].message.tool_calls → list of 2 tool_calls
for tc in response.choices[0].message.tool_calls:
print(tc.function.name, tc.function.arguments)
Anthropic Tool Use Format
Anthropic uses tool_use content blocks instead of tool_calls:
import anthropic
client = anthropic.Anthropic()
tools = [{
"name": "get_weather",
"description": "Get current weather for a city",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}]
response = client.messages.create(
model="claude-3-5-haiku-20241022",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Weather in Paris?"}],
)
# Tool call in content blocks
for block in response.content:
if block.type == "tool_use":
print(block.name, block.input)
Gemini FunctionDeclaration
import google.generativeai as genai
genai.configure(api_key="YOUR_KEY")
get_weather = genai.protos.FunctionDeclaration(
name="get_weather",
description="Get current weather",
parameters=genai.protos.Schema(
type=genai.protos.Type.OBJECT,
properties={"city": genai.protos.Schema(type=genai.protos.Type.STRING)},
required=["city"],
),
)
model = genai.GenerativeModel("gemini-1.5-flash", tools=[get_weather])
response = model.generate_content("Weather in Berlin?")
Error Handling and Retries
Always validate tool arguments before executing — the model can hallucinate invalid values:
try:
args = json.loads(tool_call.function.arguments)
result = execute_tool(args)
except (json.JSONDecodeError, ValueError) as e:
result = {"error": str(e)}
# Return error to model — it will retry with corrected arguments
Full reference: OpenAI function calling and Anthropic tool use.