Function calling is what turns an LLM from a text generator into something that can actually take action — checking a database, calling an API, running a calculation — by letting the model request that a specific function be called with specific arguments, which your code then executes.
Defining Tools the Model Can Call
from openai import OpenAI
client = OpenAI()
def get_weather(city: str) -> str:
# In reality, this would call a real weather API
return f"It's 18°C and cloudy in {city}."
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"}
},
"required": ["city"]
}
}
}]
The Agent Loop
import json
def run_agent(user_message):
messages = [{"role": "user", "content": user_message}]
response = client.chat.completions.create(
model="gpt-4o-mini", messages=messages, tools=tools
)
message = response.choices[0].message
if message.tool_calls:
messages.append(message)
for call in message.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args) # actually execute the requested function
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result,
})
# Send the tool's result back so the model can form a final answer
final = client.chat.completions.create(model="gpt-4o-mini", messages=messages)
return final.choices[0].message.content
return message.content
print(run_agent("What's the weather like in Berlin?"))
Why This Pattern Matters
The model never actually executes anything itself — it just decides which function to call and with what arguments, based on the conversation. Your code retains full control over what actually happens, which is exactly the safety boundary that makes tool-calling agents practical to deploy: you can validate, rate-limit, or reject any requested action before it runs.
Scaling Up: Multi-Step Agents
Real agentic systems loop this pattern — model requests a tool call, your code executes it, the result goes back to the model, which may then request another tool call based on that result, continuing until it has enough information to give a final answer. This is the core mechanism behind essentially every “AI agent” product on the market today.