【天気予報も書類仕事もAIに】ChatGPTの「Function Calling」を超わかりやすく解説!

押さえておきたいポイント
  • Function CallingはChatGPTに外部ツール操作を自動判断させる機能
  • 学習データ外のAPI情報を活用し、より実用的な応答を生成
  • 正確な関数定義とトークン管理が活用の鍵

「Function Calling」ChatGPTのAPI(OpenAI API)に備わる1機能です。

Function Calling
参考:https://platform.openai.com/docs/guides/function-calling

こちらは「ChatGPTに外部ツールを操作させられる」機能らしいのですが、何がすごいのかわかりづらいですよね。

ということで、Function Callingについて、難しい言葉を使わないで、やさしく解説していきたいと思います。
公開されているプログラムにコメントもりもりで解説するので、ぜひ最後までお読みください!

\生成AIを活用して業務プロセスを自動化/

ChatGPTの「Function Calling」機能について

ChatGPTのAPI(OpenAI API)から使える「Function Calling」は、LLMに検索や電卓等の外部ツールを自動操縦させられる機能です。

この機能を使うと、LLMに外部ツールの取扱説明書(関数)を渡してその操作を代行させる「関数呼び出し」が実現します。これの何が嬉しいかというと、次の2点です。

  • 外部APIや関数を呼ぶべきか呼ばないかをGPT(AI)側に判断させられること
  • 外部APIや関数の値をもとに、回答を生成できること(つまり、学習データ以外のデータにもアクセスできる)

まず、前提として、OpenAI APIを使ってGPTと会話する方法について確認です。

import openai

openai.api_key = 'your-api-key'

response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo-0613",

        messages=[

            {"role": "user", "content": "PythonでHello worldと出力するプログラムを書いて"},

        ])

print(response['choices'][0]['message']['content'])

上記ではプログラムのmessages のところで、「PythonでHello worldと出力して」と入力しています。ChatGPTのプロンプトに該当していますね。

実際に実行してみると回答としてPythonプログラムが返ってきます。このときの回答は、純粋にGPTが考えて出力しています。この前提を踏まえた上で、function_call を使う場合についてお話します。

Function Calling 機能を使う場合、次のプログラムのようにパラメータが追加されます。

import openai

openai.api_key = 'your-api-key'

response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo-0613",

        messages=[

        //プロンプト:ボストンの天気は何ですか?

            {"role": "user", "content": "What's the weather like in Boston?"},

        ],

        //追加されたパラメータ1

     functions=[

            {

               //ここに呼び出す関数情報を記述する。

            }

        ],

        //追加されたパラメータ2

        function_call="auto",

)

print(response['choices'][0]['message']['content'])

追加されたパラメータは以下の2つです。

  • functions
  • function_call

特に重要なのが、functions というパラメーター。必要なときにGPTに呼び出してもらいたい関数の情報を伝えるために使います。関数の情報は複数伝えることもできます。

例えば、

  • 天気APIを実行する関数
  • Google Trends APIを実行する関数

の2つを用意します。

import openai

openai.api_key = 'your-api-key'

response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo-0613",

        messages=[

        # プロンプト:ボストンの天気は何ですか?

            {"role": "user", "content": "What's the weather like in Boston?"},

        ],

        # 追加されたパラメータ1

        functions=[

            {

                #  天気APIを実行する関数の情報を記載

            },

            {

                # Google Trends APIを実行する関数の情報を記載

            }

        ],

        # 追加されたパラメータ2

        function_call="auto",

        )

#本来必要な処理は省略している。

print(response['choices'][0]['message']['content'])

プロンプトに「ボストンの天気は何ですか?」と入力されています。この場合、AIが「天気について尋ねられたので、天気APIを実行する関数を呼び出そう」と自動で判断してくれます。そうすることで、天気APIの結果をもとにして、「ボストンの天気は晴れ!」と回答してくれるようになるのです。

