Open11

OpenAI の ChatGPT に追加された FunctionCall を使ってみたテスト

at yasuat yasu

要は何者?

プログラムで読ませる時に、プロンプトコーディングで json などでフォーマットを指定しないといけなかったのを、ええ感じに読み込みやすい形式にして返させるようにする機能。(として捉えた。他の使い方もあるかもしれない)

at yasuat yasu

からのあれこれをする感じ。 ChatGPT がわからない部分を推測・補足する感じに使う。ただ、ピンポイントにしないと駄目なのが難しいから、返り値を整えたいとかに使うほうがメインになる?

at yasuat yasu

とりあえず、手元でサクッと使えるのが openai-php/client -- github があるので、それで試してみる。

サンプルとしてあるのは What\'s the weather like in Boston? というプロンプトを投げたら、 location と わかれば unit も返すといった感じのもの。隠しておいた方が良いだろなという部分は「にゃーん」に書き換えている。

> $response = $openai->create([    'model' => 'gpt-3.5-turbo-0613',
.     'messages' => [
.         ['role' => 'user', 'content' => 'What\'s the weather like in Boston?'],
.     ],
.     'functions' => [
.         [
.             'name' => 'get_current_weather',
.             'description' => 'Get the current weather in a given location',
.             'parameters' => [
.                 'type' => 'object',
.                 'properties' => [
.                     'location' => [
.                         'type' => 'string',
.                         'description' => 'The city and state, e.g. San Francisco, CA',
.                     ],
.                     'unit' => [
.                         'type' => 'string',
.                         'enum' => ['celsius', 'fahrenheit']
.                     ],
.                 ],
.                 'required' => ['location'],
.             ],
.         ]
.     ]
. ]);
= OpenAI\Responses\Chat\CreateResponse {#6799
    +id: "chatcmpl-にゃーん",
    +object: "chat.completion",
    +created: 1686797479,
    +model: "gpt-3.5-turbo-0613",
    +choices: [
      OpenAI\Responses\Chat\CreateResponseChoice {#6802
        +index: 0,
        +message: OpenAI\Responses\Chat\CreateResponseMessage {#6800
          +role: "assistant",
          +content: null,
          +functionCall: OpenAI\Responses\Chat\CreateResponseFunctionCall {#6789
            +name: "get_current_weather",
            +arguments: """
              {\n
                "location": "Boston, MA"\n
              }
              """,
          },
        },
        +finishReason: "function_call",
      },
    ],
    +usage: OpenAI\Responses\Chat\CreateResponseUsage {#6792
      +promptTokens: 82,
      +completionTokens: 18,
      +totalTokens: 100,
    },
  }
at yasuat yasu

どこまで期待通りに動いているかわからんから、プロンプトに適当なテキストを書いて、それが「古文」「漢文」「現代文」のいずれかか分類できるか試す。

プロンプト: 次の文は漢文・古文・現代文のいずれかです。どれにあたるか分類してください。\n\n色は匂えど、散りぬるを\n我が世誰そ、常ならむ

:think_face: この使い方合ってるのか…?

> $response = $openai->create([
.     'model' => 'gpt-3.5-turbo-0613',
.     'messages' => [
.         ['role' => 'user', 'content' => "次の文は漢文・古文・現代文のいずれかです。どれにあたるか分類してください。\n\n色は匂えど、散りぬるを\n我が世誰そ、常ならむ"],
.     ],
.     'functions' => [
.         [
.             'name' => 'get_text_historical',
.             'description' => '日本語の文章を漢文・古文・現代文のいずれかに分類します。',
.             'parameters' => [
.                 'type' => 'object',
.                 'properties' => [
.                     'text' => [
.                       'type' => 'string',
.                       'description' => '分類する文章'
.                     ],
.                     'genre' => [
.                         'type' => 'string',
.                         'enum' => ['漢文', '古文', '現代文']
.                     ],
.                 ],
.                 'required' => ['text', 'genre'],
.             ],
.         ]
.     ]
. ]);
= OpenAI\Responses\Chat\CreateResponse {#6803
    +id: "chatcmpl-にゃーん",
    +object: "chat.completion",
    +created: 1686798510,
    +model: "gpt-3.5-turbo-0613",
    +choices: [
      OpenAI\Responses\Chat\CreateResponseChoice {#6806
        +index: 0,
        +message: OpenAI\Responses\Chat\CreateResponseMessage {#6804
          +role: "assistant",
          +content: null,
          +functionCall: OpenAI\Responses\Chat\CreateResponseFunctionCall {#6792
            +name: "get_text_historical",
            +arguments: """
              {\n
                "text": "色は匂えど、散りぬるを\n我が世誰そ、常ならむ",\n
                "genre": "古文"\n
              }
              """,
          },
        },
        +finishReason: "function_call",
      },
    ],
    +usage: OpenAI\Responses\Chat\CreateResponseUsage {#6796
      +promptTokens: 164,
      +completionTokens: 53,
      +totalTokens: 217,
    },
  }
