見出し画像

ChatGPT APIの新機能「Function calling」を試してみた。

はじめに

本日、2023年6月14日 ChatGPTのAPIの新機能として「Function calling」が公開されました。

Function callingとは

これまで公開されていたChatGPTの「プラグイン」機能は、下記の画像のように、ブラウザのChatGPTから外部サービスを自然言語で利用可能にするものでした。

ChatGPT プラグイン 食べログ

今回発表された「Function calling」を利用すると、ChatGPTからだけではなく、例えばLINEのような外部サービスから、食べログのようなサービスを利用することが可能になります。
(厳密には、食べログはChatGPTプラグインは公開しておりますが、APIは公開していないため、LINEから食べログの利用はできなそうです。)

GASでFunction callingを触ってみた。

Function callingの公式ドキュメント( https://platform.openai.com/docs/guides/gpt/function-calling )に記載されている天気の情報を取得するサンプルコードを、GASで動くように書いてみました。
それに加えて、2点間の距離を問われた場合にはGoogle MapsのAPIを利用して答えるような処理をテスト的に追加してみました。

const OPENAI_APIKEY = PropertiesService.getScriptProperties().getProperty('OPENAI_APIKEY');
const CHAT_GPT_URL = 'https://api.openai.com/v1/chat/completions';

function myFunction() {
  const userMessage = '東京から大阪までの距離を教えて。';

  try {
    const chatGptMessage = getChatGPTResponse(userMessage);
    console.log(chatGptMessage);
  } catch (error) {
    console.error(error);
  }
}

function getChatGPTResponse(userMessage) {
  const response = sendGptRequest(userMessage);
  if (response.choices[0].message.function_call) {
    const function_name = response.choices[0].message.function_call.name;
    console.log('function_name: ' + function_name);
    const function_arguments = JSON.parse(response.choices[0].message.function_call.arguments);
    let function_response;
    if (function_name === 'get_current_weather') {
      const location = function_arguments.location;
      function_response = getCurrentWeather(location);
    } else if (function_name === 'get_distance_between_locations') {
      const start_location = function_arguments.start_location;
      const end_location = function_arguments.end_location;
      function_response = getRoute(start_location, end_location);
    }
    return sendGptRequestWithFunction(userMessage, response.choices[0].message, function_name, function_response);
  } else {
    return response.choices[0].message.content.trim();
  }
}

function sendGptRequest(userMessage) {
  const requestOptions = createRequestOptions(userMessage);
  try {
    const response = UrlFetchApp.fetch(CHAT_GPT_URL, requestOptions);
    return JSON.parse(response.getContentText());
  } catch (error) {
    console.error(error);
    throw new Error('GPT API request failed.');
  }
}

function sendGptRequestWithFunction(userMessage, message, functionName, functionResponse) {
  const requestOptions = createRequestOptionsWithFunction(userMessage, message, functionName, functionResponse);
  try {
    const response = UrlFetchApp.fetch(CHAT_GPT_URL, requestOptions);
    return JSON.parse(response.getContentText()).choices[0].message.content.trim();
  } catch (error) {
    console.error(error);
    throw new Error('GPT API request with function failed.');
  }
}

function createRequestOptions(userMessage) {
  return {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + OPENAI_APIKEY
    },
    "payload": JSON.stringify({
      "model": "gpt-3.5-turbo-0613",
      "messages": [{ "role": "user", "content": userMessage }],
      "functions": getFunctionDefinitions(),
    })
  };
}

function createRequestOptionsWithFunction(userMessage, message, functionName, functionResponse) {
  return {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + OPENAI_APIKEY
    },
    "payload": JSON.stringify({
      "model": "gpt-3.5-turbo-0613",
      'messages': [
        { "role": "user", "content": userMessage },
        message,
        {
          "role": "function",
          "name": functionName,
          "content": functionResponse,
        },
      ],
      "functions": getFunctionDefinitions(),
    })
  };
}

function getFunctionDefinitions() {
  return [
    {
      "name": "get_current_weather",
      "description": "Get the current weather in a given location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "The city and state, e.g. San Francisco, CA"
          },
          "unit": {
            "type": "string",
            "enum": ["celsius", "fahrenheit"]
          }
        },
        "required": ["location"]
      }
    },
    {
      "name": "get_distance_between_locations",
      "description": "Get the distance between two locations using Google Maps API",
      "parameters": {
        "type": "object",
        "properties": {
          "start_location": {
            "type": "string",
            "description": "The starting location, e.g. Tokyo, Japan"
          },
          "end_location": {
            "type": "string",
            "description": "The ending location, e.g. Osaka, Japan"
          },
          "unit": {
            "type": "string",
            "enum": ["kilometers", "miles"],
            "description": "The unit of distance measurement"
          }
        },
        "required": ["start_location", "end_location"]
      }
    }
  ];
}

function getCurrentWeather(location, unit = "celsius") {
  var weatherInfo = {
    "location": location,
    "temperature": "33",
    "unit": unit,
    "forecast": ["sunny", "windy"]
  };
  return JSON.stringify(weatherInfo);
}

function getRoute(start_location, end_location) {
  var apiKey = PropertiesService.getScriptProperties().getProperty('GOOGLE_MAPS_APIKEY');
  var url = 'https://maps.googleapis.com/maps/api/directions/json?origin=' + start_location + '&destination=' + end_location + '&key=' + apiKey;
  var options = {
    method: 'GET'
  };

  var response = UrlFetchApp.fetch(url, options);
  var data = JSON.parse(response.getContentText());

  if (data.status != "OK") {
    Logger.log("Error: " + data.status);
    return;
  }

  var routes = data.routes;
  var distance_info = {};
  for (var i = 0; i < routes.length; i++) {
    var route = routes[i];
    var legs = route.legs;
    for (var j = 0; j < legs.length; j++) {
      var leg = legs[j];
      distance_info = {
        "Start": leg.start_address,
        "End": leg.end_address,
        "Distance": leg.distance.text,
        "Duration": leg.duration.text
      }
    }
  }
  return JSON.stringify(distance_info);
}

実行結果

天気に関する質問をすると、get_current_weatherのfunctionが利用され、天気取得API(モック)が叩かれる

2点間の距離に関する質問をすると、get_distance_between_locationsのfunctionが利用され、GoogleMapsのAPIが叩かれる

定義したfunctionと無関係なメッセージを送信すると、functionは利用されず、通常のGPTが応答する

最後に

「Function calling」の機能により、ChatGPTを経由して、異なるサービス間のデータの受け渡しを自然言語でやり取りできるようになりました。

具体的には、LINEから特定のアカウントに日本語で「◯月◯日に大阪でホテルの予約をしたい。」のようなメッセージを送信して、Booking.comでホテルを予約する、といったことが実現可能になります。

ChatGPTのプラグインの機能をAPIで利用できるように、いつかはなるだろうと思っていましたが、もうできてしまいましたね。OpenAI社のスピード感は素晴らしいです。

ChatGPTを利用したチャットボット等の開発に興味がある方は、ぜひお気軽にご相談ください。

参考文献


この記事が気に入ったらサポートをしてみませんか?