Function Calling vs Tool Use: What's the Difference and When to Use Each
Clarify the distinction between function calling and tool use in the context of large language models, covering terminology differences across providers, architectural patterns, implementation strategies, and guidance on when to use each approach for building AI applications.
The Terminology Confusion
If you have built LLM applications across different providers, you have encountered both "function calling" and "tool use" -- sometimes used interchangeably, sometimes referring to distinct concepts. The confusion exists because different providers chose different terminology for related but not identical features, and the ecosystem has not fully standardized.
Let us clarify the terms and their practical differences.
Definitions
Function Calling (OpenAI Terminology)
Function calling was introduced by OpenAI in June 2023. The term refers to the LLM's ability to output structured JSON that describes a function to call, including the function name and arguments. The model does not execute the function -- it generates the intent to call it.
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "What's the weather in Tokyo?"}
],
functions=[ # Original "functions" parameter
{
"name": "get_weather",
"description": "Get weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
},
"required": ["city"]
}
}
],
function_call="auto" # Original "function_call" parameter
)
# Model returns:
# function_call: { "name": "get_weather", "arguments": '{"city": "Tokyo"}' }
OpenAI later deprecated the functions parameter in favor of tools, but the community still uses "function calling" as the general term.
Tool Use (Anthropic Terminology)
Anthropic uses "tool use" to describe the same core capability: the model deciding to invoke an external tool and generating structured input for it. However, Anthropic's implementation uses a different message structure with explicit tool_use and tool_result content blocks.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=[ # "tools" parameter
{
"name": "get_weather",
"description": "Get weather for a city",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string"},
},
"required": ["city"]
}
}
],
messages=[
{"role": "user", "content": "What's the weather in Tokyo?"}
]
)
# Model returns content blocks:
# [
# {"type": "text", "text": "I'll check the weather for you."},
# {"type": "tool_use", "id": "toolu_123", "name": "get_weather",
# "input": {"city": "Tokyo"}}
# ]
The Unified "Tools" Standard
OpenAI has since migrated to a tools parameter that wraps functions, aligning terminology closer to Anthropic's:
# Modern OpenAI "tools" format
response = client.chat.completions.create(
model="gpt-4o",
messages=[...],
tools=[
{
"type": "function", # Tool type
"function": { # Function definition
"name": "get_weather",
"description": "Get weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}
],
tool_choice="auto"
)
Architectural Differences
While the terminology is converging, there are genuine architectural differences in how providers implement the feature:
Message Structure
| Aspect | OpenAI | Anthropic | Google Gemini |
|---|---|---|---|
| Tool definition param | tools[].function |
tools[] |
tools[].function_declarations |
| Model output format | tool_calls array |
Content blocks (tool_use type) |
function_call in parts |
| Result return format | tool role message |
tool_result content block |
function_response part |
| Parallel calls | Yes (multiple tool_calls) | Yes (multiple tool_use blocks) | Yes (multiple function_calls) |
| Forcing a tool | tool_choice: {type: "function", function: {name: "..."} } |
tool_choice: {type: "tool", name: "..."} |
tool_config.function_calling_config |
Anthropic's Approach: Content Blocks
Anthropic's design treats tool use as just another content type alongside text. This means a single response can contain both text and tool calls interleaved:
# Claude can think out loud AND call tools in one response
response.content = [
{"type": "text", "text": "Let me check the weather and your calendar."},
{"type": "tool_use", "id": "toolu_1", "name": "get_weather",
"input": {"city": "Tokyo"}},
{"type": "tool_use", "id": "toolu_2", "name": "check_calendar",
"input": {"date": "2026-01-22"}},
]
OpenAI's Approach: Separate Tool Call Array
OpenAI puts tool calls in a separate array on the message object:
# GPT-4o separates tool calls from content
message.content = "Let me check that for you."
message.tool_calls = [
{"id": "call_1", "type": "function",
"function": {"name": "get_weather", "arguments": '{"city": "Tokyo"}'}},
{"id": "call_2", "type": "function",
"function": {"name": "check_calendar", "arguments": '{"date": "2026-01-22"}'}},
]
Provider-Agnostic Tool Use
To build applications that work across providers, use an abstraction layer:
from dataclasses import dataclass
from abc import ABC, abstractmethod
@dataclass
class ToolCall:
id: str
name: str
arguments: dict
@dataclass
class ToolResult:
tool_call_id: str
content: str
is_error: bool = False
class LLMProvider(ABC):
@abstractmethod
async def generate(self, messages, tools, **kwargs):
pass
@abstractmethod
def extract_tool_calls(self, response) -> list[ToolCall]:
pass
@abstractmethod
def format_tool_results(self, results: list[ToolResult]) -> dict:
pass
class AnthropicProvider(LLMProvider):
async def generate(self, messages, tools, **kwargs):
return await self.client.messages.create(
model=kwargs.get("model", "claude-sonnet-4-20250514"),
messages=messages,
tools=tools,
max_tokens=kwargs.get("max_tokens", 4096),
)
def extract_tool_calls(self, response) -> list[ToolCall]:
return [
ToolCall(id=b.id, name=b.name, arguments=b.input)
for b in response.content
if b.type == "tool_use"
]
def format_tool_results(self, results: list[ToolResult]) -> dict:
return {
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": r.tool_call_id,
"content": r.content,
"is_error": r.is_error,
}
for r in results
],
}
class OpenAIProvider(LLMProvider):
async def generate(self, messages, tools, **kwargs):
# Convert tool format from Anthropic-style to OpenAI-style
oai_tools = [
{
"type": "function",
"function": {
"name": t["name"],
"description": t["description"],
"parameters": t["input_schema"],
}
}
for t in tools
]
return await self.client.chat.completions.create(
model=kwargs.get("model", "gpt-4o"),
messages=messages,
tools=oai_tools,
)
def extract_tool_calls(self, response) -> list[ToolCall]:
msg = response.choices[0].message
if not msg.tool_calls:
return []
return [
ToolCall(
id=tc.id,
name=tc.function.name,
arguments=json.loads(tc.function.arguments),
)
for tc in msg.tool_calls
]
def format_tool_results(self, results: list[ToolResult]) -> list[dict]:
return [
{
"role": "tool",
"tool_call_id": r.tool_call_id,
"content": r.content,
}
for r in results
]
When to Use Which Pattern
Use "Simple" Tool Calling When:
- You have a fixed set of tools that rarely changes
- Each tool call is independent (no chaining needed)
- The application controls which tools are available
- You want a single LLM round-trip
# Example: Extracting structured data using tool calling
# (force a specific tool to get guaranteed structured output)
response = client.messages.create(
model="claude-sonnet-4-20250514",
tools=[extraction_tool],
tool_choice={"type": "tool", "name": "extract_data"},
messages=[{"role": "user", "content": document_text}],
)
Use Agentic Tool Use When:
- The LLM needs to decide which tools to call dynamically
- Tool calls may be chained (output of one feeds into another)
- The number of tool calls is not predetermined
- Complex multi-step reasoning is required
# Example: Agent that researches, calculates, and reports
async def research_agent(query: str):
messages = [{"role": "user", "content": query}]
while True:
response = await client.messages.create(
model="claude-sonnet-4-20250514",
tools=[search_tool, calculator_tool, chart_tool, report_tool],
tool_choice={"type": "auto"}, # Model decides
messages=messages,
)
if response.stop_reason == "end_turn":
return extract_text(response)
# Model autonomously chains tools as needed
messages.append({"role": "assistant", "content": response.content})
results = await execute_tools(response)
messages.append({"role": "user", "content": results})
Use MCP When:
- Tools need to be shared across multiple applications
- Third-party tool providers want a standard interface
- Tools require their own lifecycle management (connections, auth)
- You want to decouple tool implementation from AI application code
Common Patterns Across Both Approaches
Forced Tool Use for Structured Output
All providers support forcing a specific tool, which guarantees structured output:
# Anthropic
tool_choice={"type": "tool", "name": "extract_entities"}
# OpenAI
tool_choice={"type": "function", "function": {"name": "extract_entities"}}
# Google
tool_config={"function_calling_config": {"mode": "ANY",
"allowed_function_names": ["extract_entities"]}}
Disabling Tool Use
Sometimes you want the model to respond with text only, even when tools are defined:
# Anthropic: tool_choice={"type": "none"}
# OpenAI: tool_choice="none"
# Google: tool_config={"function_calling_config": {"mode": "NONE"}}
Summary: Function Calling vs Tool Use
| Aspect | Function Calling | Tool Use |
|---|---|---|
| Origin | OpenAI (June 2023) | Anthropic (April 2024) |
| Core concept | Model generates function call intent | Model generates tool invocation request |
| Practical difference | Minimal (same underlying capability) | Minimal (same underlying capability) |
| Key architectural difference | Separate tool_calls array | Content blocks alongside text |
| Modern naming trend | Converging on "tools" | Converging on "tools" |
The bottom line: "function calling" and "tool use" describe the same fundamental capability -- the model requesting execution of external code. The terms originated from different providers and are now converging around the "tools" terminology. When building applications, focus on the architectural patterns (simple extraction vs agentic loop vs MCP) rather than the terminology.
NYC News
Expert insights on AI voice agents and customer communication automation.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.