Function calling is the API feature that lets a language model return a structured request to run a function you have defined, with arguments matching a JSON schema. Introduced by OpenAI in 2023 and now supported across major providers, it is the concrete developer-facing mechanism behind tool calling. The terms are often used interchangeably; “function calling” usually emphasises the API mechanics, while “tool calling” emphasises the agent capability.
Key takeaways
- You define functions with a name, description and JSON schema.
- The model returns a function name plus arguments as structured JSON.
- Your code executes the function and returns the result to the model.
- It also works as a reliable way to get structured output, even with no function to run.
- Schema design and descriptions determine how well it works.
Function calling explained in simple terms
Instead of hoping a model writes “call get_weather for Pune” in prose that you then have to parse, you hand it a form. It fills in the form fields precisely, and your code reads them. The model supplies intent and parameters; your software keeps the execution.
Defining a function
A definition typically contains:
- name: `get_invoice_status`
- description: “Look up the payment status of an invoice by its number.”
- parameters: a JSON schema, for example an object with a required string `invoice_number` and an optional boolean `include_history`.
The description is what the model reads when deciding whether this function fits the request, so write it for clarity, not brevity.
The request-response cycle
- Send the conversation plus function definitions.
- The model responds either with normal text or with a function call.
- If it is a function call, parse the JSON arguments.
- Validate them against your schema and business rules.
- Execute the function.
- Send the result back as a function or tool result message.
- The model produces the final answer, or calls another function.
A worked example
User: “Has invoice 2041 been paid?”
The model returns:
{ "name": "get_invoice_status", "arguments": { "invoice_number": "2041" } }
Your code calls the accounting system, gets `{“status”: “unpaid”, “due_date”: “2026-09-01”, “amount”: 18450}`, returns it, and the model answers: “Invoice 2041 is unpaid. It was due on 1 September for ₹18,450.”
Practical guidance
| Practice | Reason |
|---|---|
| Write detailed descriptions | The model selects functions by reading them |
| Use enums for fixed choices | Prevents invented values |
| Mark required fields | Reduces missing arguments |
| Keep functions single-purpose | Improves selection accuracy |
| Validate everything | Models can produce plausible but wrong arguments |
| Return concise results | Large payloads consume context |
| Handle “no function needed” | Sometimes a plain answer is correct |
Function calling for structured data
Even without executing anything, function calling is a dependable way to extract structured data: define a function whose schema matches the fields you want, and use the arguments as your output. Many teams used this before dedicated structured-output modes existed, and it remains a common pattern.
Parallel and multi-step calls
Modern APIs allow several function calls in one response, useful when requests are independent, such as checking three invoices. Sequential calls happen across turns, when one result determines the next step.
Limitations
- Models can hallucinate arguments, so validation is essential.
- Very large function lists reduce selection accuracy.
- Schema support differs slightly between providers.
- Execution, permissions and safety remain entirely your responsibility.