もし、プロンプトが「ブログネタに使えそうなテックの流行りを教えて」だとしたらどうでしょうか?

Google Trends APIを実行する関数を呼び出そう」とAIが判断して、「今の流行りは OpenAI API のFunction Calling 」と回答してくれるわけです。

この機能を使い、外部APIアクセスを自動で判断できるということは、学習データ以外のデータにアクセスできるようになったことを意味します。

なお、OpenAIの公式機能「Custom Instructions」について詳しく知りたい方は、下記の記事を合わせてご確認ください。

ChatGPTのFunction CallingとMCPの違い

Function Callingと同じく、「LLMに外部ツールの取扱説明書を渡して操作を代行させる」技術として「MCP(Model Context Protocol)」というものがあります。

このMCPはOpenAIのライバル・Anthropicがリリースした技術なのですが、Function Callingとは以下の点で異なります。

スクロールできます
Function Calling(ChatGPT)MCP
LLMとツールの連携方法各ユーザーが独自に&ゼロから関数を定義する既存のMCPサーバーを利用して関数定義なしで導入できる
汎用性OpenAIの独自規格のため△オープンソース(統一規格)のため◎
Function CallingとMCPの違い

MCPについては、その汎用性の高さからOpenAIも採用しており、今後メインストリームの技術となるかもしれません。(※2)

【ハンズオン】ChatGPTのFunction Calling機能を試す

OpenAI公式が発表しているFunction Callingのユースケースとしては、以下のようなものがあります。

  1. 外部APIを呼び出して質問に答えるチャットボット
  2. 自然言語をAPI呼び出しに変換
  3. テキストからの構造化データの抽出

その中でも公開されていた1.に関するプログラムを解説していきます。

外部のAPIを呼び出して質問に答えるチャットボット

こちらでは、「天気APIを呼び出して質問に答える」チャットボットを例に解説します。デモのため、正確には天気APIを呼び出しておらず、ダミーデータを使っています。解説の流れとしては、まずはプログラムの全文をお見せし、実行される順番にパートに分けていきます。

import openai

import json

# 6. 天気情報を取得する関数を定義します。

# 本来ならAPIを使いますが、デモのためダミーデータを使います。

def get_current_weather(location, unit="fahrenheit"):

    """Get the current weather in a given location"""

    weather_info = {

        "location": location,

        "temperature": "72", # APIで気温は動的に得られる

        "unit": unit,

        "forecast": ["sunny", "windy"], # APIで天気は動的に得られる

    }

    return json.dumps(weather_info)

