By Bonaventure Ogeto|

What Is Function Calling in LLM APIs? Tool Use With Code Examples

Function calling (also called tool use) is a feature of LLM APIs where the model can request that your code execute a specific function with specific arguments, instead of generating a text answer. You describe the available functions and their parameters in the API request. When the model decides a function would help answer the user's question, it returns a structured function call instead of a text response. Your code executes the function, sends the result back, and the model uses it to compose the final answer.

The problem function calling solves

LLMs generate text. They cannot check a database, call an API, or look up live data on their own. Before function calling, developers used awkward hacks: they would prompt the model to output a JSON command, then regex-parse the output to figure out what to call. This was brittle and error-prone.

Function calling makes this a first-class feature. You tell the model "here are the tools you can use," and when it needs one, it returns a structured JSON object with the function name and arguments. No regex. No guessing. The model picks the right tool, fills in the arguments from the conversation, and your code handles execution.

How the function calling flow works

The flow has four steps:

  1. Define tools. You describe each function's name, purpose, and parameter schema in the API request.
  2. Send the request. The user asks a question. The model reads the question and the tool definitions.
  3. Model returns a tool call. Instead of a text response, the model returns a JSON object: { "name": "get_weather", "arguments": { "city": "Nairobi" } }.
  4. Execute and respond. Your code runs the function, gets the result, sends it back to the model. The model then writes a natural-language response using the function's output.

The model never executes anything. It only decides what to call and with what arguments. Your code runs the actual function. This keeps you in control of what the system can do.

Example 1: A weather tool

This TypeScript example defines a weather function and lets the model call it.

import OpenAI from 'openai';

const openai = new OpenAI();

// The actual function your code runs
function getWeather(city: string): string {
  // In production, this would call a weather API
  const data: Record<string, string> = {
    'Nairobi': '22°C, partly cloudy',
    'Mombasa': '31°C, sunny',
    'Kisumu': '27°C, light rain',
  };
  return data[city] ?? 'Weather data not available for this city.';
}

// Define the tool for the model
const tools: OpenAI.ChatCompletionTool[] = [
  {
    type: 'function',
    function: {
      name: 'get_weather',
      description: 'Get current weather for a Kenyan city',
      parameters: {
        type: 'object',
        properties: {
          city: {
            type: 'string',
            description: 'City name, e.g. Nairobi, Mombasa, Kisumu',
          },
        },
        required: ['city'],
      },
    },
  },
];

async function chat(userMessage: string) {
  // Step 1: Send user message with tool definitions
  const response = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      { role: 'system', content: 'You are a helpful assistant.' },
      { role: 'user', content: userMessage },
    ],
    tools,
  });

  const message = response.choices[0].message;

  // Step 2: Check if the model wants to call a tool
  if (message.tool_calls) {
    const toolCall = message.tool_calls[0];
    const args = JSON.parse(toolCall.function.arguments);
    const result = getWeather(args.city);

    // Step 3: Send the tool result back
    const finalResponse = await openai.chat.completions.create({
      model: 'gpt-4o',
      messages: [
        { role: 'system', content: 'You are a helpful assistant.' },
        { role: 'user', content: userMessage },
        message, // includes the tool_calls
        {
          role: 'tool',
          tool_call_id: toolCall.id,
          content: result,
        },
      ],
      tools,
    });

    return finalResponse.choices[0].message.content;
  }

  return message.content;
}

chat('What is the weather in Mombasa?').then(console.log);
// Output: "The current weather in Mombasa is 31°C and sunny."

Example 2: An M-Pesa balance checker stub

Function calling shines when you want a conversational interface over your own APIs. Here is a stub that simulates checking an M-Pesa business account balance.

// Stub function (in production, this calls the Daraja API)
function checkMpesaBalance(shortcode: string): string {
  // Simulated response
  return JSON.stringify({
    shortcode,
    balance: 'KES 142,350.00',
    lastUpdated: '2026-08-04T10:30:00Z',
  });
}

const mpesaTools: OpenAI.ChatCompletionTool[] = [
  {
    type: 'function',
    function: {
      name: 'check_mpesa_balance',
      description: 'Check the M-Pesa business account balance for a given shortcode',
      parameters: {
        type: 'object',
        properties: {
          shortcode: {
            type: 'string',
            description: 'The M-Pesa business shortcode, e.g. 174379',
          },
        },
        required: ['shortcode'],
      },
    },
  },
];

// Usage:
// User: "What is the balance on shortcode 174379?"
// Model returns: tool_call { name: "check_mpesa_balance", arguments: { shortcode: "174379" } }
// Your code runs checkMpesaBalance("174379")
// Model responds: "The M-Pesa balance for shortcode 174379 is KES 142,350.00,
//                  last updated at 10:30 AM today."

The model extracted the shortcode from the natural-language question and called the right function with the right argument. Your user does not need to know anything about APIs or shortcodes. They just ask in plain English (or Swahili).

Working with multiple tools

You can define as many tools as you need. The model decides which one(s) to call based on the user's question. It can even call multiple tools in sequence if the question requires it.

const tools: OpenAI.ChatCompletionTool[] = [
  // weather tool
  { type: 'function', function: { name: 'get_weather', /* ... */ } },
  // M-Pesa balance tool
  { type: 'function', function: { name: 'check_mpesa_balance', /* ... */ } },
  // currency conversion tool
  { type: 'function', function: { name: 'convert_currency', /* ... */ } },
];

If the user asks "What is the balance on 174379 in USD?", the model might call check_mpesa_balance first, then convert_currency with the KES amount. Your code handles each call and sends the results back.

Tips for multiple tools:

  • Write clear descriptions. The model picks tools based on the description, not the function name. A vague description leads to wrong tool selection.
  • Keep parameter schemas strict. Use required and enum fields to constrain what the model can pass. Fewer degrees of freedom means fewer mistakes.
  • Limit the number of tools. Models handle 5 to 15 tools well. Beyond that, selection accuracy drops. If you have 50 tools, group them into categories and use a routing layer.

Safety and validation

The model generates the function arguments from the conversation. Those arguments are user-influenced input. Treat them like any other user input:

  • Validate arguments. Check types, ranges, and allowed values before executing. If the model passes an unexpected shortcode format, reject it.
  • Limit capabilities. Only expose functions the user should have access to. Do not define a "delete_all_records" tool and hope the model will never call it.
  • Log tool calls. Record what the model requested and what your code executed. This is critical for debugging and auditing.
  • Handle errors gracefully. If the function fails, send an error message back as the tool result. The model can then tell the user something went wrong instead of hallucinating a result.

Frequently Asked Questions

Does the model actually run the function?
No. The model only outputs a JSON object describing which function to call and with what arguments. Your application code receives that JSON, executes the function, and sends the result back to the model. The model never has direct access to your APIs or databases.
Is function calling the same as plugins?
Function calling is the underlying mechanism. Plugins (like ChatGPT plugins) are a product layer built on top of function calling. When you use the API directly, you work with function calling. The concept is the same: the model requests actions, your code executes them.
What if the model calls the wrong function?
It happens, especially with vague function descriptions or ambiguous user queries. Improve your function descriptions, add examples in the description string, and validate the arguments before executing. For critical operations, add a confirmation step where the user approves the action before your code runs it.

Ready to build real-world apps?

Join the McTaba Labs full-stack marathon. Ship 8 production apps with M-Pesa, USSD, and WhatsApp integrations, and get career support until placement.

See Programs

Also available: AI Features micro-course