初めに
2023年6月13日にGPT Function callingがリリースされました.
入力した文字列に応じて関数の呼び出しが可能にとの事ですが,いまいちよく分からなかったので,とりあえず実装してみました.
参考記事のほとんどが天気情報の関数呼び出しをしているため,今回は周辺情報を取得する関数を使ってみたいと思います.
実装
今回はPythonを使って開発していきます.
また,周辺情報の取得に関してはGoogleが提供しているPlacesAPIを使います.
PlacesAPIの使い方に関しては,メインではないので説明を省きます.
関数の定義
まずはFunction callingで呼び出す関数を作成する必要があります.
def get_location(latitude, longitude, radius, keyword):
base_url = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
api_key = '自分のAPIKey'
parameters = {
'location': f'{latitude},{longitude}',
'radius': radius,
'keyword': keyword,
'language': 'ja',
'key': api_key
}
response = requests.get(base_url, params=parameters)
if response.status_code == 200:
data = response.json()
# 名前の情報を格納するリスト
name_list = []
# 出力結果から名前を取り出してリストに追加
for result in data['results']:
name = result['name']
name_list.append(name)
return json.dumps(name_list)
else:
return None
必須のパラメーターはlocation
radius
key
の3つです.
keyword
には地名・住所・施設のカテゴリを入力することができます.これにより検索対象を絞ることができます.language
は返答分の言語を指定しています.
他のパラメータについて知りたい場合は以下のリンクからご覧ください.
PlaceAPIのパラメータ
出力結果のresult['name']
には検索した施設の名称が含まれています.
この施設名称をChatGPTの入力値として使います.
注意
ChatGPTに入力する最大文字数は4096文字です.
そのため,入力値が多すぎる場合はエラーとなります.
Functionプロパティの定義
place_function = {
"name": "get_location",
"description": "経度緯度の情報から周辺の場所を取得",
"parameters": {
"type": "object",
"properties": {
"latitude": {
"type": "string",
"description": "経度の情報",
},
"longitude": {
"type": "string",
"description": "緯度の情報",
},
"radius": {
"type": "string",
"description": "半径の情報",
},
"keyword": {
"type": "string",
"description": "キーワード",
},
},
"required": ["latitude","longitude","radius","keyword"],
},
}
name
に先ほど作成した関数名を記述してください.
description
は任意の項目ですが,関数呼び出しの際に使っている可能性があるため,一応記述しておきます.
parameters
には関数呼び出しに必要となるパラメータを記述します.
required
には必須のパラメーターを記述します.
Functionプロパティを定義することで,ユーザーの入力内容から自動でパラメーターの値を生成してくれます.
OpenAI API
import openai
import json
import requests
# OpenAI APIキーの準
openai.api_key = "自分のAPIKey"
def main(text):
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
messages=[{"role": "user", "content": text}],
#Functionプロパティ
functions=[place_function],
function_call="auto",
)
message = response["choices"][0]["message"]
if message.get("function_call"):
function_name = message["function_call"]["name"]
arguments=json.loads(message["function_call"]["arguments"])
function_response = get_location(
latitude=arguments.get("latitude"),
longitude=arguments.get("longitude"),
radius=arguments.get("radius"),
keyword=arguments.get("keyword"),
)
second_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
messages=[
{"role": "user", "content": text},
message,
{
"role": "function",
"name": function_name,
"content": function_response,
},
],
)
return second_response.choices[0]["message"]["content"].strip()
#Function callingを使わない場合
return response.choices[0]["message"]["content"].strip()
現在関数呼び出しに対応しているモデルはgpt-4-0613
もしくはgpt-3.5-turbo-0613
のみです.
処理の流れは以下の通りです.
- 入力内容から関数呼び出しが必要かどうか判断
- 必要だと判断した場合,関数のパラメーターを入力内容から生成
- 生成したパラメーターを使って関数を実行
- 実行結果を
messages
に含めて回答文を生成
実行結果
周辺情報を聞いた場合
入力内容:スカイツリーから100メートル以内でおすすめのレストランを5件教えて
以下の内容はmessage
の内容で,function_callが実行され,パラメータが生成されているのがわかります
{
"role": "assistant",
"content": null,
"function_call": {
"name": "get_location",
"arguments": "{\n \"latitude\": \"35.710063\",\n \"longitude\": \"139.8107\",\n \"radius\": \"100\",\n \"keyword\": \"\u30ec\u30b9\u30c8\u30e9\u30f3\",\n}"
}
}
実行結果は以下の通りです.
1. Sky Restaurant 634
2. パラッツォ サン グスト
3. おぼんdeごはん 東京スカイツリータウン・ソラマチ店
4. スペイン料理&ワイン パエリア東京スカイツリータウン・ソラマチ
5. 炭焼きLamp
どれも美味しい食事を楽しむことができるレストランです。ぜひ訪れてみてください!
日常会話を入力した場合
次は入力内容を日常会話にしてみます.
入力内容:今日は暑いね
{
"role": "assistant",
"content": "\u306f\u3044\u3001\u672c\u5f53\u306b\u6691\u3044\u3067\u3059\u306d\u3002\u5916\u306b\u51fa\u308b\u969b\u306f\u71b1\u4e2d\u75c7\u5bfe\u7b56\u3092\u3057\u3063\u304b\u308a\u3068\u884c\u3044\u307e\u3057\u3087\u3046\u3002\u6c34\u5206\u88dc\u7d66\u3084\u65e5\u5098\u306e\u4f7f\u7528\u306a\u3069\u3001\u6ce8\u610f\u304c\u5fc5\u8981\u3067\u3059\u3002"
}
function_callが実行されていません.
実行結果は以下の通りです.
はい、本当に暑いですね。外に出る際は熱中症対策をしっかりと行いましょう。水分補給や日傘の使用など、注意が必要です。
終わりに
関数呼び出しを行うことで,chatGPTの精度はかなり向上できると思われます.
しかし,APIで取得した結果もトークンとしてカウントされるため,トークン量の削減などが今後は必要になってくるでしょう.
また,現在の方法では1つの関数しか呼び出しできません.
実際にアプリなどに組み込む場合は,LangChainなどを利用して複数の関数呼び出しに対応させる必要があります.