Ctrl + K
AI16 min read

Function Calling Explained

Understand how function calling allows LLMs to interact with APIs, databases, and application functions, including the complete request flow, schemas, validation, security, errors, and practical TypeScript examples.

Published: 2026-09-14

Function calling is a capability that allows a language model to request the execution of predefined functions or tools. Instead of generating only natural-language text, the model can determine that an external operation is needed, provide structured arguments for that operation, and then use the returned result to produce an answer.

For example, a user might ask, "What is the weather in London?" A language model does not automatically have access to a weather service. With function calling, it can request a function such as getWeather with London as an argument. The application executes that function, returns the result to the model, and the model generates the final response.

Function calling is an important building block for AI assistants, chatbots, agents, customer-support systems, coding tools, and applications that need to connect language models with real-world data or actions.

What Is Function Calling?

Function calling creates a controlled interface between an LLM and application code. The developer defines which functions are available and describes the arguments each function accepts. The model can then select an appropriate function when a user's request requires it.

User request
      ↓
   LLM model
      ↓
Function call + arguments
      ↓
Application backend
      ↓
Execute function
      ↓
External API / Database / Service
      ↓
Result
      ↓
Application backend
      ↓
Tool result
      ↓
   LLM model
      ↓
Final response

Function Calling vs Normal Text Generation

A normal language model response contains text intended for the user. Function calling introduces another possible output: a structured request to execute a specific function.

ApproachModel OutputTypical Use
Text generationNatural languageAnswering questions
Structured outputStructured dataReturning predictable data
Function callingFunction name + argumentsCalling external operations

The distinction is important. Structured output describes the format of information returned by the model, while function calling describes an interaction in which the model requests an operation defined by the application.

A Simple Example

Suppose an application has a server-side function called getWeather. The function accepts a city and returns weather information.

async function getWeather(city: string) {
  const response = await fetch(
    `https://example.com/weather?city=${encodeURIComponent(city)}`
  );

  return response.json();
}

The model can be given a tool definition describing this function. If the user asks about the weather, the model can return a tool call instead of trying to invent weather information.

{
  "name": "getWeather",
  "arguments": {
    "city": "London"
  }
}

The application receives this structured request, executes getWeather, and sends the result back to the model.

The Complete Function Calling Flow

A function-calling interaction usually consists of several steps. Understanding this sequence makes it easier to design and debug tool-enabled AI applications.

  • The user sends a natural-language request.
  • The application sends the request and available tool definitions to the model.
  • The model decides whether a tool is needed.
  • The model returns a tool call with a function name and arguments.
  • The backend validates the requested function and arguments.
  • The backend executes the function.
  • The backend sends the function result back to the model.
  • The model uses the result to generate the final response.

Defining a Function Schema

The model needs a description of each available function. A schema normally specifies the function name, its purpose, and the parameters it accepts.

{
  "name": "getWeather",
  "description": "Get the current weather for a city",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "Name of the city"
      }
    },
    "required": ["city"]
  }
}

Modern AI APIs commonly use JSON Schema-like definitions for tool arguments, although the exact request format differs between providers.

Why Function Schemas Matter

The schema is part of the interface between the model and the application. A vague or incomplete schema can cause the model to select the wrong function or produce unsuitable arguments.

  • Use descriptive function names.
  • Clearly explain what each function does.
  • Describe every parameter.
  • Specify required parameters.
  • Use appropriate parameter types.
  • Avoid exposing unnecessary functions.
  • Keep tool descriptions consistent with actual behavior.
💡 A function description should explain when the tool is useful and what it actually does. Do not describe capabilities that the implementation does not provide.

The Model Does Not Execute the Function

One of the most important concepts in function calling is that the model normally does not directly execute your application code. It produces a structured request. Your application decides whether and how to execute it.

LLM:
"Call getWeather with city=London"
        ↓
Backend:
Validate request
        ↓
Execute getWeather()
        ↓
Return result to LLM

This separation is essential for security. The backend remains responsible for authorization, validation, business rules, and execution.

Validate Tool Arguments

