話題の記事

【速報 : OpenAI APIがアップデートされました!!】GPT-4, GPT-3.5の0613版がリリース / GPT-3.5のコンテキスト長が4倍に / 新機能Function callingも追加

2023.06.14

こんちには。

データアナリティクス事業本部 インテグレーション部 機械学習チームの中村です。

OpenAI APIのアップデートが以下のように発表されました。

以下がアップデートの概要です。

  • GPT-4とGPT-3.5-turboの0613版が登場
    • 無印を使用中の場合、6月27日に自動的に上記の新モデルにアップグレード
    • それ以降も明示的に指定すれば旧モデルの使用は可能だが、アクセスは9月13日まで(それ以降はリクエストは失敗となる予定)
    • 0613版から、GPT-3.5-turboにコンテキスト長(対応トークン長)が4倍となった16kバージョンも追加
  • 0613版には、Function callingという機能追加が含まれる
    • 自身で定義した処理を組み込んだチャットが実現できる機能
  • GPT-3.5-turboとEmbeddings APIの一部がより低価格で提供

以下は従来通りのようです。

  • 3月1日に導入したのと同じデータプライバシーとセキュリティの保証付きで、APIデータがトレーニングに使用されることはない
  • 学習データは2021年9月分まで

それでは詳細を見ていきましょう。

アップデートについて

GPT-4とGPT-3.5-turboのアップデート

以下が安定版、旧モデル、新モデルの対応付けです。

安定したモデル名 旧モデル 新モデル
gpt-4 gpt-4-0314 gpt-4-0613
gpt-4-32k gpt-4-32k-0314 gpt-4-32k-0613
gpt-3.5-turbo gpt-3.5-turbo-0301 gpt-3.5-turbo-0613
gpt-3.5-turbo-16k (なし) gpt-3.5-turbo-16k-0613

APIドキュメントも更新されているようですので、そちらもご確認ください。

各モデルで0613のsuffixが付いたモデルが公開されています。

モデルを評価するフレームワークであるEvalsで、これらのバージョンを比較評価することも可能なようです。

旧モデルでは存在しなかったgpt-3.5-turbo-16kが登場しており、以下のように最大トークン数が4倍に拡大したモデルとなっています。

  • gpt-3.5-turboの最大トークン数 : 4096token
  • gpt-3.5-turbo-16kの最大トークン数 : 16384token

後述の通り、16kの料金は2倍となるのですが、トークン長が4倍となることで、従来は適用しにくかった用途にも、別途フレームワークを使用することなく適用できる可能性があります。

ちなみに16kのトークン長は、1回のリクエストで20ページ程度のテキストを処理できる程度のもの、と公式アナウンスには記載されています。

一方、APIドキュメントに記載されている通り、TRAINING DATAは「Up to Sep 2021」のままとなっており、従来通り2021年9月までの学習データを用いています。

今後の各モデルのライフサイクルは以下のような計画となっているようです。

  • 安定したモデル名でのアクセスは6月27日に自動的に上記の新モデルにアップグレード
  • それ以降も旧モデルへのアクセスは明示的に指定すれば可能だが、旧モデルへのアクセスは9月13日まで
    • 旧モデルへのアクセスはこれ以降はリクエストに失敗

旧モデルへのアクセスは失敗するようになる点は注意が必要ですね。

公式アナウンスには、今後数週間で、新バージョンでのウェイティングリストの消化を目指したい旨も語られており、使用できるようになる方も増えることが期待されます。

Pricing

価格も改訂されており、一部の機能が低料金化され、これも嬉しいニュースです。

まずはgpt-3.5-turboの料金改訂ですが、以下のように入力トークンと出力トークンで費用が分かれる形となっています。

入力トークン 出力トークン
改訂前 $0.002 / 1K tokens $0.002 / 1K tokens
改訂後 $0.0015 / 1K tokens $0.002 / 1K tokens

少し計算方法が複雑にはなっていますが、入力トークン側の料金が25%安くなっています。

GPT-4の価格は変わらずとなっており、GPT-3.5にも16k版が追加されているため、全体としては以下のような料金体系となります。

