アップデートされたgpt-3.5-turbo-0613を使えば、自分の作った関数と連携できるらしいので実験

準備

pythonのインストールなどは、前回までの記事に記載しています。

OpenAIのAPIの関数呼び出しとは

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

OpenAIの新機能「関数呼び出し」により、開発者はGPTモデルに対して特定の関数を説明し、それらの関数を呼び出すためのJSONオブジェクトを生成させることができます。これにより、GPTの能力と外部ツールやAPIとをより確実に連携させることができます。例えば、「来週の金曜日にAnyaにコーヒーを飲みに行くかどうかメールを送る」や「ボストンの天気はどうですか?」といった自然言語のクエリを、それぞれsend_email(to: string, body: string)get_current_weather(location: string, unit: 'celsius' | 'fahrenheit')のような関数呼び出しに変換することができます。また、API呼び出しやデータベースクエリへの変換、テキストからの構造化データの抽出といった応用も可能です。具体的な使用例としては、ユーザーが「ボストンの現在の天気は?」と尋ね、それがget_current_weather関数の呼び出しに変換され、その結果がGPTモデルによって要約される、といった流れが挙げられます。これにより、開発者はより確実に構造化データをGPTモデルから取得でき、ユーザーの入力に基づいて関数を呼び出すことができます​。

会議室検索と連動させるプログラムを実装

公式のお天気関数呼び出しを参考に、ダミーの会議室予約関数をChatと連動させるプログラムです。

このプログラムは、GPT-3.5-turbo-0613を使用して、会議室の空き状況を検索するための対話システムを実装しています。ユーザーは、日付、定員、設備を指定して、空いている会議室を検索することができます。GPT-3.5は、ユーザーの入力を解釈し、関数を呼び出して、空いている会議室のリストを返します。このプログラムは、Pythonで書かれており、コンソールで実行することができます。

  • function.py
import openai
import json
import datetime
import sys
sys.stdout.reconfigure(encoding='utf-8')

# Example dummy function hard coded to return the same weather
# In production, this could be your backend API or an external API
def get_current_weather(location, unit="fahrenheit"):
    """Get the current weather in a given location"""
    weather_info = {
        "location": location,
        "temperature": "36",
        "unit": unit,
        "forecast": ["sunny", "windy"],
    }
    return json.dumps(weather_info)

json_data = '''
{
  "rooms": [
    {
      "id": 1,
      "name": "会議室A",
      "capacity": 10,
      "facilities": ["プロジェクター", "ホワイトボード"],
      "availability": {
        "2023-06-28": {
          "09:00": true,
          "10:00": true,
          "11:00": false,
          "12:00": true,
          "13:00": false,
          "14:00": true,
          "15:00": true
        },
        "2023-06-29": {
          "09:00": true,
          "10:00": false,
          "11:00": true,
          "12:00": true,
          "13:00": true,
          "14:00": true,
          "15:00": true
        }
      }
    },
    {
      "id": 2,
      "name": "会議室B",
      "capacity": 6,
      "facilities": ["ホワイトボード"],
      "availability": {
        "2023-06-28": {
          "09:00": false,
          "10:00": false,
          "11:00": true,
          "12:00": true,
          "13:00": true,
          "14:00": true,
          "15:00": true
        },
        "2023-06-29": {
          "09:00": true,
          "10:00": true,
          "11:00": true,
          "12:00": true,
          "13:00": true,
          "14:00": true,
          "15:00": true
        }
      }
    },
    {
      "id": 3,
      "name": "会議室C",
      "capacity": 4,
      "facilities": [],
      "availability": {
        "2023-06-28": {
          "09:00": true,
          "10:00": true,
          "11:00": true,
          "12:00": true,
          "13:00": true,
          "14:00": true,
          "15:00": true
        },
        "2023-06-29": {
          "09:00": true,
          "10:00": true,
          "11:00": true,
          "12:00": true,
          "13:00": true,
          "14:00": true,
          "15:00": true
        }
      }
    }
  ]
}
'''


def get_available_rooms(date, capacity, facilities):
    # JSONデータを辞書に変換
    data = json.loads(json_data)
    # フィルタリング結果を格納するリスト
    filtered_rooms = []
    # 会議室を順番にチェック
    for room in data['rooms']:
        # 会議室の空き状況を取得
        availability = room['availability'].get(date)
        # 空き状況が存在する場合
        if availability:
            # 会議室の定員をチェック
            if room['capacity'] >= capacity:
                # 会議室の設備をチェック
                if all(facility in room['facilities'] for facility in facilities):
                    # roomからavailabilityを削除
                    del room['availability']
                    # フィルタリング条件に合致する会議室を追加
                    filtered_rooms.append(room)
    # フィルタリング結果を返す
    return json.dumps(filtered_rooms)


def run_conversation():
    # Step 1: send the conversation and available functions to GPT
    messages = [
        {"role": "system", "content": 'こんにちは。今日の' + str(datetime.date.today()) + 'の空いている会議室を検索します。'},
        {"role": "user", "content": "6/29日 13時から1時間、空いている会議室を教えてください。ホワイトボードが必要で四人で使います。"}
        ]
    functions = [
        {
            "name": "get_available_rooms",
            "description": "空いてる会議室を検索する。戻り値は空いている会議室のリスト",
            "parameters": {
                "type": "object",
                "properties": {
                    "date": {
                        "type": "string",
                        "description": "日付 e.g. yyyy-mm-dd",
                    },
                    "capacity": {"type": "number", "description": "定員"},
                    "facilities": {
                        "type": "array", 
                        "description": "設備",
                        "items": {"type": "string", "enum": ["プロジェクター", "ホワイトボード"]}
                    },
                },
                "required": ["date", "capacity"],
            },
        }
    ]
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-0613",
        messages=messages,
        functions=functions,
        function_call="auto",  # auto is default, but we'll be explicit
    )
    response_message = response["choices"][0]["message"]

    # Step 2: check if GPT wanted to call a function
    if response_message.get("function_call"):
        # Step 3: call the function
        # Note: the JSON response may not always be valid; be sure to handle errors
        available_functions = {
            "get_available_rooms": get_available_rooms,
        }  # only one function in this example, but you can have multiple
        function_name = response_message["function_call"]["name"]
        fuction_to_call = available_functions[function_name]
        function_args = json.loads(response_message["function_call"]["arguments"])
        function_response = fuction_to_call(
            date=function_args.get("date"),
            capacity=function_args.get("capacity"),
            facilities=function_args.get("facilities"),
        )

        print(response_message)

        # Step 4: send the info on the function call and function response to GPT
        messages.append(response_message)  # extend conversation with assistant's reply
        messages.append(
            {
                "role": "function",
                "name": function_name,
                "content": function_response,
            }
        )  # extend conversation with function response
        second_response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=messages,
        )  # get a new response from GPT where it can see the function response
        return second_response


res = run_conversation()
enc = json.dumps(res, indent=2, ensure_ascii=False)
print(enc)

実行はコンソールから。

python function.py

実行結果

こんな感じで、使える会議室を返してくれました!

2023年6月29日の13:00から1時間利用可能な会議室を検索しました。以下の2つの会議室が該当します。

1. 会議室A:

– 定員: 10人

– 設備: プロジェクター、ホワイトボード

2. 会議室B:

– 定員: 6人

– 設備: ホワイトボード

どちらの会議室を利用しますか?