3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

はじめに

昨日公表されたOpenAI APIのFunction callingをGoogle Colaboratoryで試してみました
この機能ずっと実現されないかな〜 と前から思ってました。

簡単に言いますと人間の言葉から与えられた関数の仕様に適合するパラメータを抽出して作成してもらえるという機能ですね。
言葉によるシステム操作インターフェースが比較的容易に作れるようになります。
たとえばSlackなどのチャットツール向けのボットアプリとはとても相性の良い機能と言えると思います。

検証

早速やってみましょう!
まずは昨日のOpenAI発表ページにあったサンプルをそのままPythonに焼き直してColabで実行します。
OpenAIのAPIキーは各自でご用意ください。

image.png

functionsというパラメータを渡すことにより
AIにコールしたい関数の仕様を教えてあげることになります
人間の言葉から関数の仕様に適合した関数のパラメータを作成してくれます

import openai
import json

openai.api_key = "APIキー"

messages = []
message = {"role": "user", "content": "What is the weather like in Boston?"}
messages.append(message)

functions = []
function = {
      "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"]
      }
    }

functions.append(function)

result = openai.ChatCompletion.create(model="gpt-3.5-turbo-0613", messages=messages, functions=functions)
ai_response = result.choices[0].message.function_call
decoded_arguments = json.loads(ai_response["arguments"])
print(ai_response)
print(decoded_arguments)

返却された内容

{
  "name": "get_current_weather",
  "arguments": "{\n  \"location\": \"Boston, MA\"\n}"
}
{'location': 'Boston, MA'}

このように人間の言葉から抽出したデータをJSON形式で返してくれるので
プログラム内での取り扱いが容易になります

次に日本語への対応を検証してみました

import openai
import json

openai.api_key = "APIキー"

messages = []
message = {"role": "user", "content": "ニューヨークの天気と気温を摂氏で教えてください"}
messages.append(message)

functions = []
function = {
      "name": "get_current_weather",
      "description": "Get the current weather in a given location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "都市や地域の名前(日本語)"
          },
          "unit": {
            "type": "string",
            "enum": ["摂氏", "華氏"]
          }
        },
        "required": ["location"]
      }
    }

functions.append(function)

result = openai.ChatCompletion.create(model="gpt-3.5-turbo-0613", messages=messages, functions=functions)
ai_response = result.choices[0].message.function_call
decoded_arguments = json.loads(ai_response["arguments"])
print(ai_response)
print(decoded_arguments)

返却された内容

{
  "name": "get_current_weather",
  "arguments": "{\n\"location\": \"\u30cb\u30e5\u30fc\u30e8\u30fc\u30af\",\n\"unit\": \"\u6442\u6c0f\"\n}"
}
{'location': 'ニューヨーク', 'unit': '摂氏'}

最初そのまま日本語の質問に変えたら英語で返されたので
propertiesdescriptionを日本語に書き換えたら日本語で返るようになりました。
この辺はfunctions内の各種プロパティを調整しながら試していく感じになるかなと思いますね。

ここでは試していないですが複数の関数をパラメータに設定できそうなので
関数自体の呼び分けも制御できそうに見えますね。

おわりに

重要なこととして関数を直接コールすることはさすがにできないのですが
コールする関数の判断と引数データを抽出してもらえるので動的な処理制御が可能になります。

これからいろんなアイデアが出てきて面白いアプリが沢山誕生する期待がありますね。

おまけ(20230617追記)

ここでは試していないですが複数の関数をパラメータに設定できそうなので
関数自体の呼び分けも制御できそうに見えますね。

こちらがどうしてもキニナル!なので試してみました。

import openai
import json

openai.api_key = "APIキー"

messages = []
message = {"role": "user", "content": "質問内容"}
messages.append(message)

functions = []
function = {
      "name": "get_current_weather",
      "description": "Get the current weather in a given location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "都市や地域の名前(日本語)"
          },
          "unit": {
            "type": "string",
            "enum": ["摂氏", "華氏"]
          }
        },
        "required": ["location"]
      }
    }

functions.append(function)

function2 = {
      "name": "get_postal_code",
      "description": "Get the postal code in a given location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "都市や地域の名前(日本語)"
          }
        },
        "required": ["location"]
      }
    }
functions.append(function2)

result = openai.ChatCompletion.create(model="gpt-3.5-turbo-0613", messages=messages, functions=functions)
ai_response = result.choices[0].message.function_call
decoded_arguments = json.loads(ai_response["arguments"])
print(message)
print(ai_response)
print(decoded_arguments)

function2functionsに新しく追加しました。
質問内容によって適切な関数が選択され正しいパラメータが取得できるのか検証しました。

質問1

{'role': 'user', 'content': 'ニューヨークの天気と気温を摂氏で教えてください'}
{
  "name": "get_current_weather",
  "arguments": "{\n  \"location\": \"\u30cb\u30e5\u30fc\u30e8\u30fc\u30af\",\n  \"unit\": \"\u6442\u6c0f\"\n}"
}
{'location': 'ニューヨーク', 'unit': '摂氏'}

質問2

{'role': 'user', 'content': '千代田区の郵便番号を教えてください'}
{
  "name": "get_postal_code",
  "arguments": "{\n\"location\": \"\u5343\u4ee3\u7530\u533a\"\n}"
}
{'location': '千代田区'}

見事にget_current_weatherget_postal_codeの選択が出来てますね!
よって以降はこのような感じでコードを発展させることが可能ですね。

def get_current_weather(location, unit):
  print(location + unit)

def get_postal_code(location):
  print(location)

name = ai_response["name"]
arguments = json.loads(ai_response["arguments"])

if name == "get_current_weather":
  get_current_weather(arguments["location"], arguments["unit"])
elif name == "get_postal_code":
  get_postal_code(arguments["location"])

あとは気になることとしてfunctionsのラインアップを増やしていった場合の応答時間の影響やプロンプトが複雑化した場合の正確性については実装しながら検証していくことになると思います。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?