Lesson 1 of 3 · Mastering Function Calling & Tool Use

What Function Calling Is

reading13 min

A product manager asks you to build a chatbot that can check order status. Simple enough -- except the order data lives in your database, not in the model's training data. The model cannot query your database directly. It has no network access, no API credentials, no way to reach your systems.

Function calling solves this. It is the bridge between what the model knows and what your systems can do. The model decides when to call a function and what arguments to pass. Your code executes the function and returns the result. The model synthesizes the result into a natural language response.

This is how ChatGPT checks the weather, books flights, and searches the web. It is the same mechanism behind every useful AI agent. And it is surprisingly simple once you understand the flow.

5 steps

is all it takes to give any AI model access to your real-world systems

The 5-Step Flow

Function calling follows the same pattern every time. No exceptions. Once you internalize this flow, every tool-use implementation becomes a variation on the same theme.

Let's walk through each step with a concrete example: a customer support chatbot that can look up order status.

Step 1: Define Tools and Send the Request

You describe your available functions using JSON Schema. The model reads these descriptions to understand what tools it has and when to use them.

Python
from openai import OpenAI

client = OpenAI()

tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Look up the current status of a customer order by order ID. Use this when a customer asks about their order status, shipping, or delivery.",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "The order ID, e.g., ORD-12345"
                }
            },
            "required": ["order_id"]
        }
    }
}]

response = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {"role": "system", "content": "You are a customer support assistant."},
        {"role": "user", "content": "Where is my order ORD-78901?"}
    ],
    tools=tools
)

Step 2: Model Returns tool_calls

The model does not execute the function. It returns a structured request telling you which function to call and with what arguments:

JSON
{
  "choices": [{
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_abc123",
        "type": "function",
        "function": {
          "name": "get_order_status",
          "arguments": "{\"order_id\": \"ORD-78901\"}"
        }
      }]
    },
    "finish_reason": "tool_calls"
  }]
}

Notice: content is null and finish_reason is "tool_calls". The model is saying: "I need to call this function before I can answer the user."

The Model Never Executes Functions

This is the most important thing to understand about function calling. The model does not have access to your systems. It cannot run code. It returns a structured JSON object describing the function it wants called. Your application executes the function. This means you maintain full control over what happens -- you can validate arguments, add logging, enforce permissions, or reject the call entirely.

Step 3: Execute the Function Locally

Python
import json

# Parse the tool call
tool_call = response.choices[0].message.tool_calls[0]
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)

# Execute YOUR function with YOUR data
def get_order_status(order_id):
    # This queries YOUR database -- the model has no access
    return {
        "order_id": order_id,
        "status": "shipped",
        "carrier": "FedEx",
        "tracking": "FX-9876543",
        "estimated_delivery": "2025-06-15"
    }

result = get_order_status(**arguments)

Step 4: Return the Result as a Tool Message

Python
# Send the result back to the model
follow_up = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {"role": "system", "content": "You are a customer support assistant."},
        {"role": "user", "content": "Where is my order ORD-78901?"},
        response.choices[0].message,  # The assistant's tool_call message
        {
            "role": "tool",
            "tool_call_id": tool_call.id,  # Must match the call ID
            "content": json.dumps(result)
        }
    ],
    tools=tools
)

Step 5: Model Synthesizes the Response

The model now has the function result and produces a natural language answer:

"Your order ORD-78901 has been shipped via FedEx! The tracking number
is FX-9876543, and the estimated delivery date is June 15, 2025.
Would you like me to help with anything else?"

Your First Function Call

beginner
Concept Card

Why This Matters

Without function calling, AI models are limited to what they learned during training. They cannot check your database, call your APIs, send emails, or take any real-world action. Function calling transforms a language model from a static knowledge base into a dynamic agent that can interact with any system you connect it to.

Do

Think of function calling as giving the model a menu of capabilities. Your code is the kitchen. The model takes orders from the user, selects items from the menu, and your code prepares and serves the result.

Don't

Think of function calling as the model executing code. The model suggests actions. Your code executes them. This distinction is fundamental to security and reliability.