def run_conversation():

    # 2. OpenAIのチャットモデルに対するAPIリクエストの作成

    # GPTへの質問文をmessagesという変数に格納している

    messages = [{"role": "user", "content": "What's the weather like in Boston?"}]

    # functionsという変数に、呼ぶ関数情報を設定している。

    functions = [

        {

            # 呼び出す関数の名前や説明

            "name": "get_current_weather", #関数名

            "description": "Get the current weather in a given location", #関数の説明

            # 関数の引数について設定している

            "parameters": {

                "type": "object", # 関数が受け取るパラメータは、JSON形式

                # 引数について設定している。今回は、location と unit の2種類

                "properties": {

                    "location": {# location 引数は、string 型。description は具体例.

                        "type": "string",

                        "description": "The city and state, e.g. San Francisco, CA",

                    },

                    "unit": { #unit 引数は、string 型。

                        "type": "string", 

                        "enum": ["celsius", "fahrenheit"] #許容される文字列2種類を指定

                        },

                },

                "required": ["location"], #location 引数は必須であることを指定

            },

        }

    ]

    # 格納した変数を使い、Function Calling機能を使った会話リクエストを作る

    response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo-0613",

        messages=messages,

        functions=functions,

        function_call="auto",  

    )

    # 3. APIレスポンスからメッセージを取得します

    response_message = response["choices"][0]["message"]

    # 4. メッセージに関数呼び出しが含まれているかどうかを確認

    if response_message.get("function_call"):

        # 関数呼び出し(function_call)がされていたら、関数を呼び出すための処理を実行する

        # 実行される関数を動的に選ぶための処理。

        # 入力規則は以下。

        # functionsで入力したnameパラメータ(文字列型) : def で定義した関数名(関数型)

        available_functions = {

            "get_current_weather": get_current_weather,

        }

        # GPTが呼び出すと判断した関数の情報を取得します。

        # 今回の場合は、get_current_weather()関数

        function_name = response_message["function_call"]["name"]

        # 引数情報を取得

        function_args = json.loads(response_message["function_call"]["arguments"])

        # function_to_call に関数型が値が代入される

        function_to_call = available_functions[function_name]

        # そのため以下は、get_current_weather()関数が実行されたときと同じ挙動をする。

        function_response = function_to_call(

            location=function_args.get("location"),

            unit=function_args.get("unit"),

        )

        # 関数呼び出しで取得した値を messages変数(GPTへの質問文)に追加

        # ここでは、関数呼び出しを行い、質問、回答を持ち合わせている状態

        messages.append(response_message) 

        messages.append(

            {

                "role": "function",

                "name": function_name,

                "content": function_response,

            }

        )  

        #5. 前段までで準備した情報をGPT-3.5 モデルに入力する。

        # こうすることで質問に対しての回答を整理するイメージ

        second_response = openai.ChatCompletion.create(

            model="gpt-3.5-turbo-0613",

            messages=messages,

        ) 

        # 7. 最後に、json形式なので、「ボストンの天気」情報に絞った要素を

        return second_response["choices"][0]["message"]["content"] 

# 1. run_conversation()関数を呼び出し、その出力を表示します。

print(run_conversation())

1. 最初にrun_conversation()関数が呼び出されます。この関数の役割は、OpenAIのチャットモデルを利用してユーザーの質問に基づいた天候情報を取得することです。

# 1. run_conversation()関数を呼び出し、その出力を表示します。
print(run_conversation())

2. run_conversation()関数内で最初に行うことは、OpenAI チャットモデルとの会話リクエストの作成。このプロセスはopenai.ChatCompletion.createメソッドを利用して行われます。そのために、まずは必要な情報を変数に格納しています。

具体的には、messages変数にはモデルへの質問文(「What’s the weather like in Boston?」)を、functions変数には呼び出すべき関数の設定(get_current_weather)をそれぞれ格納しています。この後、これらの情報を用いてGPT-3.5モデルに対する会話リクエストを作成しています。

def run_conversation():

    # 2. OpenAIのチャットモデルに対するAPIリクエストの作成

    # GPTへの質問文をmessagesという変数に格納している

    messages = [{"role": "user", "content": "What's the weather like in Boston?"}]

    # functionsという変数に、呼ぶ関数情報を設定している。

    functions = [

        {

            # 呼び出す関数の名前や説明

            "name": "get_current_weather", #関数名

            "description": "Get the current weather in a given location", #関数の説明

            # 関数の引数について設定している

            "parameters": {

                "type": "object", # 関数が受け取るパラメータは、JSON形式

                # 引数について設定している。今回は、location と unit の2種類

                "properties": {

                    "location": {# location 引数は、string 型。description は具体例.

                        "type": "string",

                        "description": "The city and state, e.g. San Francisco, CA",

                    },

                    "unit": { #unit 引数は、string 型。

                        "type": "string", 

                        "enum": ["celsius", "fahrenheit"] #許容される文字列2種類を指定

                        },

                },

                "required": ["location"], #location 引数は必須であることを指定

            },

        }

    ]

    # 格納した変数を使い、Function Calling機能を使った会話リクエストを作る

    response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo-0613",

        messages=messages,

        functions=functions,

        function_call="auto",  

    )

3. 次に、APIレスポンスから情報を取得します。Function Calling 判定などに必要な情報を一部抜粋してmessage 変数に格納します。

# 3. APIレスポンスからメッセージを取得します

message = response["choices"][0]["message"]

4. message 変数にfunction_call という値があるかを確認します。もしあれば、name パラメータを使って関数(get_current_weather)を呼び出します。

# 4. メッセージに関数呼び出しが含まれているかどうかを確認

    if response_message.get("function_call"):

        # 関数呼び出し(function_call)がされていたら、関数を呼び出すための処理を実行する

        # 実行される関数を動的に選ぶために必要な処理。available_functions への入力規則は以下。

        # functionsで入力したnameパラメータ(文字列型) : def で定義した関数名(関数型)

        available_functions = {

            "get_current_weather": get_current_weather,

        }

        # GPTが呼び出すと判断した関数情報を取得します。

        # 今回の場合は、get_current_weather()関数

        function_name = response_message["function_call"]["name"]

        # 引数情報を取得

        function_args = json.loads(response_message["function_call"]["arguments"])

        # function_to_call に関数型が値が代入される

        function_to_call = available_functions[function_name]

        # そのため以下は、get_current_weather()関数が実行されたときと同じ挙動をする。

        function_response = function_to_call(

            location=function_args.get("location"),

            unit=function_args.get("unit"),

        )

        print(response_message)

        # 関数呼び出しで取得した値を messages変数(GPTへの質問文)に追加

        # ここでは、関数呼び出しを行い、質問、回答を持ち合わせている状態

        messages.append(response_message) 

        messages.append(

            {

                "role": "function",

                "name": function_name,

                "content": function_response,

            }

        )

5. get_current_weather(location, unit=”fahrenheit”)関数について。上述したrun_conversation()関数内で、呼び出されています。この関数は、location 引数で指定された場所の現在の天候情報をJSON形式で取得。その後、JSON形式から文字列に変換し、値を返します。

# 5. 天気情報を取得する関数を定義します。

# 本来ならAPIを使いますが、デモのためダミーデータを使います。

def get_current_weather(location, unit="fahrenheit"):

    """location 引数から与えられた場所の気温データ取得"""

    weather_info = {

        "location": location,

        "temperature": "72", # APIを使えば、気温は動的に得られる

        "unit": unit,

        "forecast": ["sunny", "windy"], # APIを使えば、天気は動的に得られる

    }

    return json.dumps(weather_info)

6. 2つ目のAPIレスポンス。messages 変数には、質問や関数呼び出しで取得した回答が格納されています。それを再度、GPTに入力することで整理し、最終的な回答が得られます。

#6. 前段で準備した情報をGPT-3.5 モデルに入力する。

        # こうすることで、get_current_weather()関数からの値が取得できる

        second_response = openai.ChatCompletion.create(

            model="gpt-3.5-turbo-0613",

            messages=messages,

        )

7. return second_response[“choices”][0][“message”][“content”]について。今回の場合はget_current_weather()関数の戻り値が格納されています。

# 7. 最後に、「ボストンの天気」の情報が得られます。

return second_response["choices"][0]["message"]["content"]

ChatGPTのFunction Callingの活用例

ここまで挙げてきたもの以外で、Function Calling(ChatGPT)の活用例としては下記が考えられます。

  • RPAとの組み合わせで、柔軟な判断を交えながら反復作業を自動化
  • 光学式文字認識(OCR)との組み合わせで、紙のデータをデジタル化&構造化
  • ECサイトでの商品検索・説明提供・受発注対応の自動化 等

「安定した繰り返し処理」を強みとする外部ツールに、LLM最大の魅力「文脈・状況を踏まえた柔軟な判断力」が合わさることで、従来以上の高度な自動化が実現しそうです。

Function Callingを利用する際の注意点

Function Callingを利用するにあたって注意する点は以下の3つです。

  • トークンの使用量が大きくなりすぎるケースがある
  • 1度のリクエストで複数の情報は得られない
  • 関数を正確に定義する必要がある