at yasuat yasu

GPT model が 0613 のものであれば使える機能なので、GPT-4-0613 を使ってみる。結果的には、プロンプト的にも難しいものではないので、GPT-3.5 と変わらない。

> $response = $openai->create([
.     'model' => 'gpt-4-0613',
.     'messages' => [
.         ['role' => 'user', 'content' => "次の文は漢文・古文・現代文のいずれかです。どれにあたるか分類してください。\n\n色は匂えど、散りぬるを\n我が世誰そ、常ならむ"],
.     ],
.     'functions' => [
.         [
.             'name' => 'get_text_historical',
.             'description' => '日本語の文章を漢文・古文・現代文のいずれかに分類します。',
.             'parameters' => [
.                 'type' => 'object',
.                 'properties' => [
.                     'text' => [
.                       'type' => 'string',
.                       'description' => '分類する文章'
.                     ],
.                     'genre' => [
.                         'type' => 'string',
.                         'enum' => ['漢文', '古文', '現代文']
.                     ],
.                 ],
.                 'required' => ['text', 'genre'],
.             ],
.         ]
.     ]
. ]);
= OpenAI\Responses\Chat\CreateResponse {#6822
    +id: "chatcmpl-にゃーん",
    +object: "chat.completion",
    +created: 1686801004,
    +model: "gpt-4-0613",
    +choices: [
      OpenAI\Responses\Chat\CreateResponseChoice {#6821
        +index: 0,
        +message: OpenAI\Responses\Chat\CreateResponseMessage {#6819
          +role: "assistant",
          +content: null,
          +functionCall: OpenAI\Responses\Chat\CreateResponseFunctionCall {#6815
            +name: "get_text_historical",
            +arguments: """
              {\n
              "text": "色は匂えど、散りぬるを 我が世誰そ、常ならむ",\n
              "genre": "古文"\n
              }
              """,
          },
        },
        +finishReason: "function_call",
      },
    ],
    +usage: OpenAI\Responses\Chat\CreateResponseUsage {#6817
      +promptTokens: 164,
      +completionTokens: 50,
      +totalTokens: 214,
    },
  }
at yasuat yasu

問い合わせた functionCall を使って更に問い合わせができる。

> $response = $openai->create([
.     'model' => 'gpt-4-0613',
.     'messages' => [
.         ['role' => 'user', 'content' => "現代文にして"],
.         $response->choices[0]->message->toArray(),
.         ['role' => 'function', 'name' => 'get_text_historical', 'content' => json_encode(['text' => "色は匂えど、散りぬるを\n我が世誰そ、常ならむ", 'genre' => '古文']) ]
.     ]
. ]);

= OpenAI\Responses\Chat\CreateResponse {#6792
    +id: "chatcmpl-にゃーん",
    +object: "chat.completion",
    +created: 1686805403,
    +model: "gpt-4-0613",
    +choices: [
      OpenAI\Responses\Chat\CreateResponseChoice {#6811
        +index: 0,
        +message: OpenAI\Responses\Chat\CreateResponseMessage {#6825
          +role: "assistant",
          +content: "「色は香りますが、消えてしまうでしょう。私たちの中で、誰が永遠にいられるでしょうか?」",
          +functionCall: null,
        },
        +finishReason: "stop",
      },
    ],
    +usage: OpenAI\Responses\Chat\CreateResponseUsage {#6823
      +promptTokens: 157,
      +completionTokens: 47,
      +totalTokens: 204,
    },
  }

at yasuat yasu