入力トークン 出力トークン
gpt-3.5-turbo $0.0015 / 1K tokens $0.002 / 1K tokens
gpt-3.5-turbo-16k $0.003 / 1K tokens $0.004 / 1K tokens
gpt-4 $0.03 / 1K tokens $0.06 / 1K tokens
gpt-4-32k $0.06 / 1K tokens $0.12 / 1K tokens

また使用されることの多いEmbeddings APIである、text-embedding-ada-002の料金も以下のように改訂されました。

料金
改訂前 $0.0004 / 1K tokens
改訂後 $0.0001 / 1K tokens

Embeddings APIはベクトル化したデータを作成するために使用されることも多いため、料金が75%安くなったことは嬉しいですね。

こちらは現時点で記載のものですので、料金情報は公式のページの方も必ずご確認ください。

Function calling

Function callingは開発者向けとしては目玉の機能追加だと思います。

自身で定義した処理を組み込んだチャットが実現できる機能となっています。

文字での説明はちょっと難しいので、詳細は以降の試してみるでご説明致します。

試してみる

それでは実際に動かしてみます。

環境

Google Colaboratoryを使います。

!python --version
Python 3.10.12

openaiライブラリを入れておきます。

!pip install openai
!pip freeze | grep -e "openai"
openai==0.27.8

インポートおよびAPIキーを設定します。

import openai
import os

openai.api_key = "{sk-で始まるAPIキーを指定してください。}"

とりあえず新しいやつを動かす

以下のコードで動かしてみました。

model_name = "gpt-3.5-turbo-0613"

question = "pyenvとpipenvの環境構築方法について教えてください。"

response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
    ],
)
print(response.choices[0]["message"]["content"].strip())

以下のような応答となっています。

pyenvとは、Pythonのバージョン管理ツールであり、複数のPythonバージョンをインストールして切り替えることができます。pipenvはpyenvと組み合わせて使用することで、仮想環境の作成とパッケージ管理を簡素化するツールです。

以下に、pyenvとpipenvの環境構築方法を説明します。

(...以下略...)

他、gpt-3.5-turbo-0613、gpt-4-0613も試しましたが無事に動くことを確認できました。

GPT-4の方はウェイティングリストの状況にもよりますので、必ず動くとは限らない点ご注意ください。

Function callingを試す

こちらは以下のAPIドキュメントをベースに試してみます。

まずは天気を取得する関数を定義します。

ここは本来は別のAPIなどをたたくなどが考えられますが、今回は固定の天気情報を返します。

import json

def get_current_weather(location, unit="fahrenheit"):
    weather_info = {
        "location": location,
        "temperature": "30",
        "unit": unit,
        "forecast": ["sunny", "windy"],
    }
    return json.dumps(weather_info)

次に、この関数に関する情報をOpenAI APIに与えるために、以下のようにdescriptionを含んだデータを作成します。

functions=[
    {
        "name": "get_current_weather",
        "description": "指定した場所の現在の天気を取得する。",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "都市名や地名、県名など",
                },
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
            },
            "required": ["location"],
        },
    }
]

ここからは少しOpenAI APIの使い方に工夫が必要です。

Function callingを使う場合、2回以上OpenAI APIをコールする場合があります。

1回目は普通に問い合わせますが、functionsというパラメータに先ほど作成した関数に関する情報を与えます。

(function_callは"auto"とします)

model_name = "gpt-3.5-turbo-0613"

question = "東京都港区の天気を教えてください。"

response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
    ],
    functions=functions,
    function_call="auto",
)

以下のように1回目のレスポンスのmessageに、function_callが含まれる場合は、2度目のリクエストを投げます。

message = response["choices"][0]["message"]
message
<OpenAIObject at 0x7f4260054c20> JSON: {
  "role": "assistant",
  "content": null,
  "function_call": {
    "name": "get_current_weather",
    "arguments": "{\n  \"location\": \"\u6771\u4eac\u90fd\u6e2f\u533a\"\n}"
  }
}

またこのレスポンスに、引数に何を与えるべきかも含まれますので、その情報を元に自分で定義した関数を呼び出してあげて、2回目のリクエストを投げる形となります。

実装としては以下のようになります。

function_name = message["function_call"]["name"]

