Listen up. If you're building modern applications, understanding Function Calling in AI & Artificial Intelligence is non-negotiable. This is where simple logic turns into intelligent behavior.
1Why LLMs Need Function Calling
An LLM can only generate text — it has no way to check a live weather API, query your database, or send an email on its own. Function calling bridges that gap by letting the model describe, in structured JSON, which function it wants your application to run and with what arguments.
The model never executes anything itself; it only ever produces a request for your code to act on, which keeps all real side effects under your application's control.
// Example
console.log("Running AI concept...");AI logic processed successfully.
2Defining a Tool with a JSON Schema
A tool definition is a small JSON object describing the function's name, a natural-language description of what it does, and a parameters schema listing each argument's name and type. The description field matters more than it looks — the model decides whether and how to call the tool almost entirely based on how clearly that text explains its purpose.
A vague description ('does stuff with weather') leads to the model calling the tool at the wrong times or with malformed arguments far more often than a precise one.
const tools = [{
type: 'function',
function: {
name: 'get_weather',
description: 'Get current temperature',
parameters: {
type: 'object',
properties: {
location: { type: 'string' }
}
}
}
}];AI logic processed successfully.
3Reading a tool_calls Response
When the model decides a tool is needed, it doesn't return normal message content — it returns a tool_calls array containing a call id, the function name it picked, and the arguments it extracted from the user's message, already serialized as a JSON string.
For 'What's the weather in Tokyo?', that means the model has already done the work of pulling out location: "Tokyo" for you; your code just has to parse that JSON and call the real function.
// AI Response:
{
"tool_calls": [
{
"id": "call_123",
"function": { "name": "get_weather", "arguments": "{\"location\":\"Tokyo\"}" }
}
]
}AI logic processed successfully.
4Sending the Result Back with the 'tool' Role
Once your application actually calls the real weather API and gets '22°C', that result gets pushed back onto the messages array as a new entry with role: 'tool' and the matching tool_call_id, then the whole array is sent back to the model for a second completion.
The tool_call_id is what lets the model correctly match a result to the specific request it made, which matters once you're handling multiple tool calls in the same turn.
messages.push({
role: 'tool',
tool_call_id: 'call_123',
content: '22°C'
});
// AI finally answers: 'It is 22°C in Tokyo!'AI logic processed successfully.
5From Function Calling to Agents
Nothing stops you from repeating this call-tool/return-result cycle more than once per turn — that repeated loop, run until the model has enough information to give a final answer, is exactly what turns a single function-calling feature into a full autonomous agent.
Function calling is the mechanism; an agent is just this mechanism wrapped in a loop with a stopping condition.
Status: Agentic
AI logic processed successfully.
6Parallel Tool Calls
Modern models can return several tool_calls entries in a single response — for example requesting get_weather and book_hotel at the same time when a user asks to plan a trip — instead of forcing one round-trip per tool.
Your application code needs to execute all of them (ideally concurrently) and return a matching 'tool' result message for each individual call_id before sending the array back, or the model will be missing an answer it's still waiting on.
// Multi-tool call
"tool_calls": [
{ "function": { "name": "get_weather" } },
{ "function": { "name": "book_hotel" } }
]AI logic processed successfully.
7Forcing a Tool with tool_choice
By default the model decides for itself whether a tool call is even necessary. Setting tool_choice to a specific function name forces it to call exactly that tool regardless of the input, which is useful for fixed workflows like 'always extract structured fields from this form submission' where you never want a plain-text reply.
tool_choice: 'required' is the middle ground — it forces some tool call, but leaves the model free to pick which one.
tool_choice: { type: 'function', function: { name: 'get_weather' } }AI logic processed successfully.
8From Chatbot to Control Center
Once an LLM can reliably call functions, it stops being a text generator and becomes an interface to real actions — booking a flight, updating a database row, or triggering a webhook — all driven by natural language input.
The reliability of that transition rests entirely on your tool schemas and the code that executes them, since the model is only ever as good as the tools you expose to it.
AI: Integrated
AI logic processed successfully.
9Next: Chaining Function Calls into Agents
The next lesson takes this exact call-tool/return-result cycle and wraps it in a loop with reasoning steps and memory, turning a single function call into a fully autonomous, multi-step AI agent.
Agents Next
AI logic processed successfully.
10Step-by-Step Breakdown
LLMs are great at text, but they can't natively act on the world. Function Calling bridges this gap by allowing the AI to 'request' code execution.
Instead of just generating text, we give the LLM a 'Tool'—a JSON schema describing a function's name and its parameters.
When a user asks about Tokyo's weather, the AI doesn't answer; it returns a 'tool_call' request with the location already extracted.
Checkpoint: Does the LLM directly execute the code (e.g., call the weather API) on its own servers?
- →Yes, it runs the API internally
- →No, it just returns a JSON request for YOUR app to execute
Your application receives the JSON, executes the real API call, and gets the result. Then, you send this back to the AI using the 'tool' role.
This loop allows you to build 'Agents' that can book flights, check databases, or control hardware directly from a chat.
Checkpoint: What is the correct 'role' used to send a function's result back to the LLM?
- →role: 'assistant'
- →role: 'tool' (or 'function')
Parallel tool calling is possible. The AI can request multiple function calls at once, like 'Check weather and book a hotel'.
You can force the AI to use a specific tool by setting the 'tool_choice' parameter. This is useful for fixed workflows.
Checkpoint: What happens if you set 'tool_choice' to 'required'?
- →The AI decides if it needs a tool
- →The AI MUST call at least one function
Function calling mastered! Your AI is no longer just a chatbot—it's a control center.
Next, we'll learn how to chain these functions into autonomous 'Multi-Modal Agents'.
Validate a Real Tool Call. Finish checking that a model's requested tool call actually matches one of your registered tools.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Confirm Destructive Tool Calls Before Executing
When a function call would delete data, send money, or send a message on the user's behalf, surface a confirmation dialog with a clearly focus-managed 'Confirm'/'Cancel' pair before actually running it — this protects keyboard and screen-reader users from an AI-initiated action they didn't get a chance to review, the same way you'd never auto-submit a destructive form without confirmation.
<ConfirmDialog action="Delete 12 files" onConfirm={runTool} onCancel={cancel} />SEO Implications
- 1
Tool Schemas Are Backend Contracts, Not Page Content
A function's JSON schema and its runtime execution live entirely in your API layer and are never rendered as page content, so they carry zero SEO weight of their own — what matters for indexing is that a documentation page like this one explains the pattern in real, unique prose rather than templated filler.
Best Practices
Validate Arguments Before Executing, Never Trust Them Blindly
The JSON in a tool_calls response is model-generated text, not verified input — always parse it with a try/catch and validate types and ranges before passing it into a real database query, file operation, or payment API, exactly as you would validate any other untrusted user input.
Keep Tool Descriptions Specific and Narrow
A tool named searchOrders with a description like 'searches the orders table by customer email or order id' gets called correctly far more often than a vague 'looks up stuff' tool, because the model's decision to call it (and how) is driven almost entirely by that description text.
Frequent Bugs
Forgetting to include a 'tool' role message for every entry in a parallel tool_calls response.
If the model requests three parallel tool calls and your code only returns results for two of them, the next API call will error or behave unpredictably because every tool_call_id from the previous turn expects a matching result. Always loop over the full tool_calls array and respond to each one.
Real-World Examples
A Natural-Language Database Query Assistant
An internal analytics tool exposes a runSqlQuery(query: string) function with a strict allowlist of read-only tables in its description; when a manager asks 'how many orders shipped last week', the model calls the tool with a generated SELECT statement, the backend validates it against the allowlist before executing, and the result is returned as the final answer.
const tools = [{
type: 'function',
function: { name: 'runSqlQuery', description: 'Read-only query against orders, customers tables', parameters: { type: 'object', properties: { query: { type: 'string' } } } }
}];