あたしの参考文がアレだな。もうちょっと ChatGPT が苦手な関数的な物、算術演算とかにしないとわかりにくい。

at yasuat yasu

GTP-4 を使ったらコケた。なんだろな…

> $response = $openai->create([
.     'model' => 'gpt-4-0613',
.     'messages' => [
.         ['role' => 'user', 'content' => "単価130円のトマトが三個あります。100円のオクラが2つあります。消費税を含めた支払い金額はいくらでしょう?"],
.     ],
.     'functions' => [
.         [
.             'name' => 'get_multiplication',
.             'description' => '掛け算をします',
.             'parameters' => [
.                 'type' => 'object',
.                 'properties' => [
.                     'price' => [
.                       'type' => 'integer',
.                       'description' => '単価'
.                     ],
.                     'unit' => [
.                         'type' => 'integer',
.                         'description' => '購入個数'
.                     ],
.                 ],
.                 'required' => ['price', 'unit'],
.             ],
.         ],[
.             'name' => 'get_price_within_tax',
.             'description' => '消費税を含めた金額を返す',
.             'parameters' => [
.                 'type' => 'object',
.                 'properties' => [
.                     'price' => [
.                       'type' => 'integer',
.                       'description' => '購入金額'
.                     ],
.                 ],
.                 'required' => ['price'],
.             ],
.         ]
.     ]
. ]);

   OpenAI\Exceptions\ErrorException  That model is currently overloaded with other requests. You can retry your request, or contact us through our help center at help.openai.com if the error persists. (Please include the request ID fbe965bf366b26e73206268dd275c828 in your message.).
at yasuat yasu

GPT-3.5-turbo ならそれっぽく動いた。小学生の算数のようなプロンプトを投げて算術演算をFunctionCallに書いてみるテスト。なんかこれは使い方が違うっぽい。

> $response = $openai->create([
.     'model' => 'gpt-3.5-turbo-0613',
.     'messages' => [
.         ['role' => 'user', 'content' => "単価130円のトマトが三個あります。100円のオクラが2つあります。消費税を含めた支払い金額はいくらでしょう?"],
.     ],
.     'functions' => [
.         [
.             'name' => 'get_multiplication',
.             'description' => '掛け算をします',
.             'parameters' => [
.                 'type' => 'object',
.                 'properties' => [
.                     'price' => [
.                       'type' => 'integer',
.                       'description' => '単価'
.                     ],
.                     'unit' => [
.                         'type' => 'integer',
.                         'description' => '購入個数'
.                     ],
.                 ],
.                 'required' => ['price', 'unit'],
.             ],
.         ],[
.             'name' => 'get_price_within_tax',
.             'description' => '消費税を含めた金額を返す',
.             'parameters' => [
.                 'type' => 'object',
.                 'properties' => [
.                     'price' => [
.                       'type' => 'integer',
.                       'description' => '購入金額'
.                     ],
.                 ],
.                 'required' => ['price'],
.             ],
.         ]
.     ]
. ]);
= OpenAI\Responses\Chat\CreateResponse {#6749
    +id: "chatcmpl-にゃーん",
    +object: "chat.completion",
    +created: 1686806078,
    +model: "gpt-3.5-turbo-0613",
    +choices: [
      OpenAI\Responses\Chat\CreateResponseChoice {#6777
        +index: 0,
        +message: OpenAI\Responses\Chat\CreateResponseMessage {#6747
          +role: "assistant",
          +content: null,
          +functionCall: OpenAI\Responses\Chat\CreateResponseFunctionCall {#6818
            +name: "get_multiplication",
            +arguments: """
              {\n
              "price": 130,\n
              "unit": 3\n
              }
              """,
          },
        },
        +finishReason: "function_call",
      },
    ],
    +usage: OpenAI\Responses\Chat\CreateResponseUsage {#6741
      +promptTokens: 162,
      +completionTokens: 21,
      +totalTokens: 183,
    },
  }

