🛒

OpenAIのAPIとFunction Callingを活用したAI販売員のサンプル実装

2023/06/18に公開

Function Callingを利用し、以下のような会話ができるコードを書いてみた。

  • Function Callingで以下の関数を定義
    • 商品ランキングのカテゴリ一覧を返す
    • 商品カテゴリIDを引数で受け取り、そのカテゴリの人気商品を返す
  • GPT-3.5には家電量販店の販売員をしてもらう
    • 在庫がある商品を優先して案内する
  • ユーザーが欲しい商品のカテゴリを入力すると、人気の商品を勧める
  • ユーザーがexitと入力すると処理を終了する

実際の動作

どんな商品をお探しですか?
 ('exit'で終了):USBメモリ
GPT-3の回答: USBメモリのおすすめ商品は以下の通りです。

1. USBメモリA 512GB
   - 在庫あり

2. USBメモリB 256GB
   - 在庫なし

3. USBメモリ 1TB 令和最新型
   - 在庫あり

在庫がある商品を優先していますので、USBメモリA 512GBかUSBメモリ 1TB 令和最新型がおすすめです。どちらになさいますか?
 ('exit'で終了):ハードディスクはある?
GPT-3の回答: 申し訳ありませんが、現在ハードディスクの在庫はございません。他の商品をお探しすることはできますので、どうぞお気軽にお申し付けください。
 ('exit'で終了):exit

「 ('exit'で終了):」の後ろはユーザーからの入力です。

  • USBメモリ
    • get_product_ranking_categoriesでカテゴリIDを取得(例の場合、USBメモリはid=1)
    • get_product_rankingでUSBメモリの人気商品を取得
  • ハードディスクはある?
    • USBメモリと同様に処理
    • こちらは在庫がないため、その旨を伝えている。素晴らしい

コード

import json
import openai

openai.organization = "org-xxx" # TODO 実際の組織IDを設定する
openai.api_key = "xxxx" # TODO APIキーを設定する

def get_product_ranking_categories(params):
    # TODO APIリクエストを実装する。サンプルは固定値としている
    categories = [
        {"id":"1","name":"USBメモリ"},
        {"id":"2","name":"ハードディスク"},
    ]
    return json.dumps(categories, ensure_ascii=False)

def get_product_ranking(params):
    # TODO APIリクエストを実装する。サンプルは固定値としている
  if params.get("categoryId") == "1":
    return json.dumps([
      {"id": 1001, "name":"USBメモリA 512GB","isInStock":True},
      {"id": 1002, "name":"USBメモリB 256GB","isInStock":False},
      {"id": 1003, "name":"USBメモリ 1TB 令和最新型","isInStock":True},
    ], ensure_ascii=False)

  return json.dumps([
    {"id": 2001, "name":"HDD A","isInStock":False},
    {"id": 2002, "name":"HDD B","isInStock":False},
    {"id": 2003, "name":"HDD C","isInStock":False},
  ], ensure_ascii=False)


functions = [
    {
        "name": "get_product_ranking_categories",
        "description": "商品ランキングのカテゴリ一覧を取得する",
        "parameters": {
            "type": "object",
            "properties": {
              "name": {
                  "type": "string",
                  "description": "カテゴリ名",
              },
            },
            "required": [],
        },
    },
    {
        "name": "get_product_ranking",
        "description": "商品カテゴリIDを受け取り、そのカテゴリの人気商品ランキングを返す。レスポンスには、商品IDと商品名、店舗在庫有無の情報を持ったdictを返す。",
        "parameters": {
            "type": "object",
            "properties": {
                "categoryId": {
                    "type": "string",
                    "description": "商品カテゴリID",
                },
            },
            "required": ["categoryId"],
        },
    }
]

def ask_gpt3(conversation):
  response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-0613",
    messages=conversation,
    functions=functions,
    function_call="auto",
  )
  # print(response)
  return response

def main():
    print("どんな商品をお探しですか?")
    conversation = [{"role": "system", "content": "あなたは家電量販店の販売員です。ユーザーが欲しい商品のカテゴリを聞いて、おすすめの商品を教えてあげてください。ユーザーは正確にカテゴリ名を入力しないため、カテゴリ名が一番近いであろうカテゴリを勧めてください。ただし、店舗に在庫がある商品を優先して勧めてください。"}]
    while True:
        # ユーザーからの入力を受け取る
        user_input = input(" ('exit'で終了):")
        if user_input.lower() == 'exit':
            break

        conversation.append({"role": "user", "content": user_input})

        while True:
	  # GPT-3.5に質問する
          response = ask_gpt3(conversation)

          # レスポンスを確認
          message = response.choices[0]["message"]
          if message.get("function_call"):
	    # 関数呼び出しの場合
            f_call = message.get("function_call")
            function_name = f_call["name"]
            args = json.loads(f_call["arguments"])
            function_response = globals()[function_name](args)
            # print(function_response)
            conversation.append({
                  "role": "function",
                  "name": function_name,
                  "content": function_response,
              })
          else:
            # GPT-3.5の回答を出力する
            resMessage = message["content"].strip()
            conversation.append({"role": "assistant", "content": resMessage})

            print("GPT-3の回答:", resMessage)
            break

if __name__ == "__main__":
    main()

Discussion