見出し画像

Function CallingのデモをChatGPTに作ってもらう(ChatGPT部, 大城)

こんばんは、ChatGPT部(チャットGPT部)、部長の大城です。先日ChatGPTに実装されたFunction Callingが少し気になっていましたので、公式サイトを参考に、ChatGPTにサンプルプログラムの実装をお願いしてみました。
( ただ、慣れてる人は直接公式サイトのコードを読んだ方が早いかもしれません・・笑)

Function Callingとは

こちらのブログのこの図がとてもわかりやすかったです。まぁようは「ChatGPTに関数の選択肢をいくつか渡して、適切なものを1つ選んでもらう」だけな感じですね。私の理解が正しければ。

その後、戻ってきた関数を外側のプログラムで実行してChatGPTに渡す、とかそんな感じの印象を受けてます。
( これ、MSの蒲生さんが以前Function Callingが実装される前に実演されてたやつの機能化バージョンな気がしますね。 )

個人的には上記のブログの図がとてもわかりやすかったので、一度覗かれて見ることをお勧めします。


補足:今回のこのnoteでのコードのシーケンス図

ちなみに、ChatGPTに今回作ってもらったコードをShow Meプラグインでシーケンス図にしてもらったものがこちら。後半戦のコードと合わせてみていただきたいですが、Modelと書いている部分がChatGPTで、天気の情報をくれと言ったら「get_current_weather」の関数名を返してくれ、またDBアクセスしてくれと言えば「db_query」の関数名を返してくれる、という感じですね。その後、外側のプログラムで該当する関数名のAPIを呼び出して、ChatGPTに結果を渡してあげる、という流れだと理解しています。
( 多分、ChatGPTのプラグインも同じような動きのはず )

OpenAI公式の解説

こちらですね。英語なので、ChatGPTの力を借りながらデモ実行まで行きたいと思います。


ChatGPTのWeb Browsing機能(with Bing)で解説してもらう

これ、Web検索系のプラグイン(Web PilotやLink Reader)で試してみたのですが、参照先のページが長いと全然使えない( 適当な回答を返す )という感じでした。本来ならWeb PilotとNoteableプラグインを組み合わせて使いたかったのですが、仕方ないので公式のWeb Browsing機能を使って解説&コーディングしてもらいました( 公式のWeb Browsing機能は結構情報量が多くても最後までちゃんと読んでくれる印象があります )

import openai
import json

openai.api_key = 'your-openai-api-key'

# Step 1: Call the model with functions and the user's input
response1 = openai.ChatCompletion.create(
  model="gpt-3.5-turbo-0613",
  messages=[
        {"role": "user", "content": "What is the weather like in Boston?"}
    ],
  functions=[
        {
          "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"]
          }
        }
      ]
)

# Extract the function call from the model's response
function_call = response1['choices'][0]['message']['function_call']
# Step 2: Use the model response to call your API
# In this example, we simulate a response from a third-party weather API
weather_api_response = {
    "temperature": 22,
    "unit": "celsius",
    "description": "Sunny"
}
# Step 3: Send the response back to the model to summarize
response2 = openai.ChatCompletion.create(
  model="gpt-3.5-turbo-0613",
  messages=[
        {"role": "user", "content": "What is the weather like in Boston?"},
        {"role": "assistant", "content": None, "function_call": function_call},
        {"role": "function", "name": "get_current_weather", "content": json.dumps(weather_api_response)}
      ],
  functions=[
        {
          "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"]
          }
        }
      ]
)

# Extract the assistant's message from the response
assistant_message = response2['choices'][0]['message']['content']

print(assistant_message)

まぁ、わかったようなわからないような・・(笑)
実際は動かしながら確認した方が良いと思いますので、ソースコードを吐き出してもらって、別のスレッドでNoteableプラグインを立ち上げ、さらに同じディレクトリにOpenAIのAPI Keyを設置して読み込む例を次に作ってもらいました。

あと、せっかくの関数選択なので、複数あった方が面白いと思い追加でDB検索の機能も足してもらうように依頼しました。

関数追加&API Key参照するコードの作成依頼

こんな感じで先ほどのコードに追加の依頼をかけました。

作成されたコードがこちら。ちなみにnoteableプラグインで実行するには、最初にnotebook上にて「pip install openai」を実行する必要があります。

import openai
import json

# カレントディレクトリにあるテキストファイルからOpenAI APIキーを読み込む
with open('api_key_noteable_demo_noshiro.txt', 'r') as file:
    openai.api_key = file.read().strip()