arguments = json.loads(message["function_call"]["arguments"])
function_response = get_current_weather(
    location=arguments.get("location"),
    unit=arguments.get("unit"),
)

second_response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
        message,
        {
            "role": "function",
            "name": function_name,
            "content": function_response,
        },
    ],
)

print(second_response.choices[0]["message"]["content"].strip())
東京都港区の現在の天気は晴れで、気温は30度です。風が強いです。

自身で定義した関数をベースに応答できることを確認できました。

一方function_callが含まれない場合(従来通りcontentが含まれる場合)そのまま1回目のレスポンスで答えが得られますので、以下のように条件分岐して実装すれば定義した関数に関連の無いリクエストも処理できます。

if message.get("function_call"):

    function_name = message["function_call"]["name"]

    arguments = json.loads(message["function_call"]["arguments"])
    function_response = get_current_weather(
        location=arguments.get("location"),
        unit=arguments.get("unit"),
    )

    second_response = openai.ChatCompletion.create(
        model=model_name,
        messages=[
            {"role": "user", "content": question},
            message,
            {
                "role": "function",
                "name": function_name,
                "content": function_response,
            },
        ],
    )

    print(second_response.choices[0]["message"]["content"].strip())

else:
    print(response.choices[0]["message"]["content"].strip())

こちらを使って、天気と関係のない問い合わせも投げてみましょう。

model_name = "gpt-3.5-turbo-0613"

question = "pyenvとpipenvの環境構築方法について教えてください。"

response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
    ],
    functions=functions,
    function_call="auto",
)

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

if message.get("function_call"):

    function_name = message["function_call"]["name"]

    arguments = json.loads(message["function_call"]["arguments"])
    function_response = get_current_weather(
        location=arguments.get("location"),
        unit=arguments.get("unit"),
    )

    second_response = openai.ChatCompletion.create(
        model=model_name,
        messages=[
            {"role": "user", "content": question},
            message,
            {
                "role": "function",
                "name": function_name,
                "content": function_response,
            },
        ],
    )

    print(second_response.choices[0]["message"]["content"].strip())

else:
    print(response.choices[0]["message"]["content"].strip())
Sure!
pyenvとpipenvはPythonの環境を管理するための便利なツールです。ここでは、macOSまたはLinux環境での環境構築方法を説明します。

まず、pyenvをインストールします。

(...以下略...)

このように定義した関数を使わずに処理ができることを確認できました。

これは活用の幅がとても広がりそうで、開発者向けにとても良いアップデートですね!

functionsには複数の関数を設定できそうなので、活用の幅はかなり広がりそうです。

ちなみに混乱させるためにdescriptionを適当に書き換えても、正常に定義した関数を呼ぶ処理となりますので、単純にdescriptionで判断しているとも言えなさそうです。

与えるクエリや関数によっては2回以上function_callとなるケースもありますので、かなり複雑な処理も良しなにやってくれそうな印象があります。

もう少し挙動が理解できて来たら別途情報展開したいと思います。

定義した関数を呼び出したくない場合は、function_callを"none"に設定します。

速度比較

混み具合やクエリの内容にもよるので参考程度にとどめておいて頂きたいのですが、測定時は0613版の方が高速に動作している結果となっています。

以下のようなコードで、model_nameのみ変更しながら比較してみました。

%%timeit
model_name = "{モデル名を指定してください}"

question = "pyenvとpipenvの環境構築方法について教えてください。"

response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
    ],
)
モデル 測定結果
gpt-3.5-turbo-0301 24.1 s ± 8.6 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
gpt-3.5-turbo-0613 5.61 s ± 1.43 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
gpt-3.5-turbo-16k-0613 5.92 s ± 355 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
gpt-4-0314 1min 34s ± 18.7 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
gpt-4-0613 24.1 s ± 2.91 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

この結果は、安定版が差し替えられた時に変わってくる可能性もありますが、みなさまも実際に試して体感してみてください。

まとめ

いかがでしたでしょうか。

OpenAIのAPIアップデートについて整理しました。どんどん進化していきますね!

活用の幅が拡がるアップデートもありましたので、弊社でも応用先を広げていきたいと思います。