> ## Documentation Index
> Fetch the complete documentation index at: https://inference-docs.cerebras.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Tool Calling

> Learn how to connect models to external tools with tool calling.

Tool calling, also known as tool use or function calling, lets a model request functions that your application defines. Your application executes each requested function and returns the result to the model.

| Model | `tool_choice` | Strict mode | Parallel calls | Multi-turn calling | Availability |
| - | - | - | - | - | - |
| [`qwen-3.8-27b`](/models/qwen-3.8-27b) | `none`, `auto`, `required`, named function | Yes | Yes | Yes | Shared Inference |
| `kimi-k2.7-code` | `none`, `auto`, `required`, named function | Yes | Yes | Yes | Customer trials only |
| [`gpt-oss-120b`](/models/openai-oss) | `none`, `auto`, `required`, named function | Yes | Yes | Yes | Shared Inference |
| [`gemma-4-31b`](/dedicated/overview#supported-models) | `none`, `auto`, `required`, named function | Yes | Yes | Yes | Dedicated Inference |

See [Strict mode for tool calling](#strict-mode-for-tool-calling) for model-specific schema requirements.

## How it works

1. **Define the tool**: Provide a name, description, and input parameters for each tool you want the model to access.

2. **Send the request**: The prompt is sent along with available tool definitions in your API call.

3. **Select a tool**: The model determines whether a tool can help answer the request. If so, it returns the tool name and arguments.

4. **Execute the tool**: The client application receives the model's tool call request, executes the specified tool (such as calling an external API), and retrieves the result.

5. **Generate the final response**: Send the tool result to the model so it can continue the conversation.

## Basic tool calling

<Steps>
  <Step title="Set up the client">
    Import the required libraries and initialize the Cerebras client.

    <Tip>
      If you have not configured an API key, complete the [Quickstart](/quickstart) first.
    </Tip>

    ```python theme={null}
    import os
    import json
    import re
    from cerebras.cloud.sdk import Cerebras

    # Initialize Cerebras client
    client = Cerebras(
        api_key=os.environ.get("CEREBRAS_API_KEY"),
    )
    ```
  </Step>

  <Step title="Define the function">
    Define the function that the application executes. This example uses a calculator that performs basic arithmetic.

    ```python theme={null}
    def calculate(expression):
        expression = re.sub(r'[^0-9+\-*/().]', '', expression)
        
        try:
            result = eval(expression)
            return str(result)
        except (SyntaxError, ZeroDivisionError, NameError, TypeError, OverflowError):
            return "Error: Invalid expression"
    ```
  </Step>

  <Step title="Define the tool schema">
    Define the tool name, description, and parameters that the model can use.

    <Note>
      For schemas in the supported JSON Schema subset, `strict: true` uses constrained decoding to guarantee that tool-call arguments conform to the schema.
    </Note>

    ```python theme={null}
    tools = [
        {
            "type": "function",
            "function": {
                "name": "calculate",
                "strict": True,
                "description": "A calculator tool that can perform basic arithmetic operations. Use this when you need to compute mathematical expressions or solve numerical problems.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "expression": {
                            "type": "string",
                            "description": "The mathematical expression to evaluate"
                        }
                    },
                    "required": ["expression"],
                    "additionalProperties": False
                }
            }
        }
    ]
    ```
  </Step>

  <Step title="Send the request">
    Send the messages and tool schema. The response can include a tool call.

    ```python theme={null}
    messages = [
        {"role": "system", "content": "You are a helpful assistant with access to a calculator. Use the calculator tool to compute mathematical expressions when needed."},
        {"role": "user", "content": "What's the result of 15 multiplied by 7?"},
    ]

    response = client.chat.completions.create(
        model="qwen-3.8-27b",
        messages=messages,
        tools=tools,
        parallel_tool_calls=False,
    )
    ```
  </Step>

  <Step title="Handle the tool call">
    Check the response for a tool call. If one is present, execute the requested function and return its result to the model.

    ```python theme={null}
    choice = response.choices[0].message

    if choice.tool_calls:
        function_call = choice.tool_calls[0].function
        if function_call.name == "calculate":
            # Logging that the model is executing a function named "calculate".
            print(f"Model executing function '{function_call.name}' with arguments {function_call.arguments}")

            # Parse the arguments from JSON format and perform the requested calculation.
            arguments = json.loads(function_call.arguments)
            result = calculate(arguments["expression"])

            # Note: This is the result of executing the model's request (the tool call), not the model's own output.
            print(f"Calculation result sent to model: {result}")
           
           # Send the result back to the model to fulfill the request.
            messages.append({
                "role": "tool",
                "content": json.dumps(result),
                "tool_call_id": choice.tool_calls[0].id
            })
     
           # Request the final response from the model, now that it has the calculation result.
            final_response = client.chat.completions.create(
                model="qwen-3.8-27b",
                messages=messages,
            )
            
            # Handle and display the model's final response.
            if final_response:
                print("Final model output:", final_response.choices[0].message.content)
            else:
                print("No final response received")
    else:
        # Handle cases where the model's response does not include expected tool calls.
        print("Unexpected response from the model")
    ```
  </Step>
</Steps>

The example produces output similar to the following:

```
Model executing function 'calculate' with arguments {"expression": "15 * 7"}
Calculation result sent to model: 105
Final model output: 15 * 7 = 105
```

## Strict mode for tool calling

For schemas that use the supported JSON Schema subset, strict mode guarantees that tool-call arguments conform to the schema.

### Why strict mode matters for tools

Without strict mode, tool calls can contain:

* Incorrect parameter types, such as `"2"` instead of `2`
* Missing required parameters
* Unexpected parameters
* Malformed argument JSON

Strict mode prevents these schema violations for supported schemas.

### Enable strict mode

Set `strict` to `true` inside the `function` object of your tool definition:

```python Python theme={null}
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "strict": True,  # Enable constrained decoding
            "description": "Get the current weather for a location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "City and country, such as San Francisco, USA"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"]
                    }
                },
                "required": ["location", "unit"],
                "additionalProperties": False
            }
        }
    }
]
```

### Schema requirements

When using strict mode, you must set `additionalProperties: false`. This is required for every object in your schema.

For information about schema limitations that apply when using strict mode, see [Limitations in Strict Mode](/capabilities/structured-outputs#limitations-in-strict-mode).

<Note>
  For `kimi-k2.7-code`, either set the same `strict` value on every function in the request or omit it from every function. For `qwen-3.8-27b`, do not use `pattern`, `minLength`, or `maxLength` in strict tool schemas.
</Note>

### Strict mode with parallel tool calling

Strict mode works with parallel tool calling. When multiple tools are called simultaneously, each tool call's arguments will conform to its respective schema:

```python Python theme={null}
response = client.chat.completions.create(
    model="qwen-3.8-27b",
    messages=messages,
    tools=tools,  # Each tool can have strict: true
    parallel_tool_calls=True,
)
```

## Multi-turn tool calling

Most real-world workflows require more than one tool invocation. Multi-turn tool calling lets a model call a tool, incorporate its output, and then, within the same conversation, decide whether it needs to call the tool (or another tool) again to finish the task.

1. Append each tool result to `messages` and ask the model to continue.
2. Let the model determine whether it needs another tool call.
3. Continue calling `client.chat.completions.create()` until the response does not contain `tool_calls`.

The following example extends the calculator example. Complete steps 1 through 3 in [Basic tool calling](#basic-tool-calling) before running it.

```python theme={null}
messages = [
    {
        "role": "system",
        "content": (
            "You are a helpful assistant with a calculator tool. "
            "Use it whenever math is required."
        ),
    },
    {"role": "user", "content": "First, multiply 15 by 7. Then take that result, add 20, and divide the total by 2. What's the final number?"},
]

# Register every callable tool once
available_functions = {
    "calculate": calculate,
}

while True:
    resp = client.chat.completions.create(
        model="qwen-3.8-27b",
        messages=messages,
        tools=tools,
    )
    msg = resp.choices[0].message

    # If the assistant didn’t ask for a tool, we’re done
    if not msg.tool_calls:
        print("Assistant:", msg.content)
        break

    # Save the assistant turn exactly as returned
    messages.append(msg.model_dump())    

    # Run the requested tool
    call  = msg.tool_calls[0]
    fname = call.function.name

    if fname not in available_functions:
        raise ValueError(f"Unknown tool requested: {fname!r}")

    args_dict = json.loads(call.function.arguments)  # assumes JSON object
    output = available_functions[fname](**args_dict)

    # Feed the tool result back
    messages.append({
        "role": "tool",
        "tool_call_id": call.id,
        "content": json.dumps(output),
    })
```

## Parallel tool calling

Parallel tool calling lets a model request multiple independent tool calls in one response, which can reduce latency.

For example, if a user asks "Is Toronto warmer than Montreal?", the model needs to check the weather in both cities. Rather than making two separate requests, parallel tool calling enables the model to request both operations at once, reducing latency and improving efficiency.

Use parallel tool calling when:

* A request requires multiple independent data points, such as weather in different cities.
* Tool calls do not depend on the results of other tool calls.

### Enable parallel tool calling

You can explicitly control this behavior using the `parallel_tool_calls` parameter:

```python highlight={5} theme={null}
response = client.chat.completions.create(
    model="qwen-3.8-27b",
    messages=messages,
    tools=tools,
    parallel_tool_calls=True,  # Enable parallel calling (default)
)
```

To disable parallel tool calling and force sequential execution:

```python highlight={5} theme={null}
response = client.chat.completions.create(
    model="qwen-3.8-27b",
    messages=messages,
    tools=tools,
    parallel_tool_calls=False,  # Disable parallel calling
)
```

### Example: Weather comparison

The following example requests weather data for two cities in parallel.

<Steps>
  <Step title="Define the weather tool">
    Define a weather function and its tool schema.

    ```python theme={null}
    import os
    import json
    from cerebras.cloud.sdk import Cerebras

    client = Cerebras(
        api_key=os.environ.get("CEREBRAS_API_KEY"),
    )

    def get_weather(location):
        """
        Dummy function that returns mock weather data.
        In production, this would call a real weather API.
        """
        weather_data = {
            "location": location,
            "temperature": 22,
            "condition": "sunny",
            "humidity": 45,
        }
        return json.dumps(weather_data)

    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "strict": True,
                "description": "Get temperature for a given location.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "City and country, such as Toronto, Canada"
                        }
                    },
                    "required": ["location"],
                    "additionalProperties": False
                }
            }
        }
    ]
    ```
  </Step>

  <Step title="Send the request">
    Send a request that requires weather data for two cities.

    ```python theme={null}
    messages = [
        {
            "role": "system",
            "content": "You are a helpful assistant."
        },
        {
            "role": "user",
            "content": "Is Toronto warmer than Montreal?"
        }
    ]

    response = client.chat.completions.create(
        model="qwen-3.8-27b",
        messages=messages,
        tools=tools,
        parallel_tool_calls=True,
    )
    ```
  </Step>

  <Step title="Handle multiple tool calls">
    Iterate through every entry in the response's `tool_calls` array.

    ```python theme={null}
    choice = response.choices[0].message

    if choice.tool_calls:
        # Add the assistant message with tool_calls first
        messages.append(choice)

        # Process all tool calls
        for tool_call in choice.tool_calls:
            function_call = tool_call.function
            print(f"Model executing function '{function_call.name}' with arguments {function_call.arguments}")
            
            # Parse arguments and execute the function
            arguments = json.loads(function_call.arguments)
            result = get_weather(arguments["location"])
            
            print(f"Weather data sent to model: {result}")
            
            # Append each tool result to messages
            messages.append({
                "role": "tool",
                "content": result,
                "tool_call_id": tool_call.id
            })
        
        # Get final response after all tool calls are processed
        final_response = client.chat.completions.create(
            model="qwen-3.8-27b",
            messages=messages,
        )
        
        if final_response:
            print("Final model output:", final_response.choices[0].message.content)
        else:
            print("No final response received")
    else:
        print("No tool calls in response")
    ```
  </Step>
</Steps>