通常それほど差し障りのある問題ではありませんが、念頭には置いておいてください。

トークンの使用量が大きくなりすぎるケースがある

上の例のように、欲しい情報が指定位置の天気情報だけのような場合は大した使用量にはなりません。

しかし、例えば「東京のホテルを教えて」というような内容の場合、AIは複数件のホテル施設名や金額、プラン、その他オプション情報をつけて返答します。このような場合、あっという間にトークン数が膨れ上がり、トークン数オーバーによる400エラー(BadRequest)の発生が起こることをはじめ、利用料金が嵩んでしまうことも予想されます。

最近のOpenAIのAPI Modelは、比較的大きいトークンリクエストに耐えられるものもありますが、ユーザーの問いかけへの返答に対してたくさんの情報量が求められる場合には、マッチしづらいケースがあります。

1度のリクエストで複数の情報を得ることはできない

Function Callingでは、複数個のfunctionsを設定することができますが、assistantのResponseの中には1度に1つのfunctionの情報しか含まれません。

例えば、「ボストンの現在の天気とおすすめのお店を教えて」のようなプロンプトの場合です。この場合は、指定位置の天気情報を取得する処理と、指定位置のお店情報を取得する処理について、個別に都度応答と処理を行う必要があります。

関数を正確に定義する必要がある

Function Callingでは、あらかじめ関数(外部ツールの取扱説明書)をJSON形式で定義しておく必要があります。こちらに際しては、「関数名・処理の説明・パラメータ」の要素と「各要素のタイプ指定」を正確に定めることが必須。定義が不正確だと、実行時にエラーが出てしまうおそれがあります。

なお、ChatGPTのAPIついて詳しく知りたい方は、下記の記事を合わせてご確認ください。

Function Callingを使いこなそう

Function Calling機能は、GPTが外部データへのアクセスを可能にしました。
それほど変わっていないように感じるかもしれませんが、実はとても画期的な機能で、ものすごく賢いGPTの回答が学習データにとどまらないことを意味します。

一例ですが、以下のような振る舞いが可能になりました。

  • ユーザーが”ボストンの天気は何ですか?”と質問する
  • AIはそれを解析し、「天気について尋ねられたので、天気APIを実行する関数を呼び出そう」と自動的に判断する
  • その結果、天気APIのデータを基に、「ボストンの天気は晴れです!」と回答する

興味のある方はぜひ、Function Callingを試してみてくださいね。

最後に

いかがだったでしょうか?

Function Callingを活用すれば、自社システムとChatGPTを連携し、業務自動化や顧客対応を高度化できます。

株式会社WEELは、自社・業務特化の効果が出るAIプロダクト開発が強みです!

開発実績として、

・新規事業室での「リサーチ」「分析」「事業計画検討」を70%自動化するAIエージェント
・社内お問い合わせの1次回答を自動化するRAG型のチャットボット
・過去事例や最新情報を加味して、10秒で記事のたたき台を作成できるAIプロダクト
・お客様からのメール対応の工数を80%削減したAIメール
・サーバーやAI PCを活用したオンプレでの生成AI活用
・生徒の感情や学習状況を踏まえ、勉強をアシストするAIアシスタント

などの開発実績がございます。

生成AIを活用したプロダクト開発の支援内容は、以下のページでも詳しくご覧いただけます。
➡株式会社WEELのサービスを詳しく見る。

まずは、「無料相談」にてご相談を承っておりますので、ご興味がある方はぜひご連絡ください。
➡︎生成AIを使った業務効率化、生成AIツールの開発について相談をしてみる。

生成AIを社内で活用していきたい方へ
メルマガ登録

「生成AIを社内で活用したい」「生成AIの事業をやっていきたい」という方に向けて、通勤時間に読めるメルマガを配信しています。

最新のAI情報を日本最速で受け取りたい方は、以下からご登録ください。

また、弊社紹介資料もご用意しておりますので、併せてご確認ください。

タイトルとURLをコピーしました