nikkie-ftnextの日記

イベントレポートや読書メモを発信

すごいすごい! GPTを呼び出すアプリケーションが持っている関数を、GPTがFunction callingで呼び出せるぞ! これはヤバい!

はじめに

callingといえばダーク・コーリング覇王十代! nikkieです。

OpenAIから先日発表された「Function calling」を完全に理解しました!
※エンジニアミームの「完全に理解した」ですので、近日中に何も分からなくなるやつです

目次

それ(Function calling)は突然やってきた

6/14に目が覚めたらOpenAIからAPI利用者向けにメールが来ていて、「なにか重要そうなことを言っているが、さっぱりわからない。関数(function)って何?どういうこと?」となりました。
そうして完全に理解するための素振りというTODOが積まれたのです

ありがとう、先人の日本語で読めるアウトプット

Function callingという概念から分からなかったので、日本語で読める記事にいくつかあたりました。
はてなブックマークのテクノロジータブを中心に、話題になっているものを手当たり次第読んでいます。

情報収集の中で、「GPTを呼び出すアプリケーションが持っている関数を、GPTがFunction callingで呼び出せる」らしいという仮説を持ちます。

OpenAIのドキュメントの例

公式ドキュメントにあたって手を動かし仮説を検証します。
https://platform.openai.com/docs/guides/gpt/function-calling

公式ドキュメントから案内されたクックブックも参考にしました。

ボストンの天気を日本語で聞く

今回の題材はN番煎じですが、ドキュメントの例を写経する中で「日本語でも動作するだろうな」と思ったので、日本語にしたバージョンを公開します。

  • 1つ目のリクエス
    • functionsでアプリケーション(今回はスクリプト)がどんな関数を持っているかをGPTに入力
    • get_current_whetherがどんな関数かをOpenAIのAPI仕様に沿って入力
      • parameterslocationを伝えるというのはうまいな〜
      • parametersunit、デフォルト値を伝えないと「72℃」とcelsiusで返された(人住めないよ😱)ので伝えています1
  • 1つ目のレスポンスから関数呼び出しする実装は、ウォルラス2(代入式)を使って重複を減らしています
  • OpenAIのChat completion API呼び出しではtemperature=0を指定(検証なので返り値がブレないように)4
  • termcolorはcookbook5から6
    • 経過が色付きで見えるの、裏で何が起きているかわかりやすい!

動作例

今回の動作環境です

  • Python 3.10.9
  • openai 0.27.8
  • termcolor 2.3.0

環境変数OPENAI_API_KEYを設定しています(openaiライブラリが見るので、Pythonコードでの設定は不要)

「こんにちは」にはFunction calling不要

毎回Function callingされるわけではないことの確認です。
最初のプロンプトを「ボストンの天気は?」から「こんにちは。あなたの名前は?」に変えてみます。

% python ja_docs_example.py
こんにちは!私は名前を持っていません。私はAIアシスタントです。どのようにお手伝いできますか?

Chat Completion APIからは以下のJSONが返っています。
Function callingしていませんね。

{
  "id": "chatcmpl-7SlBqmUItQTBDOQL18bwqZTT8f03z",
  "object": "chat.completion",
  "created": 1687088938,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "\u3053\u3093\u306b\u3061\u306f\uff01\u79c1\u306f\u540d\u524d\u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093\u3002\u79c1\u306fAI\u30a2\u30b7\u30b9\u30bf\u30f3\u30c8\u3067\u3059\u3002\u3069\u306e\u3088\u3046\u306b\u304a\u624b\u4f1d\u3044\u3067\u304d\u307e\u3059\u304b\uff1f"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 113,
    "completion_tokens": 40,
    "total_tokens": 153
  }
}

GPTにボストンの天気を聞くとFunction callingして答えてくれる

「ボストンの天気は?」と聞いてみます。

% python ja_docs_example.py
ボストンの天気は晴れで、風も強いです。現在の気温は72°Fです。

Chat Completion APIの一度目の呼び出しでは、get_current_weatherを呼び出すというJSONが返っています。
ボストンはマサチューセッツ州の州都なので、"Boston, MA"と例に沿った形に変換してget_current_weatherを呼び出しています!

{
  "id": "chatcmpl-7SlE7IIr62tTCLxZPMVLno9dPUerK",
  "object": "chat.completion",
  "created": 1687089079,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "function_call": {
          "name": "get_current_weather",
          "arguments": "{\n  \"location\": \"Boston, MA\"\n}"
        }
      },
      "finish_reason": "function_call"
    }
  ],
  "usage": {
    "prompt_tokens": 112,
    "completion_tokens": 18,
    "total_tokens": 130
  }
}

スクリプト内にあるget_current_weatherの呼び出しでは(この関数はほぼモックなので)、以下のJSONが返ります。

{"location": "Boston, MA", "temperature": "72", "unit": "fahrenheit", "forecast": ["sunny", "windy"]}

これをmessagesに追加し、再度Chat Completion APIを呼び出します。
messagesには「ボストンの天気は?」「Function calling」「関数の呼び出し結果」の3つが入っています
返ってくるのは以下のJSON

{
  "id": "chatcmpl-7SlE9QzevQWe2uF28FrwaHJppoT6W",
  "object": "chat.completion",
  "created": 1687089081,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "\u30dc\u30b9\u30c8\u30f3\u306e\u5929\u6c17\u306f\u6674\u308c\u3067\u3001\u98a8\u3082\u5f37\u3044\u3067\u3059\u3002\u73fe\u5728\u306e\u6c17\u6e29\u306f72\u00b0F\u3067\u3059\u3002"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 75,
    "completion_tokens": 33,
    "total_tokens": 108
  }
}

こうしてGPTはFunction callingして、「ボストンの天気は?」というプロンプトに(生成によるハルシネーションなく)答えることができました!

termcolorで色を付けたことで、裏で何が起きているかとてもわかりやすかったです。
レスポンスの日本語はencodeされていてそのままでは読めない出力になっているのが宿題事項です。

終わりに

Function calling、完全に理解した!

get_current_weatherの例の関数はたいしたことなかったですが、cookbookではDB(SQLite)を使った例もあります!
また肝は(途中で引いた)「非常に簡単に思考連鎖(chain of thought)が実現できる」というところかなと思っています。
関数の実装は自由度が非常に高いので、DBに接続してもよし、LLMに質問してもよし、人に聞くなんてこともできちゃうかもしれません。
Function callingでPluginsに相当する機能の手元の関数を呼び出すこともできるはず!

引き続き手を動かして、このあたりの感触(仮説)を検証していくぞ〜


  1. cookbookではInfer this from the users location.(ユーザの場所から推論してください)と伝えていました。こんなこともできるのか!
  2. :=は「ウォルラス」って読むんです!『Effective Python 第2版』項目10をどうぞ
  3. PyCon JP 2022で「Pythonとアスタリスク」として話した事項の中の1つです
  4. Ngセンセの教え
  5. cookbookの実装ですが、requestsを使っているのが謎です。openai.ChatCompletion.createの方が楽なんじゃなかろうか
  6. coloramaのほかにtermcolorもあるのか〜