> 
> $response = $openai->create([
.     'model' => 'gpt-4-0613',
.     'messages' => [
.         ['role' => 'user', 'content' => "つづき"],
.         $response->choices[0]->message->toArray(),
.         ['role' => 'function', 'name' => 'get_multiplication', 'content' => json_encode(['multiplication' => "390"]) ]
.     ]
. ]);
= OpenAI\Responses\Chat\CreateResponse {#6793
    +id: "chatcmpl-にゃーん",
    +object: "chat.completion",
    +created: 1686806296,
    +model: "gpt-4-0613",
    +choices: [
      OpenAI\Responses\Chat\CreateResponseChoice {#6809
        +index: 0,
        +message: OpenAI\Responses\Chat\CreateResponseMessage {#6753
          +role: "assistant",
          +content: "計算結果は390です。",
          +functionCall: null,
        },
        +finishReason: "stop",
      },
    ],
    +usage: OpenAI\Responses\Chat\CreateResponseUsage {#6758
      +promptTokens: 47,
      +completionTokens: 9,
      +totalTokens: 56,
    },
  }
at yasuat yasu

意地悪をしてみる

functionCall で渡す内容に全く関係のないプロンプトを投げてみる。

> $response = $openai->create([
.     'model' => 'gpt-3.5-turbo-0613',
.     'messages' => [
.         ['role' => 'user', 'content' => "コーヒーの淹れ方を教えてください。"],
.     ],
.     'functions' => [
.         [
.             'name' => 'get_multiplication',
.             'description' => '掛け算をします',
.             'parameters' => [
.                 'type' => 'object',
.                 'properties' => [
.                     'price' => [
.                       'type' => 'integer',
.                       'description' => '単価'
.                     ],
.                     'unit' => [
.                         'type' => 'integer',
.                         'description' => '購入個数'
.                     ],
.                 ],
.                 'required' => ['price', 'unit'],
.             ],
.         ]
.     ]
. ]);

= OpenAI\Responses\Chat\CreateResponse {#6834
    +id: "chatcmpl-にゃーん",
    +object: "chat.completion",
    +created: 1686809118,
    +model: "gpt-3.5-turbo-0613",
    +choices: [
      OpenAI\Responses\Chat\CreateResponseChoice {#6841
        +index: 0,
        +message: OpenAI\Responses\Chat\CreateResponseMessage {#6821
          +role: "assistant",
          +content: """
            コーヒーの淹れ方を教えます。\n
            \n
            1. 材料と道具を準備します。\n
               - コーヒー豆:お好みの種類を選んでください。\n
               - 水:美味しいコーヒーを淹れるためには、良質な水を使いましょう。\n
               - コーヒーミル:豆を挽くためのミルがあると良いですが、挽いてある粉でも大丈夫です。\n
               - コーヒーメーカーやフレンチプレスなど、コーヒーを淹れるための器具。\n
            \n
            2. コーヒーミルで豆を挽きます(挽いてある場合はこのステップは飛ばしてください)。\n
               - 中細挽きが良いとされていますが、お好みに合わせて挽いてください。\n
            \n
            3. 適量の水を温めます。\n
               - 一般的には、コーヒーの量に対して水を1:15〜1:18の割合で使います。\n
               - 例えば、30gのコーヒー豆に対して、水を450ml〜540mlくらい使用します。\n
            \n
            4. コーヒー豆と温めた水を器具に入れます。\n
               - コーヒーメーカーを使用する場合は機械の説明に従って操作してください。\n
               - フレンチプレスを使用する場合は、豆と水をフレンチプレスの中に入れ、軽くかき混ぜたら蓋をして待ちます。\n
            \n
            5. 濃さや風味に合わせて抽出時間を調整します。\n
               - コーヒーメーカーを使用する場合は自動で抽出されますので、そのまま待ちます。\n
               - フレンチプレスを使用する場合は、おおよその抽出時間は4〜5分です。\n
               - 抽出時間が長いと苦みが強くなり、短いと薄味になります。\n
            \n
            6. 抽出が終わったら、コーヒーを楽しみましょう!\n
               - コーヒーメーカーの場合はカップに注いで、フレンチプレスの場合はプレスを押して下さい。\n
            \n
            以上が一般的なコーヒーの淹れ方です。お好みに合わせてコーヒーの豆や水の量、抽出時間を調整してみてください。どうぞ、お楽しみください!
            """,
          +functionCall: null,
        },
        +finishReason: "stop",
      },
    ],
    +usage: OpenAI\Responses\Chat\CreateResponseUsage {#6744
      +promptTokens: 81,
      +completionTokens: 710,
      +totalTokens: 791,
    },