Skip to main content
Tool calling (also called function calling) allows models to request the execution of specific functions you define. The model decides when to call a tool and with what arguments — your application executes the tool and returns the result. ARouter supports tool calling for all major providers. The interface follows the OpenAI tool calling standard.

How It Works

Tool calling follows a 3-step cycle:
  1. Inference with tools — You send a request with tool definitions. The model decides to call a tool and returns a tool_calls response.
  2. Tool execution (client-side) — Your application runs the requested function and collects the result.
  3. Inference with tool results — You send the tool result back to the model, which generates a final response.

Step 1: Inference with Tools

{
  "model": "openai/gpt-5.4",
  "messages": [
    { "role": "user", "content": "What is the weather in San Francisco?" }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get the current weather for a location",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name, e.g. 'San Francisco'"
            },
            "unit": {
              "type": "string",
              "enum": ["celsius", "fahrenheit"]
            }
          },
          "required": ["location"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}
The model responds with a tool_calls array:
{
  "id": "chatcmpl-xxx",
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_abc123",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"location\": \"San Francisco\", \"unit\": \"fahrenheit\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ]
}

Step 2: Tool Execution (Client-Side)

Your application executes the function with the model’s arguments:
import json

tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)

# Execute your function
result = get_weather(
    location=args["location"],
    unit=args.get("unit", "fahrenheit")
)
# result = {"temperature": 72, "condition": "sunny", "unit": "fahrenheit"}

Step 3: Inference with Tool Results

Send the tool result back as a tool role message:
{
  "model": "openai/gpt-5.4",
  "messages": [
    { "role": "user", "content": "What is the weather in San Francisco?" },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": "{\"location\": \"San Francisco\", \"unit\": \"fahrenheit\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_abc123",
      "content": "{\"temperature\": 72, \"condition\": \"sunny\", \"unit\": \"fahrenheit\"}"
    }
  ],
  "tools": [...]
}

Full Example

import json
from openai import OpenAI

client = OpenAI(
    base_url="https://api.arouter.ai/v1",
    api_key="lr_live_xxxx",
)

# Define the tool
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather for a location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "City name, e.g. 'San Francisco'",
                    },
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                },
                "required": ["location"],
            },
        },
    }
]

messages = [{"role": "user", "content": "What is the weather in San Francisco?"}]

# Step 1: First inference
response = client.chat.completions.create(
    model="openai/gpt-5.4",
    messages=messages,
    tools=tools,
    tool_choice="auto",
)

assistant_message = response.choices[0].message
messages.append(assistant_message)

# Step 2: Execute tools
if assistant_message.tool_calls:
    for tool_call in assistant_message.tool_calls:
        if tool_call.function.name == "get_weather":
            args = json.loads(tool_call.function.arguments)
            # Simulate weather API
            result = {"temperature": 72, "condition": "sunny", "unit": args.get("unit", "fahrenheit")}

            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(result),
            })

# Step 3: Final inference
final_response = client.chat.completions.create(
    model="openai/gpt-5.4",
    messages=messages,
    tools=tools,
)

print(final_response.choices[0].message.content)
# "The current weather in San Francisco is 72°F and sunny."

Streaming Tool Calls

When streaming is enabled, tool call arguments are delivered incrementally via delta.tool_calls:
const stream = await client.chat.completions.create({
  model: "openai/gpt-5.4",
  messages: [{ role: "user", content: "What's the weather in NYC?" }],
  tools,
  stream: true,
});

let toolCallArgs = "";
let toolCallId = "";
let toolCallName = "";

for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta;

  if (delta?.tool_calls) {
    const tc = delta.tool_calls[0];
    if (tc.id) toolCallId = tc.id;
    if (tc.function?.name) toolCallName = tc.function.name;
    if (tc.function?.arguments) toolCallArgs += tc.function.arguments;
  }

  if (chunk.choices[0]?.finish_reason === "tool_calls") {
    // All arguments have been received
    const args = JSON.parse(toolCallArgs);
    console.log(`Calling ${toolCallName} with:`, args);
  }
}

Supported Models

Use GET /v1/models to find models that support tool calling. Models with tools in their capabilities list support this feature.
curl https://api.arouter.ai/v1/models \
  -H "Authorization: Bearer lr_live_xxxx"
Tool calling is supported by most frontier models, including:
  • openai/gpt-5.4, openai/gpt-5.4-pro
  • anthropic/claude-sonnet-4.6, anthropic/claude-opus-4.5
  • google/gemini-2.5-flash, google/gemini-2.5-pro
  • deepseek/deepseek-v3.2