Even when the model produces structured arguments, the backend should not blindly trust them. Model output is still untrusted input.

function validateWeatherArgs(args: unknown) {
  if (!args || typeof args !== "object") {
    throw new Error("Invalid arguments");
  }

  const city = (args as { city?: unknown }).city;

  if (typeof city !== "string" || !city.trim()) {
    throw new Error("Invalid city");
  }

  return city.trim();
}

For more complex applications, use a schema validation library or equivalent server-side validation rather than relying only on TypeScript types. TypeScript types disappear at runtime and cannot validate data received from the model.

Validate the Function Name Too

The backend should also verify that the requested function is actually available. Never dynamically execute arbitrary code based on a model-generated function name.

const tools = {
  getWeather,
  getTime,
};

const tool = tools[toolName as keyof typeof tools];

if (!tool) {
  throw new Error("Unknown tool");
}

The available function registry should be explicitly controlled by application code.

Returning the Function Result

After the backend executes the function, its result is sent back to the model as tool output. The model can then interpret the result and generate a natural-language response.

{
  "tool": "getWeather",
  "result": {
    "temperature": 18,
    "unit": "C",
    "condition": "Cloudy"
  }
}

The model might then produce a response such as: "It is currently 18°C and cloudy in London." The exact final wording is generated by the model using the tool result as context.

Multiple Function Calls

An application can expose multiple tools. For example, an assistant could have tools for searching products, checking inventory, calculating shipping costs, and creating orders.

FunctionPurpose
searchProductsFind products matching criteria
getProductRetrieve product details
checkInventoryCheck available stock
calculateShippingCalculate delivery options
createOrderCreate an order

The model can select the function that best matches the user's request. Depending on the API, it may also request multiple tool calls in one model response.

Sequential Tool Calls

Some tasks require one tool result before another tool can be selected. For example, an assistant may first search for a product, then use the returned product identifier to retrieve detailed information.

User request
     ↓
searchProducts()
     ↓
Product ID
     ↓
getProduct(productId)
     ↓
Final answer

This pattern is one of the foundations of agentic workflows, where the model repeatedly chooses tools based on the results of previous operations.

Parallel Tool Calls

Some independent operations can be performed in parallel. For example, if an assistant needs weather information for several cities and each request is independent, executing them concurrently can reduce total latency.

const results = await Promise.all([
  getWeather("London"),
  getWeather("Paris"),
  getWeather("Berlin"),
]);

Parallel execution should only be used when the operations are independent and safe to execute concurrently.

Function Calling for External APIs

One of the most common uses of function calling is connecting an LLM to external APIs. The model determines what information is needed, while the application performs the actual HTTP request.

User
  ↓
"Find today's exchange rate"
  ↓
LLM
  ↓
getExchangeRate({ from, to })
  ↓
Backend
  ↓
HTTP request
  ↓
Exchange-rate API
  ↓
Result
  ↓
Backend → LLM → User

Function Calling for Databases

Function calling can also provide controlled access to application data. Instead of allowing a model to construct arbitrary database queries, the application can expose narrowly defined functions.

async function getCustomerOrders(customerId: string) {
  return database.order.findMany({
    where: {
      customerId,
    },
  });
}

This approach gives the application much more control over which data the model can access. Authorization should still be checked against the authenticated user rather than delegated to the model.

Function Calling for Application Actions

Tools can do more than retrieve information. They can also perform actions such as creating records, sending messages, scheduling events, or updating application settings.

Actions that have meaningful side effects require stronger safeguards than read-only operations. A chatbot should not be able to perform a sensitive action merely because the model requested it.

  • Verify the authenticated user's permissions.
  • Validate all arguments.
  • Check business rules.
  • Limit which tools each user can access.
  • Require confirmation for high-impact operations when appropriate.
  • Record important actions in audit logs.

Read-Only vs Write Tools

Tool TypeExampleRisk
Read-onlySearch documentationUsually lower
Read-onlyGet account balancePotentially sensitive
WriteCreate an orderHigher
WriteDelete a recordHigh
External actionSend an emailPotentially high

