はじめに
昨日公表されたOpenAI APIのFunction callingをGoogle Colaboratoryで試してみました
この機能ずっと実現されないかな〜 と前から思ってました。
簡単に言いますと人間の言葉から与えられた関数の仕様に適合するパラメータを抽出して作成してもらえるという機能ですね。
言葉によるシステム操作インターフェースが比較的容易に作れるようになります。
たとえばSlackなどのチャットツール向けのボットアプリとはとても相性の良い機能と言えると思います。
検証
早速やってみましょう!
まずは昨日のOpenAI発表ページにあったサンプルをそのままPythonに焼き直してColabで実行します。
OpenAIのAPIキーは各自でご用意ください。
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': '摂氏'}
最初そのまま日本語の質問に変えたら英語で返されたので
properties
のdescription
を日本語に書き換えたら日本語で返るようになりました。
この辺は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)
function2
をfunctions
に新しく追加しました。
質問内容によって適切な関数が選択され正しいパラメータが取得できるのか検証しました。
質問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_weather
とget_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
のラインアップを増やしていった場合の応答時間の影響やプロンプトが複雑化した場合の正確性については実装しながら検証していくことになると思います。