Skip to content

Feature Function Calling #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

moassaad
Copy link
Contributor

@moassaad moassaad commented Mar 4, 2025

Feature Function Calling

Deepseek has added a new feature, which is function calling.
Function Calling allows the model to call external tools to enhance its capabilities.[1]

src: https://api-docs.deepseek.com/guides/function_calling

Features In Package

Adding client trait HasToolsFunctionCalling and use it to DeepSeekClient: It has many added functions :-

  • setTools Passing the list of tools by the client.
  • queryToolCall Passing the functions called by the form to the query.
  • buildToolCallQuery Formatting the called functions to pass them to the query.
  • queryTool Passing the result of the function from its identifier to the query.
  • buildToolQuery Formatting the result of the function to pass it to the query.

Adding static properties to QueryRoles :-

  • ASSISTANT Assigned by default when passing the called functions.
  • TOOL Assigned by default when passing the result of the executed functions.

Adding static properties to QueryFlags :-

  • TOOLS Added by default when passing the tools to the form.

Adding test :-

  • ClientDependency/FakeResponse fake response to function calling test.
  • FunctionCallingTest function calling test.

Implementation steps

You Can See The Complete Example In Test `FunctionCallingTest`

In the example, the basic flow consists of two requests and they are in order:

1. Define the tools used by the model and pass them with each message passed to the model, Receive query messages from the end user and pass them to the model with the defined tools.

  • example function get_weather($city).
function get_weather($city)
{
    $city = strtolower($city);
    $city = match($city){
        "cairo" => ["temperature"=> 22, "condition" => "Sunny"],
        "gharbia" => ["temperature"=> 23, "condition" => "Sunny"],
        "sharkia" => ["temperature"=> 24, "condition" => "Sunny"],
        "beheira" => ["temperature"=> 21, "condition" => "Sunny"],
        default => "not found city name."
    };
    return json_encode($city);
}

The user requests the weather in Cairo.

$client = DeepSeekClient::build('your-api-key')
    ->query('What is the weather like in Cairo?')
    ->setTools([
        [
            "type" => "function",
            "function" => [
                "name" => "get_weather",
                "description" => "Get the current weather in a given city",
                "parameters" => [
                    "type" => "object",
                    "properties" => [
                        "city" => [
                            "type" => "string",
                            "description" => "The city name",
                        ],
                    ],
                    "required" => ["city"],
                ],
            ],
        ],
    ]
);

$response = $client->run();

Output response like.

{
    "id": "chat_12345",
    "object": "chat.completion",
    "created": 1677654321,
    "model": "deepseek-chat",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": null,
                "tool_calls": [
                    {
                        "id": "call_12345",
                        "type": "function",
                        "function": {
                            "name": "get_weather",
                            "arguments": "{\"city\": \"Cairo\"}"
                        }
                    }
                ]
            },
            "finish_reason": "tool_calls"
        }
    ]
}

2. Receive the response and check if it has called one or more tools to execute it in the system ,And execute the tool called by the model.

The deepseek api responds to the system and requests the execution of the tool responsible for fetching the weather status.

$response = $client->run();

$response = json_decode($response, true);
$message = $response['choices'][0]['message'];
$firstFunction = $message['tool_calls'][0];
if ($firstFunction['function']['name'] == "get_weather")
{
    $weather_data = get_weather($firstFunction['function']['arguments']['city']);
}

3. Coordinate the results and send the previous response with the results of the executed tools.

Formats the response, and sends it back to the form.

$response2 = $client->queryToolCall(
        $message['tool_calls'],
        $message['content'],
        $message['role']
    )->queryTool(
        $firstFunction['id'],
        $weather_data
);

Request like

{
    "messages": [
        {
            "role": "user",
            "content": "What is the weather like in Cairo?"
        },
        {
            "content": "What is the weather like in Cairo?",
            "tool_calls": [
                {
                    "id": "930c60df-3ec75f81e00e",
                    "type": "function",
                    "function": {
                        "name": "get_weather",
                        "arguments": {
                            "city": "Cairo"
                        }
                    }
                }
            ],
            "role": "assistant"
        },
        {
            "role": "tool",
            "tool_call_id": "930c60df-3ec75f81e00e",
            "content": "{\"temperature\":22,\"condition\":\"Sunny\"}"
        }
    ],
    "model": "deepseek-chat",
    "stream": false,
    "temperature": 1.3,
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "Get the current weather in a given city",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "city": {
                            "type": "string",
                            "description": "The city name"
                        }
                    },
                    "required": [
                        "city"
                    ]
                }
            }
        }
    ]
}

4. Receive the final response from the model and pass it to the end user.

The deepseek api responds with the final response, which is the weather status according to the data passed to it in the example.

$response2 = $response2->run();
echo $response2;

Output response like :-

{
    "id": "chat_67890",
    "object": "chat.completion",
    "created": 1677654322,
    "model": "deepseek-chat",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "The weather in Cairo is 22℃."
            },
            "finish_reason": "stop"
        }
    ]
}

@ELHADJ1989
Copy link

function get_weather($city)
{
$city = strtolower($city);
$city = match($city){
"cairo" => ["temperature"=> 22, "condition" => "Sunny"],
"gharbia" => ["temperature"=> 23, "condition" => "Sunny"],
"sharkia" => ["temperature"=> 24, "condition" => "Sunny"],
"beheira" => ["temperature"=> 21, "condition" => "Sunny"],
default => "not found city name."
};
return json_encode($city);
}

@moassaad
Copy link
Contributor Author

Full Example

  1. example definition function get_weather($city)
function get_weather($city)
{
    $city = strtolower($city);
    $city = match($city){
        "cairo" => ["temperature"=> 22, "condition" => "Sunny"],
        "gharbia" => ["temperature"=> 23, "condition" => "Sunny"],
        "sharkia" => ["temperature"=> 24, "condition" => "Sunny"],
        "beheira" => ["temperature"=> 21, "condition" => "Sunny"],
        default => "not found city name."
    };
    return json_encode($city);
}
  1. example function calling
use DeepSeek\DeepSeekClient;

$client = DeepSeekClient::build('your-api-key')
    ->query('What is the weather like in Cairo?')
    ->setTools([
        [
            "type" => "function",
            "function" => [
                "name" => "get_weather",
                "description" => "Get the current weather in a given city",
                "parameters" => [
                    "type" => "object",
                    "properties" => [
                        "city" => [
                            "type" => "string",
                            "description" => "The city name",
                        ],
                    ],
                    "required" => ["city"],
                ],
            ],
        ],
    ]
  );

  $response = $client->run();

  $response = json_decode($response, true);

  $message = $response['choices'][0]['message'];
  $firstFunction = $message['tool_calls'][0];

  if ($firstFunction['function']['name'] == "get_weather")
  {
      $args = json_decode($firstFunction['function']['arguments'], true);
      $weather_data = get_weather($args['city']);
  }
  
  $client2 = $client->queryToolCall(
          $message['tool_calls'],
          $message['content'],
          $message['role']
      )->queryTool(
          $firstFunction['id'],
          $weather_data,
          'tool'
  );

  $response2 = $client2->run();

  echo $response2;

@Nafania
Copy link

Nafania commented Apr 9, 2025

Definitely a very needed feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants