Skip to content

Tools

Tool calling enables the model to request specific actions from your application. Instead of generating a text response, the model returns structured function calls with arguments, which your code can execute and optionally feed back into the conversation. This is the foundation for building agents, assistants, and any application that needs to interact with external systems.

Defining Tools

Tools are defined as arrays following the OpenAI function calling format. Each tool describes a function's name, purpose, and expected parameters:

<?php

$weatherTool = [
    'type' => 'function',
    'function' => [
        'name' => 'get_weather',
        'description' => 'Get the current weather for a location',
        'parameters' => [
            'type' => 'object',
            'properties' => [
                'location' => [
                    'type' => 'string',
                    'description' => 'The city and country (e.g., "Paris, France")',
                ],
                'unit' => [
                    'type' => 'string',
                    'enum' => ['celsius', 'fahrenheit'],
                    'description' => 'The temperature unit to use',
                ],
            ],
            'required' => ['location'],
        ],
    ],
];

Making a Tool Call Request

Pass your tool definitions via the tools parameter and control how the model selects tools with toolChoice:

<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Data\ToolChoice;
use Cognesy\Polyglot\Inference\Data\ToolDefinitions;
use Cognesy\Polyglot\Inference\Inference;

$response = Inference::using('openai')
    ->with(
        messages: Messages::fromString('What is the weather like in Paris?'),
        tools: ToolDefinitions::fromArray([$weatherTool]),
        toolChoice: ToolChoice::auto(),
    )
    ->response();

Processing Tool Call Results

The response object provides methods for inspecting whether the model made tool calls and extracting their details:

<?php

if ($response->hasToolCalls()) {
    $toolCalls = $response->toolCalls();

    foreach ($toolCalls->all() as $call) {
        $name = $call->name();        // e.g. 'get_weather'
        $args = $call->args();        // e.g. ['location' => 'Paris, France']
        $id   = $call->idString();    // unique call ID string for multi-turn conversations

        // Execute the function and use the result...
    }
} else {
    // The model responded with text instead
    echo $response->content();
}

Convenience Accessors

For simple cases where you just need the tool call arguments as data, Polyglot provides shortcut methods:

<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Data\ToolChoice;
use Cognesy\Polyglot\Inference\Data\ToolDefinitions;
use Cognesy\Polyglot\Inference\Inference;

// Get tool call arguments as a JSON string
$json = Inference::using('openai')
    ->with(
        messages: Messages::fromString('Get the weather for Paris.'),
        tools: ToolDefinitions::fromArray([$weatherTool]),
        toolChoice: ToolChoice::auto(),
    )
    ->asToolCallJson();

// Or as a decoded PHP array
$data = Inference::using('openai')
    ->with(
        messages: Messages::fromString('Get the weather for Paris.'),
        tools: ToolDefinitions::fromArray([$weatherTool]),
        toolChoice: ToolChoice::auto(),
    )
    ->asToolCallJsonData();

When the model returns a single tool call, asToolCallJsonData() returns that call's arguments as an array. When multiple tool calls are returned, it returns an array of all calls.

Controlling Tool Selection

The toolChoice parameter controls how the model decides whether to use tools:

<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Data\ToolChoice;
use Cognesy\Polyglot\Inference\Data\ToolDefinitions;
use Cognesy\Polyglot\Inference\Inference;

$toolDefs = ToolDefinitions::fromArray($tools);

// Let the model decide whether to call a tool or respond with text
$response = Inference::using('openai')
    ->with(
        messages: Messages::fromString('What is the weather like in Paris?'),
        tools: $toolDefs,
        toolChoice: ToolChoice::auto(),
    )
    ->response();

// Force the model to call a specific tool
$response = Inference::using('openai')
    ->with(
        messages: Messages::fromString('What is the weather like in Paris?'),
        tools: $toolDefs,
        toolChoice: ToolChoice::specific('get_weather'),
    )
    ->response();

// Prevent tool usage entirely (model responds with text)
$response = Inference::using('openai')
    ->with(
        messages: Messages::fromString('What is the weather like in Paris?'),
        tools: $toolDefs,
        toolChoice: ToolChoice::none(),
    )
    ->response();

Multiple Tools

You can provide multiple tool definitions in a single request. The model will select the most appropriate one based on the user's message:

<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Data\ToolChoice;
use Cognesy\Polyglot\Inference\Data\ToolDefinitions;
use Cognesy\Polyglot\Inference\Inference;

$tools = [
    [
        'type' => 'function',
        'function' => [
            'name' => 'get_weather',
            'description' => 'Get the current weather for a location',
            'parameters' => [
                'type' => 'object',
                'properties' => [
                    'location' => ['type' => 'string'],
                ],
                'required' => ['location'],
            ],
        ],
    ],
    [
        'type' => 'function',
        'function' => [
            'name' => 'get_flight_info',
            'description' => 'Get information about a flight',
            'parameters' => [
                'type' => 'object',
                'properties' => [
                    'flight_number' => ['type' => 'string'],
                    'date' => ['type' => 'string'],
                ],
                'required' => ['flight_number'],
            ],
        ],
    ],
];

$response = Inference::using('openai')
    ->with(
        messages: Messages::fromString('What is the status of flight AA123?'),
        tools: ToolDefinitions::fromArray($tools),
        toolChoice: ToolChoice::auto(),
    )
    ->response();

Using the Fluent API

The fluent builder methods withTools() and withToolChoice() offer an alternative to passing everything through with():

<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Data\ToolChoice;
use Cognesy\Polyglot\Inference\Data\ToolDefinitions;
use Cognesy\Polyglot\Inference\Inference;

$response = Inference::using('openai')
    ->withMessages(Messages::fromString('Get the weather for Paris.'))
    ->withTools(ToolDefinitions::fromArray([$weatherTool]))
    ->withToolChoice(ToolChoice::auto())
    ->response();

Provider Support

Tool calling support varies across providers:

Provider Tool Calling Tool Choice
OpenAI Yes Yes (auto, none, specific function)
Anthropic Yes Yes
Groq Yes Yes
Gemini Yes Varies by model
Other providers Varies Varies

You can query tool support programmatically through DriverCapabilities::supportsToolCalling() and DriverCapabilities::supportsToolChoice().

When to Use Tool Calling

Tool calling is ideal for:

  • Building agents that interact with external APIs and services
  • Creating assistants that retrieve real-time information
  • Implementing multi-step workflows where the model orchestrates actions
  • Extracting structured data using function schemas (an alternative to JSON Schema mode)
  • Giving the model access to specific capabilities like calculations, database queries, or file operations