Skip to main content
Tool calling (also known as function calling) enables models to intelligently select and use external tools based on user input. You can build agents that access APIs, retrieve real-time data, or perform actions—all through OpenAI-compatible tool specifications. How it works:
  1. Define tools using JSON Schema (name, description, parameters)
  2. Model analyzes the query and decides whether to call a tool
  3. If needed, model returns structured tool calls with parameters
  4. You execute the tool and send results back for the final response

Quick example

Define tools and send a request - the model will return structured tool calls when needed:
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ.get("FIREWORKS_API_KEY"),
    base_url="https://api.fireworks.ai/inference/v1"
)

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a location",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "City name"}
            },
            "required": ["location"]
        }
    }
}]

response = client.chat.completions.create(
    model="accounts/fireworks/models/kimi-k2-instruct-0905",
    messages=[{"role": "user", "content": "What's the weather in San Francisco?"}],
    tools=tools,
    temperature=0.1
)

print(response.choices[0].message.tool_calls)
# Output: [ChatCompletionMessageToolCall(id='call_abc123', function=Function(arguments='{"location":"San Francisco"}', name='get_weather'), type='function')]
For best results with tool calling, use a low temperature (0.0-0.3) to reduce hallucinated parameter values and ensure more deterministic tool selection.
import os
from openai import OpenAI
import json

client = OpenAI(
    api_key=os.environ.get("FIREWORKS_API_KEY"),
    base_url="https://api.fireworks.ai/inference/v1"
)

# Step 1: Define your tools
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a location",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "City name"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["location"]
        }
    }
}]

# Step 2: Send initial request
messages = [{"role": "user", "content": "What's the weather in San Francisco?"}]
response = client.chat.completions.create(
    model="accounts/fireworks/models/kimi-k2-instruct-0905",
    messages=messages,
    tools=tools,
    temperature=0.1
)

# Step 3: Check if model wants to call a tool
if response.choices[0].message.tool_calls:
    # Step 4: Execute the tool
    tool_call = response.choices[0].message.tool_calls[0]
    
    # Your actual tool implementation
    def get_weather(location, unit="celsius"):
        # In production, call your weather API here
        return {"temperature": 72, "condition": "sunny", "unit": unit}
    
    # Parse arguments and call your function
    function_args = json.loads(tool_call.function.arguments)
    function_response = get_weather(**function_args)
    
    # Step 5: Send tool response back to model
    messages.append(response.choices[0].message)  # Add assistant's tool call
    messages.append({
        "role": "tool",
        "tool_call_id": tool_call.id,
        "content": json.dumps(function_response)
    })
    
    # Step 6: Get final response
    final_response = client.chat.completions.create(
        model="accounts/fireworks/models/kimi-k2-instruct-0905",
        messages=messages,
        tools=tools,
        temperature=0.1
    )
    
    print(final_response.choices[0].message.content)
    # Output: "It's currently 72°F and sunny in San Francisco."

Defining tools

Tools are defined using JSON Schema format. Each tool requires:
  • name: Function identifier (a-z, A-Z, 0-9, underscores, dashes; max 64 characters)
  • description: Clear explanation of what the function does (used by the model to decide when to call it)
  • parameters: JSON Schema object describing the function’s parameters
Write detailed descriptions and parameter definitions. The model relies on these to select the correct tool and provide appropriate arguments.

Parameter types

JSON Schema supports: string, number, integer, object, array, boolean, and null. You can also:
  • Use enum to restrict values to specific options
  • Mark parameters as required or optional
  • Provide descriptions for each parameter
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get current weather for a location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "City name, e.g. San Francisco"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "Temperature unit"
                    }
                },
                "required": ["location"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_restaurants",
            "description": "Search for restaurants by cuisine type",
            "parameters": {
                "type": "object",
                "properties": {
                    "cuisine": {
                        "type": "string",
                        "description": "Type of cuisine (e.g., Italian, Mexican)"
                    },
                    "location": {
                        "type": "string",
                        "description": "City or neighborhood"
                    },
                    "price_range": {
                        "type": "string",
                        "enum": ["$", "$$", "$$$", "$$$$"]
                    }
                },
                "required": ["cuisine", "location"]
            }
        }
    }
]

Additional configurations

tool_choice

The tool_choice parameter controls how the model uses tools:
  • auto (default): Model decides whether to call a tool or respond directly
  • none: Model will not call any tools
  • required: Model must call at least one tool
  • Specific function: Force the model to call a particular function
# Force a specific tool
response = client.chat.completions.create(
    model="accounts/fireworks/models/kimi-k2-instruct-0905",
    messages=[{"role": "user", "content": "What's the weather?"}],
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "get_weather"}},
    temperature=0.1
)
Some models support parallel tool calling, where multiple tools can be called in a single response. Check the model’s capabilities before relying on this feature.

Streaming

Tool calls work with streaming responses. Arguments are sent incrementally as the model generates them:
import json
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ.get("FIREWORKS_API_KEY"),
    base_url="https://api.fireworks.ai/inference/v1"
)

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["city"]
        }
    }
}]

stream = client.chat.completions.create(
    model="accounts/fireworks/models/kimi-k2-instruct-0905",
    messages=[{"role": "user", "content": "What's the weather in San Francisco?"}],
    tools=tools,
    stream=True,
    temperature=0.1
)

# Accumulate tool call data
tool_calls = {}

for chunk in stream:
    if chunk.choices[0].delta.tool_calls:
        for tool_call in chunk.choices[0].delta.tool_calls:
            index = tool_call.index
            
            if index not in tool_calls:
                tool_calls[index] = {"id": "", "name": "", "arguments": ""}
            
            if tool_call.id:
                tool_calls[index]["id"] = tool_call.id
            if tool_call.function and tool_call.function.name:
                tool_calls[index]["name"] = tool_call.function.name
            if tool_call.function and tool_call.function.arguments:
                tool_calls[index]["arguments"] += tool_call.function.arguments
    
    if chunk.choices[0].finish_reason == "tool_calls":
        for tool_call in tool_calls.values():
            args = json.loads(tool_call["arguments"])
            print(f"Calling {tool_call['name']} with {args}")
        break

Troubleshooting

  • Check that your tool descriptions are clear and detailed
  • Ensure the user query clearly indicates a need for the tool
  • Try using tool_choice="required" to force tool usage
  • Verify your model supports tool calling (check supportsTools field)
  • Add more detailed parameter descriptions
  • Use lower temperature (0.0-0.3) for more deterministic outputs
  • Provide examples in parameter descriptions
  • Use enum to constrain values to specific options
  • Always validate tool call arguments before parsing
  • Handle partial or malformed JSON gracefully in production
  • Use try-catch blocks when parsing tool_call.function.arguments

Next steps