Skip to main content

Overview

Function calling (also called tool use) allows LLMs to call external functions and APIs. LiteLLM provides a unified interface that automatically translates between different provider formats.

Quick Start

from litellm import completion

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather in a location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "City and state, e.g. San Francisco, CA"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"]
                    }
                },
                "required": ["location"]
            }
        }
    }
]

response = completion(
    model="gpt-4o",
    messages=[{"role": "user", "content": "What's the weather in NYC?"}],
    tools=tools
)

if response.choices[0].message.tool_calls:
    for tool_call in response.choices[0].message.tool_calls:
        print(f"Function: {tool_call.function.name}")
        print(f"Arguments: {tool_call.function.arguments}")

Defining Functions

Standard format used by LiteLLM.
tools = [
    {
        "type": "function",
        "function": {
            "name": "search_database",
            "description": "Search the product database",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Search query"
                    },
                    "category": {
                        "type": "string",
                        "enum": ["electronics", "clothing", "books"]
                    },
                    "max_results": {
                        "type": "integer",
                        "description": "Max number of results",
                        "default": 10
                    }
                },
                "required": ["query"]
            }
        }
    }
]

Function Calling Flow

from litellm import completion
import json

# Step 1: Define tools
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
            "description": "Get current stock price",
            "parameters": {
                "type": "object",
                "properties": {
                    "symbol": {"type": "string", "description": "Stock symbol"}
                },
                "required": ["symbol"]
            }
        }
    }
]

# Step 2: Initial request
messages = [{"role": "user", "content": "What's AAPL stock price?"}]
response = completion(
    model="gpt-4o",
    messages=messages,
    tools=tools
)

# Step 3: Check for tool calls
if response.choices[0].message.tool_calls:
    # Step 4: Execute functions
    for tool_call in response.choices[0].message.tool_calls:
        function_name = tool_call.function.name
        arguments = json.loads(tool_call.function.arguments)
        
        if function_name == "get_stock_price":
            # Execute your function
            result = {"symbol": arguments["symbol"], "price": 150.25}
            
            # Step 5: Add tool response to messages
            messages.append(response.choices[0].message)
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(result)
            })
    
    # Step 6: Get final response
    final_response = completion(
        model="gpt-4o",
        messages=messages,
        tools=tools
    )
    print(final_response.choices[0].message.content)

Tool Choice Control

Let the model decide whether to call functions.
response = completion(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
    tools=tools
    # tool_choice="auto" is implicit
)

Provider Support

Native support with full features.
from litellm import completion

response = completion(
    model="gpt-4o",
    messages=[{"role": "user", "content": "What's the weather?"}],
    tools=tools
)

Streaming with Function Calls

from litellm import completion

response = completion(
    model="gpt-4o",
    messages=[{"role": "user", "content": "What's the weather in NYC?"}],
    tools=tools,
    stream=True
)

tool_calls_buffer = []
content_buffer = ""

for chunk in response:
    delta = chunk.choices[0].delta
    
    # Handle tool call deltas
    if delta.tool_calls:
        for tool_call_delta in delta.tool_calls:
            # Accumulate tool call information
            if tool_call_delta.function.name:
                print(f"\nCalling: {tool_call_delta.function.name}")
            if tool_call_delta.function.arguments:
                print(tool_call_delta.function.arguments, end="")
    
    # Handle content
    elif delta.content:
        content_buffer += delta.content
        print(delta.content, end="")

Parallel Function Calls

Some providers support calling multiple functions simultaneously.
from litellm import completion
import json

tools = [
    {"type": "function", "function": {"name": "get_weather", ...}},
    {"type": "function", "function": {"name": "get_time", ...}}
]

response = completion(
    model="gpt-4o",
    messages=[{"role": "user", "content": "What's the weather and time in NYC?"}],
    tools=tools,
    parallel_tool_calls=True  # Enable parallel calls
)

# Handle multiple tool calls
if response.choices[0].message.tool_calls:
    for tool_call in response.choices[0].message.tool_calls:
        print(f"Call {tool_call.id}: {tool_call.function.name}")
        # Execute functions in parallel

Complex Parameter Types

tools = [
    {
        "type": "function",
        "function": {
            "name": "book_flight",
            "description": "Book a flight",
            "parameters": {
                "type": "object",
                "properties": {
                    "departure": {
                        "type": "object",
                        "properties": {
                            "city": {"type": "string"},
                            "airport": {"type": "string"},
                            "date": {"type": "string", "format": "date"}
                        },
                        "required": ["city", "date"]
                    },
                    "arrival": {
                        "type": "object",
                        "properties": {
                            "city": {"type": "string"},
                            "airport": {"type": "string"}
                        },
                        "required": ["city"]
                    },
                    "passengers": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "name": {"type": "string"},
                                "age": {"type": "integer"}
                            }
                        }
                    },
                    "class": {
                        "type": "string",
                        "enum": ["economy", "business", "first"]
                    }
                },
                "required": ["departure", "arrival"]
            }
        }
    }
]

Error Handling

from litellm import completion
import json

try:
    response = completion(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Get weather"}],
        tools=tools
    )
    
    if response.choices[0].message.tool_calls:
        for tool_call in response.choices[0].message.tool_calls:
            try:
                args = json.loads(tool_call.function.arguments)
                # Execute function
                result = execute_function(tool_call.function.name, args)
            except json.JSONDecodeError:
                print("Invalid JSON in arguments")
            except Exception as e:
                print(f"Function execution error: {e}")
                # Return error to model
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": json.dumps({"error": str(e)})
                })
                
except Exception as e:
    print(f"Completion error: {e}")

Best Practices

  • Write clear, detailed descriptions
  • Explain when the function should be used
  • Include example values in parameter descriptions
  • Be specific about parameter formats
  • Use descriptive parameter names
  • Mark only truly required parameters as required
  • Provide enums for fixed choices
  • Use appropriate JSON schema types
  • Always validate function arguments
  • Handle JSON parsing errors gracefully
  • Return structured error messages to the model
  • Include relevant context in function results
  • Keep full conversation history in messages
  • Include both assistant and tool messages
  • Allow multiple tool call rounds if needed
  • Provide clear context in tool results

Advanced Patterns

def call_with_retry(messages, tools, max_retries=3):
    for attempt in range(max_retries):
        response = completion(
            model="gpt-4o",
            messages=messages,
            tools=tools
        )
        
        if response.choices[0].message.tool_calls:
            try:
                # Execute and validate
                result = execute_tools(response.choices[0].message.tool_calls)
                return result
            except Exception as e:
                # Add error feedback
                messages.append(response.choices[0].message)
                messages.append({
                    "role": "tool",
                    "content": f"Error: {e}. Please try again."
                })
        else:
            return response
    
    raise Exception("Max retries exceeded")

Debugging

import litellm
from litellm import completion

# Enable debug logging
litellm.set_verbose = True

response = completion(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Get weather"}],
    tools=tools
)

# Inspect tool calls
if response.choices[0].message.tool_calls:
    for i, tool_call in enumerate(response.choices[0].message.tool_calls):
        print(f"\nTool Call {i}:")
        print(f"  ID: {tool_call.id}")
        print(f"  Type: {tool_call.type}")
        print(f"  Function: {tool_call.function.name}")
        print(f"  Arguments: {tool_call.function.arguments}")

Build docs developers (and LLMs) love