编程

Laravel 及 ChatGPT "函数调用" 的使用

1094 2023-08-04 12:16:00

最近,OpenAI 发布了一个 ChatGPT 更新,引入新特性,使开发者可以描述语言模型函数 - gpt-4-0613 和 gpt-3.5-turbo-0613。这些特性允许生成包含参数的 JSON 对象,以便根据用户输入运行这些函数。

让我们来探讨一下这个新功能的示例。您可以使用它来获取有关 IP 地址、以前的订单、常见问题解答中的信息、天气预报或任何其他所需信息。

为了演示它是如何工作的,我们将使用 openaiphp/client 库。首先,通过运行以下命令创建 Artisan 命令:

php artisan make:command ChatFunction

更新 ChatFunction 类如下:

namespace App\Console\Commands;

use Illuminate\Console\Command;
use OpenAI\Client;

class ChatFunction extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:chat-function';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Invoke a chat function with OpenAI language model.';

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $client = new Client(config('openai.api_key'));

        $response = $client->chat()->create([
            'model'    => 'gpt-3.5-turbo-0613',
            'messages' => [
                ['role' => 'user', 'content' => 'What do you know about IP address 12.175.87.227?'],
            ],
        ]);

        $answer = $response->choices[0]->message->content;

        $this->info("OpenAI response: $answer");
    }
}

如果我们向 AI 询问有关特定 IP 地址的信息,它可能会回答说:“很抱歉,但我无法提供有关特定 IP 的信息。”

为了解决这个问题,让我们在请求中指定函数。

namespace App\Console\Commands;

use Illuminate\Console\Command;

class ChatFunction extends Command
{
    public function handle()
    {
        $client = \OpenAI::factory()
            ->withApiKey(config('openai.api_key'))
            ->make();

        $response = $client->chat()->create([
            'model'     => 'gpt-3.5-turbo-0613',
            'messages'  => [
                ['role' => 'user', 'content' => 'What do you know about IP 12.175.87.227 ?'],
            ],
            'functions' => [
                [
                    'name'        => 'about_ip',
                    'description' => 'Get information about the IP address',
                    'parameters'  => [
                        'type'       => 'object',
                        'properties' => [
                            'ip' => [
                                'type'        => 'string',
                                'description' => 'IP address v4',
                            ],
                        ],
                        'required'   => ['ip'],
                    ],
                ],
            ],
        ]);

        // As we can see, we now have a proposal to call a function on our side and there are arguments:  
        $name = $response->choices[0]->message->functionCall->name; // ip_info  
        $arguments = $response->choices[0]->message->functionCall->arguments; // {\n "ip": "12.175.87.227" }  
    }
}

现在,我们已经准备好了数据,例如要调用的函数的名称及其参数。我认为执行此类任务的一个很好的解决方案是使用 Sajya 包,它简化了在控制台和作为 API 使用 JSON-RPC 的工作。因此,让我们使用这个包创建一个简单的类:

使用 Laravel 的 CLI 手动创建名为 “AboutIp” 的新过程的命令:

php artisan make:procedure AboutIp

现在,我们添加一个有用的 action: 

namespace App\Http\Procedures;  

use Illuminate\Support\Collection;  
use Illuminate\Support\Facades\Http;  
use Sajya\Server\Procedure;  

class AboutIp extends Procedure  
{  
    /**  
     * The name of the procedure that is used for referencing.  
     * 
     * @var string  
     */  
    public static string $name = 'about';  

    /**  
     * Execute the procedure.  
     * 
     * @param string $ip  
     * @return Collection  
     */  
    public function ip(string $ip): Collection  
    {  
        return Http::get('http://ip-api.com/json/' . $ip)->collect();  
    }  
}

这个 “about_ip” 过程只接收一个 IP 地址,从另外一个 API 中获取信息,并返回给用户。

让我们回到控制台命令,添加一个方法来创建和调用远程过程调用(RPC):

protected function callRPC(string $method, ?string $params = null): ?string
{
    $app = new App([
        \App\Http\Procedures\AboutIp::class,
    ], '_');

    $response = $app->terminate(json_encode([
        'jsonrpc' => '2.0',
        'method'  => $method,
        'params'  => json_decode($params, true),
        'id'      => 1,
    ]));

    return json_encode($response, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}

如果我们只是通过名称和参数调用它,我们不会收到人类回应。要获得该信息,我们需要参考 ChatGPT:

/**
 * Execute the console command.
 */
public function handle()
{
    $client = \OpenAI::factory()
        ->withApiKey(config('openai.api_key'))
        ->make();

    $response = $client->chat()->create([
        'model'     => 'gpt-3.5-turbo-0613',
        'messages'  => [
            ['role' => 'user', 'content' => 'What do you know about IP 12.175.87.227 ?'],
        ],
        'functions' => [
            [
                'name'        => 'about_ip',
                'description' => 'Get information about the IP address',
                'parameters'  => [
                    'type'       => 'object',
                    'properties' => [
                        'ip' => [
                            'type'        => 'string',
                            'description' => 'IP address v4',
                        ],
                    ],
                    'required'   => ['ip'],
                ],
            ],
        ],
    ]);

    // As we can see, we now have a proposal to call a function on our side and there are arguments:
    $name = $response->choices[0]->message->functionCall->name; // ip_info
    $arguments = $response->choices[0]->message->functionCall->arguments; // {\n "ip": "12.175.87.227" }


    $functionResult = $this->callRPC($name, $arguments);

    // Again we turn to ChatGPT, but this time we add the response from the function:
    $response = $client->chat()->create([
        'model'     => 'gpt-3.5-turbo-0613',
        'messages'  => [
            ['role' => 'user', 'content' => 'What do you know about IP 12.175.87.227 ?'],
            ['role' => 'function', 'name' => $name, 'content' => $functionResult],
        ],
        'functions' => [
            [
                'name'        => 'about_ip',
                'description' => 'Get information about the IP address',
                'parameters'  => [
                    'type'       => 'object',
                    'properties' => [
                        'ip' => [
                            'type'        => 'string',
                            'description' => 'IP address v4',
                        ],
                    ],
                    'required'   => ['ip'],
                ],
            ],
        ],
    ]);

    $response->choices[0]->message->content;

    // The IP address 12.175.87.227 is located in San Diego, California, United States.
    // The postal code is 92110.
    // The latitude and longitude coordinates are 32.7616 and -117.2058 respectively.
    // The timezone of this location is America/Los_Angeles.
    // The ISP (Internet Service Provider) is AT&T Services, Inc.
    // The organization associated with this IP address is Coffman Specialties.
    // The Autonomous System (AS) number is AS7018 AT&T Services, Inc.
}

现在我们获得人类回应,并使用该 ChatGPT ”特性“去丰富实际信息。