LLM Function Calling: OpenAI, Anthropic, and Gemini Side by Side
Function calling lets LLMs invoke your code with structured arguments - here is the complete guide with parallel calls, error handling, and cross-provider format differences.
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.
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
Practical deep-dives on LLMs, developer tools, and AI engineering. No filler. Unsubscribe any time.
// written byFIG. AUTH-01
530
Mahmudul Haque Qudrati
CEO & ML Engineer
CEO and ML Engineer at Pristren. Builds AI-powered software for teams and writes about machine learning, LLMs, developer tools, and practical AI applications.
What is Harness engineering: Leveraging Codex in an agent-first world? A Practical Overview
Harness engineering is the practice of building structured, safe environments for AI agents to execute code. This post explains how to leverage OpenAI Codex in an agent-first world, with concrete examples, cost breakdowns, and honest tradeoffs.