Function calling, also called tool use, is a capability that lets a large language model request that your code run a specific function — such as a…
See the division of labor: the model decides the call, your code runs it.
Function calling adds one capability to a language model: instead of only writing text, it can output a structured request to call one of the functions you gave it. Crucially, the model does not run anything — it emits the function name and arguments, and your code executes the function.
You send the user's message plus a list of available tools; the model decides whether a tool is needed and, if so, which one and with what arguments; your code runs it and passes the result back so the model can finish the answer.
Language models cannot look up live data, do exact arithmetic, or change the world on their own. Function calling bridges that gap by letting the model reach real systems — search, databases, calculators, APIs — in a controlled, structured way, turning a text generator into something that can act.
Describe a function so the model knows when and how to call it.
A tool definition has three parts. The name identifies the function. The description tells the model what the tool does and when to use it — this is what the model reads to decide, so it should be clear and specific. The parameters are a JSON Schema describing the arguments, including types and which are required.
The schema is not just documentation: providers use it to constrain the model's output so the arguments come back well-typed and valid, which is what makes the call safe to execute.
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}The description drives selection — the model reads it to decide this tool fits a weather question. The parameters schema forces a single required string 'city', so the model returns arguments your code can trust without extra parsing.
Walk one complete request, tool execution, and final answer.
A single tool use takes two model turns. On the first turn the model, given the question and tools, returns a tool call instead of an answer. Your code runs the function and appends the result to the conversation. On the second turn the model reads that result and writes the natural-language answer.
If a task needs several tools, this repeats — call, execute, observe — which is exactly the loop that becomes an agent.
resp = model.chat(messages, tools=[weather_tool]) if resp.tool_call: # turn 1: model requests a tool args = resp.tool_call.arguments # {"city": "Paris"} result = get_weather(**args) # YOUR code runs it messages += [resp, tool_result(result)] resp = model.chat(messages, tools=[weather_tool]) # turn 2 print(resp.text) # grounded final answer
The first call yields a tool_call, not prose. Your code executes get_weather, appends the result, and calls the model again; only then does it produce the final answer, now grounded in real data. The if-branch is where you validate arguments before running anything.
Place a single tool call against the multi-step loop that makes an agent.
Function calling is the building block; an agent is what you get when you run it in a loop with a goal. A single function call answers one question that needs one tool. An agent keeps deciding, calling, and observing across many steps until a goal is met.
If your task is 'what's the weather in Paris,' one call suffices. If it is 'plan and book a trip,' you need an agent that chains many tool calls, decides the order at run time, and stops when done.
Avoid the errors that make tool use unreliable or unsafe.
The frequent failures are avoidable. Vague descriptions make the model pick the wrong tool or none — write descriptions that say exactly when to use each. Loose schemas let bad arguments through — mark required fields and constrain types and enums. Trusting arguments blindly is a security risk — validate them before executing, since the model can be steered by injected content.
Also give too many tools and selection degrades; keep the set small and distinct. And never let a tool take an irreversible action without validation or human approval.
Function calling (tool use) lets a language model output a structured request to run one of your functions; the model decides the call, your code executes it and returns the result, and the model answers grounded in real data. You define tools with a name, description, and JSON Schema. A single call handles one need; running it in a loop toward a goal is what makes an agent. Clear descriptions, strict schemas, and argument validation keep it reliable and safe.
Design a tool a support bot could call — say lookup_order(order_id). Write its name, description, and JSON Schema, then list two argument validations you would run before executing it and one action you would never let it take without human approval.
What is function calling in LLMs?
Function calling lets the model request a specific tool with arguments; the model decides, but your code performs the execution.
How does an LLM know which function to call?
The model selects based on the tool descriptions, which is why clear, specific descriptions are essential; the JSON Schema then shapes valid arguments.
Does the LLM execute the function itself?
Execution is always on your side; this separation is what lets you validate arguments and control what the tool can do.
What is the difference between function calling and an AI agent?
Function calling is the primitive; an agent is the loop built on top of it that chains many tool calls until a goal is met.