Tool permissions should be designed according to the consequences of an operation, not simply according to whether the model can technically call it.

Function Calling and Security

Function calling expands what an AI application can do, but it also expands its attack surface. A malicious or manipulated prompt can attempt to make the model request an inappropriate tool call.

The model should therefore be treated as an untrusted decision-making component rather than a security boundary.

  • Never rely on the model for authorization.
  • Validate tool arguments server-side.
  • Use allowlisted tools.
  • Restrict tool access by user and role.
  • Keep secrets out of model-visible tool results.
  • Validate external identifiers.
  • Limit dangerous operations.
  • Log security-sensitive actions.

Prevent Prompt Injection From Reaching Tools

Prompt injection becomes particularly important when the model can call tools. An attacker may attempt to manipulate the model into retrieving private information or performing an action that the user is not authorized to perform.

Untrusted user content
          ↓
        LLM
          ↓
     Tool request
          ↓
     Authorization
          ├── Reject
          └── Execute

The backend should independently determine whether the current user is allowed to perform the requested operation. The model's decision should never override those rules.

Validate Tool Results Too

Validation should not stop at the function arguments. Tool results may come from external services and should be checked before being passed into subsequent application logic.

  • Verify expected response structure.
  • Handle missing or invalid fields.
  • Apply reasonable size limits.
  • Avoid forwarding unnecessary sensitive data.
  • Handle external service errors.
  • Treat external content as untrusted when it can influence further tool calls.

Error Handling

Functions can fail because of invalid arguments, unavailable services, authorization problems, timeouts, network errors, or application bugs. The chatbot should handle these failures without exposing internal implementation details.

ErrorRecommended Response
Invalid argumentsReject the call and return a safe error
Unknown functionReject the request
Unauthorized actionDo not execute the function
External API failureReturn a controlled tool error
TimeoutStop or retry according to policy
Application errorLog details server-side and return a safe message

Depending on the AI API, the application may allow the model to see a controlled tool error and decide whether to retry, select another tool, or explain that the operation could not be completed.

Avoid Infinite Tool Loops

An agentic application can accidentally enter a loop in which the model repeatedly calls tools without reaching a final answer.

LLM -> Tool -> LLM -> Tool -> LLM -> Tool -> ...

Set a maximum number of tool iterations or another execution budget. This protects both application resources and AI API costs.

Limit Tool Execution Time

External tools can be slow or unavailable. A chatbot should not wait indefinitely for a tool to finish.

const controller = new AbortController();

const timeout = setTimeout(() => {
  controller.abort();
}, 5000);

try {
  const response = await fetch(url, {
    signal: controller.signal,
  });

  return await response.json();
} finally {
  clearTimeout(timeout);
}

Function Calling and Streaming

Function calling can be combined with streaming. An application may stream normal assistant text while also receiving structured tool-call events.

When a tool call is detected, the backend can collect the required arguments, validate them, execute the tool, and then continue the model interaction with the tool result.

LLM stream
   ├── Text chunk
   └── Tool call
         ↓
     Execute tool
         ↓
     Tool result
         ↓
Continue LLM stream

This architecture is more complex than simple text streaming because the application must distinguish generated text from tool-call events and manage the additional model round trip.

Function Calling vs Structured Output

Function calling and structured output are related but solve different problems. Structured output is useful when the application wants the model to return data in a predictable schema. Function calling is useful when the application wants the model to request an operation.

RequirementBetter Fit
Return a JSON objectStructured output
Extract fields from textStructured output
Call an external APIFunction calling
Query application dataFunction calling
Perform an application actionFunction calling
Return predictable machine-readable dataStructured output

Function Calling vs Hard-Coded Intent Detection

Before function calling became common, developers often used manually defined intent classifiers. The application would classify a user's request and then choose a function using custom rules.

User text
   ↓
Intent classifier
   ├── weather → getWeather()
   ├── order → getOrder()
   └── search → searchProducts()

Function calling allows the language model to select from explicitly described tools and produce structured arguments. This can reduce custom intent-routing code, although application-side validation and authorization are still required.

