【OpenAI API】Function calling による振り分けを試してみた
こんにちは!@Ryo54388667です!☺️
普段は都内でフロントエンドエンジニアとして業務をしてます!
主にTypeScriptやNext.jsといった技術を触っています。
今回はOpenAIのAPI、Function callingという機能を試してみたいと思います。
📌 Function calling とは
In an API call, you can describe functions and have the model intelligently choose to output a JSON object containing arguments to call one or many functions. The Chat Completions API does not call the function; instead, the model generates JSON that you can use to call the function in your code.
https://platform.openai.com/docs/guides/function-calling
モデルに対して、複数の関数を説明を追加することで、プロンプトに応じて適切な関数を判断させる手法 です。
ChatGPTのUIを見て、特定のプロンプトでリクエストすると、それに応じてコンポーネントが表示されます。例えば、「猫の画像を作成して」と入力すると、「画像を作成中…」という表示があらわれます。
ユーザーが明示的に画像生成モデルを指定しなくても、アプリ側で自動で判断してくれているようです。おそらくこの仕組みをFunction calling が担っているのだと推測できます。内部を見たわけではありませんが。。
留意点もあります。
The Chat Completions API does not call the function; instead, the model generates JSON that you can use to call the function in your code.
上記にもあるように、関数を呼び出すことはせず、あくまで判断のみを行う仕様です。
自然言語を解析して、期待されることを基に関数を選択するというのがスゴいところですね!👍
プロンプトに応じた関数の動的な呼び出し方に焦点を当て、試していきたいと思います。
📌 検証内容
手順
本検証では、プロンプトに応じて実行すべき関数を判断できるかどうかを確認します。
下記の手順で行います。
- 複数のプロンプトを用意する
- それぞれに対して最適な関数が呼び出されるかどうかを確認する
Function callingが機能すると、実行結果のレスポンスデータの中に"finish_reason":"function_call"
というものが出力されます。
また、下記のように、関数名がvalueとなるnameプロパティも同時に出力されます。
"function_call": {
"name": "use_plugin",
"arguments": “{…}”
}
こちらをもとに 「Function callingが機能したのか?」「どの関数を呼び出すと判断したのか?」 を確認していきます。
今回はChatGPTのように、
- 画像生成を行う関数 (generate_image)
- Web検索を行う関数 (search_web)
- 社内ドキュメント検索を行う関数 (search_internal)
- 特定のプラグインを使用する関数 (use_plugin)
を振り分けられるか検証してみます。
プロンプトの検討
実際に特定の関数を呼び出すことを期待するプロンプトを検討します。この作業が地味に難しかったです。。😇直接的な単語を利用すると、実際のユースケースとは乖離してしまうこともあります。例えば、ITに明るくない人が利用する場合、「プラグイン」のような単語は知らないと思われますし。。モデルが判断に苦心するような際どいプロンプトかつ、実際のユースケースに沿うようなものをリクエストする必要があります。以下のプロンプトを用意しました。
■ generate_imageを期待するプロンプト
- ~の画像を作成して
■ search_webを期待するプロンプト
- 今週の日本の映画ランキングの結果を調べて
- 2024年のオリンピックの新しいマスコットを検索して
- 最近発表されたAppleの新製品についての評価を調べて
■ search_internalを期待するプロンプト
- 最新の社員満足度調査の結果を探して
- テレワーク規則における最近の変更点を検索して
- 昨年度の全社員会議の議事録を検索して
■ use_pluginを期待するプロンプト
- 来週の会議のための自動返信メールを設定してほしい。
- パリへの旅行計画で、予算内で収まるおすすめの宿泊施設を探して。
- 明日のタスクリストを作成して、優先順位をつけてくれる?
ソースコード
以下のパッケージとバージョンを使用します。
パッケージ | バージョン |
---|---|
python | 3.11 |
openai | 0.28.0 |
呼び出す関数の定義を書きます。
後述しますが、この説明書きで精度が変化すると思われます。
functions = [
{
"name": "search_web",
"description": "指定されたキーワードでWeb検索を行い、結果を返します。",
"parameters": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "検索キーワード。例: '最新のテクノロジートレンド'"
}
},
"required": ["title"]
}
},
...略...
]
functionsの全文
functions = [
{
"name": "generate_image",
"description": "指定された説明に基づいて画像を生成します。",
"parameters": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "画像の説明。例: '静かな湖の上で夕日が沈む風景'"
}
},
"required": ["title"]
}
},
{
"name": "search_web",
"description": "指定されたキーワードでWeb検索を行い、結果を返します。",
"parameters": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "検索キーワード。例: '最新のテクノロジートレンド'"
}
},
"required": ["title"]
}
},
{
"name": "search_internal",
"description": "会社内のドキュメントやデータベースを検索します。",
"parameters": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "検索クエリ。例: '四半期報告書 Q2'"
}
},
"required": ["title"]
}
},
{
"name": "use_plugin",
"description": "指定されたプラグインを利用して特定の操作を実行します。",
"parameters": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "利用するプラグインの名前。例: 'currency_converter'"
}
},
"required": ["title"]
}
}
]
リクエストの箇所
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[
{"role": "user", "content": "今週の日本の映画ランキングの結果を調べて"},
],
functions=functions, ## <== こちらで振り分ける関数を設定する
function_call="auto" ## <== モデル側で振り分けるかどうかを設定します。auto と明示していますが、デフォルト値はautoです。
)
準備ができたので、早速、準備したプロンプトでリクエストしていきます!
📌 検証結果
まず、画像生成モデルについてはプロンプトの性質上(ex. ~画像を作成して。)、そこまで判断が難しくないようなので、深掘りするのは省略しました。そのほかの結果は以下の通りです。
search_webを期待するプロンプトをリクエストした時
使用したモデル:GPT-3.5-turbo
プロンプト | 判断 |
---|---|
今週の日本の映画ランキングの結果を調べて | ✅ |
2024年のオリンピックの新しいマスコットを検索して | ✅ |
最近発表されたAppleの新製品についての評価を調べて | ✅ |
search_internalを期待するプロンプトをリクエストした時
使用したモデル:GPT-3.5-turbo
プロンプト | 判断 |
---|---|
最新の社員満足度調査の結果を探して | ✅ |
テレワーク規則における最近の変更点を検索して | ✅ |
昨年度の全社員会議の議事録を検索して | ✅ |
直接的な単語がなくとも、判断してくれそうです!
use_pluginを期待するプロンプトをリクエストした時
使用したモデル:GPT-3.5-turbo
プロンプト | 判断 |
---|---|
来週の会議のための自動返信メールを設定してほしい。 | ❌ |
パリへの旅行計画で、予算内で収まるおすすめの宿泊施設を探して。 | ❌(search_webになる) |
明日のタスクリストを作成して、優先順位をつけてくれる? | ❌ |
ほとんどのケースでFunction callingを利用せずに通常のGPTのレスポンスになってしまった。
なお、「プラグイン」 という単語を利用すると判断できます。
プロンプト:クックパッドのプラグインで料理のレシピを教えて
レスポンス:
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"function_call": {
"name": "use_plugin",
"arguments": "{\n \"title\": \"cookpad_recipe\"\n}"
}
},
"logprobs": null,
"finish_reason": "function_call"
}
],
これを受けて、モデルをアップグレードして再び検証してみました。
使用したモデル:GPT-4
プロンプト | 判断 |
---|---|
来週の会議のための自動返信メールを設定してほしい。 | ❌ |
パリへの旅行計画で、予算内で収まるおすすめの宿泊施設を探して。 | ❌ |
明日のタスクリストを作成して、優先順位をつけてくれる? | ❌ |
さらに、検証を続けます。
各関数の箇所(functions)のdescriptionにプラグインの種類
を下記のように追記してみます。
"name": "use_plugin",
"description": "指定されたプラグインを利用して特定の操作を実行します。自動メール返信プラグイン、トラベルプラン用プラグイン、todoリストを作成するプラグインがある。",
使用したモデル:GPT-3.5-turbo
プロンプト | 判断 |
---|---|
来週の会議のための自動返信メールを設定してほしい。 | ✅ |
パリへの旅行計画で、予算内で収まるおすすめの宿泊施設を探して。 | ❌(search_webになる) |
明日のタスクリストを作成して、優先順位をつけてくれる? | ❌ |
使用したモデル:GPT-4
プロンプト | 判断 |
---|---|
来週の会議のための自動返信メールを設定してほしい。 | ✅ |
パリへの旅行計画で、予算内で収まるおすすめの宿泊施設を探して。 | ✅ |
明日のタスクリストを作成して、優先順位をつけてくれる? | ✅ |
個人的には、けっこう面白い結果に感じました!☺️
各関数の箇所(functions)をより精緻に、より詳細に記述する必要がありますね!
📌 まとめ
Function callingによる関数の振り分けを試してみました。直接的な単語無しでも振り分け判断ができそうです!加えて、期待する関数の説明(description)を詳細に記述するとパフォーマンスも良くなるようでした。
最後まで読んでいただきありがとうございます!
気ままにつぶやいているので、気軽にフォローをお願いします!🥺
個人メディアもあります〜
Discussion