# ステップ1: モデルに関数とユーザーの入力を伴って呼び出す
response1 = openai.ChatCompletion.create(
  model="gpt-3.5-turbo-0613",
  messages=[
        {"role": "user", "content": "What is the weather like in Boston?"}
    ],
  functions=[
        {
          "name": "get_current_weather",
          "description": "指定した場所の現在の天気を取得する",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "都市と州、例えばSan Francisco, CA"
              },
              "unit": {
                "type": "string",
                "enum": ["celsius", "fahrenheit"]
              }
            },
            "required": ["location"]
          }
        },
        {
          "name": "db_query",
          "description": "データベースを問い合わせる",
          "parameters": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "実行するSQLクエリ"
              }
            },
            "required": ["query"]
          }
        }
      ]
)

# モデルのレスポンスから関数呼び出しを抽出する
function_call = response1['choices'][0]['message']['function_call']

# ステップ2: モデルのレスポンスを使用してAPIを呼び出す
# この例では、サードパーティの天気APIからのレスポンスをシミュレートします
weather_api_response = {
    "temperature": 22,
    "unit": "celsius",
    "description": "Sunny"
}

# ステップ3: レスポンスをモデルに送り返して要約させる
response2 = openai.ChatCompletion.create(
  model="gpt-3.5-turbo-0613",
  messages=[
        {"role": "user", "content": "What is the weather like in Boston?"},
        {"role": "assistant", "content": None, "function_call": function_call},
        {"role": "function", "name": "get_current_weather", "content": json.dumps(weather_api_response)}
      ],
  functions=[
        {
          "name": "get_current_weather",
          "description": "指定した場所の現在の天気を取得する",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "都市と州、例えばSan Francisco, CA"
              },
              "unit": {
                "type": "string",
                "enum": ["celsius", "fahrenheit"]
              }
            },
            "required": ["location"]
          }
        }
      ]
)

# モデルのレスポンスから関数呼び出しを抽出する
assistant_message = response2['choices'][0]


検証①:Noteableプラグインで実行、天気情報取得のケース


Function Callingは「ChatGPTが呼び出す関数を選択する」という部分がミソなので、2つ実験をしてみました。

まずはボストンの天気について尋ねてみたパターン。

# ステップ1: モデルに関数とユーザーの入力を伴って呼び出す
response1 = openai.ChatCompletion.create(
  model="gpt-3.5-turbo-0613",
  messages=[
        {"role": "user", "content": "What is the weather like in Boston?"}
    ],
・・・ (以下略)

「What is the weather like in Boston?」ということでなぜか英語ですがBostonの天気について聞いてます。このときのresponse1に含まれているfunction_call変数にChatGPTが選んだ関数名が入るのですが、この場合だと「get_current_weather」という文字が帰ってきます。天気を取得するための関数名ですね。

実際はこの戻ってきた文字(関数名)を使い、ChatGPTの外側のプログラムが該当の処理(get_current_weather関数やAPI)を別の処理として呼び出す、という流れですね。(ChatGPT自身が外部の機能を直接呼び出すことが出来る訳ではない点に注意)


検証②:Noteableプラグインで実行、DB接続関数呼び出しのケース

ではこちらの場合はどうでしょうか。

# ステップ1: モデルに関数とユーザーの入力を伴って呼び出す (DB Calling)
response1 = openai.ChatCompletion.create(
  model="gpt-3.5-turbo-0613",
  messages=[
        {"role": "user", "content": "DB接続関数を呼び出してください"}
    ],
・・・(以下略)

先ほどとの違いは「DB接続関数を呼び出してください」という依頼部分ですね。これはユーザーからChatGPTへの指示文です。

そちらに対してのレスポンスは以下になります。今度は「db_query」の文字列が返却されてますね。これを元に、今度は外の処理でDB接続を呼び出す、という形になるのかと思います。(恐らくあってるはず。でもargumentsのselect * from users、はどこからでてきたんだろ・・)

所感等:Function Callingは色々使えそう&まだまだコーディングの知識は必要

Function Calling、どこまで厳密にChatGPTが関数名選択をしてくれるかは検証の余地がありますが、いろいろな機能に分岐させたい時に使えそうですね。特に、「曖昧な条件下での関数名選択」などは有効でしょう。あと、応用としては「コードやUnixコマンドを書かせて実行させる」とかでしょうか。exec関数みたいなものを定義してしまうのも一手かもしれません(何が実行されるかわからない状態だと、やや心配ですが)

ただ、この辺の実装ややはりサンプルコードの理解は普通にPythonの知識やAPIの知識が必要なので、ある程度プログラミングに慣れた人じゃないと難しそうだな、とも改めて思いました。そういう意味ではまだまだ我々の出番はありそうですね(10年後など、ある程度世の中の処理の自動化が完了した頃はどうかわかりませんが・・)

ということで今日はさわりの部分にはなりますが、ChatGPTにのFunction Callingのデモプログラムを作ってもらって少し触ってみた、というお話でした。
それではみなさんもどうぞ良いChatGPTライフを・・!(大城)

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