Designing Good Tools

The quality of the tool interface strongly affects how reliably the model can use it. Tools should represent clear application capabilities rather than exposing an unnecessarily large collection of low-level functions.

  • Give each tool one clear responsibility.
  • Use descriptive names.
  • Keep parameters focused.
  • Use strict parameter types.
  • Make required fields explicit.
  • Return concise and useful results.
  • Avoid exposing internal implementation details.
  • Separate read and write operations when appropriate.
💡 A small set of well-designed tools is usually easier for both the model and the application to manage than dozens of overlapping functions.

Keep Tool Results Small

Tool results become part of the model's context. Returning unnecessary data increases token usage and can make it harder for the model to identify the information that matters.

For example, a database function that only needs to tell the model whether an order exists should not necessarily return the complete customer record, internal identifiers, audit information, and unrelated metadata.

Monitor Function Calls

Production systems should monitor tool usage separately from normal model responses. Useful metrics include which tools are called, how often they fail, execution latency, and how many model turns are required to complete a task.

MetricWhy It Matters
Tool call countShows which capabilities are used
Tool failure rateIdentifies unreliable integrations
Execution latencyFinds slow external operations
Arguments rejectedReveals schema or model issues
Iterations per requestDetects inefficient agent behavior
Tool-related costHelps control overall AI spending

Common Mistakes

  • Trusting model-generated arguments without validation.
  • Allowing arbitrary function names.
  • Using the model as an authorization system.
  • Exposing too many tools at once.
  • Giving tools vague descriptions.
  • Returning excessive data from tools.
  • Allowing dangerous actions without confirmation.
  • Ignoring tool execution timeouts.
  • Allowing unlimited tool-call loops.
  • Exposing sensitive information through tool results.
  • Failing to monitor tool execution and errors.
  • Automatically retrying failed actions without considering side effects.

Best Practices

  • Define explicit tools with clear schemas.
  • Keep tool execution on the server.
  • Validate every function name and argument.
  • Perform authorization independently of the model.
  • Use allowlists for available tools.
  • Separate read-only and write operations when useful.
  • Apply timeouts to external calls.
  • Limit the number of tool iterations.
  • Return concise tool results.
  • Protect sensitive data.
  • Log important tool executions.
  • Measure tool latency and failure rates.
  • Test normal, invalid, and adversarial requests.

Frequently Asked Questions

What is function calling in AI?

Function calling is a capability that allows a language model to request a predefined application function with structured arguments. The application executes the function and can provide the result back to the model.

Does the LLM execute functions itself?

Usually no. The model generates a structured tool or function request, while the application's backend validates and executes the corresponding function.

Is function calling the same as structured output?

No. Structured output is primarily used to make model responses conform to a predictable data schema. Function calling is used when the model needs to request an operation such as calling an API, querying data, or performing an application action.

Are function calls secure by default?

No. Function calling provides a structured interface, but the application must still validate arguments, enforce authorization, restrict available tools, protect sensitive data, and control dangerous operations.

Can an LLM call multiple functions?

Yes. Depending on the API and application design, a model can request multiple tool calls either sequentially or in parallel. The backend should execute them according to explicit application rules.

What can function calling be used for?

Common uses include calling external APIs, searching databases, retrieving account information, querying internal systems, performing calculations, creating records, sending messages, and connecting AI assistants to application capabilities.

Conclusion

Function calling gives language models a controlled way to interact with software outside the model itself. Instead of expecting an LLM to know real-time information or directly perform application operations, the model can request a predefined function and receive its result.

The core architecture is straightforward: define tools, send their schemas to the model, receive a function call, validate it, execute the operation on the server, return the result, and let the model generate the final response.

The difficult part is making tool use reliable and secure. Production applications need strict validation, authorization, timeouts, execution limits, error handling, monitoring, and protection against prompt injection. When these controls are implemented correctly, function calling becomes a powerful foundation for AI assistants and agentic applications.

Found an issue?

Found an error, outdated information, or something missing from this article? Let me know through the Contact page.

Your feedback helps improve our articles and keep them accurate and useful.