理系学生日記

おまえはいつまで学生気分なのか

初めてのGPTのAPI(OpenAI API):コストの理解とTypeScriptでの呼び出し

TL;DR

初めてOpenAI APIを使ってみました。 まず、OpenAIのHTTP APIとNode.jsライブラリopenai-nodeの使用方法について学び、その上でTypeScriptを使ってAPIを実際に呼び出してみました。その過程でAPIの使用料金と、それがどのようにモデルや入出力トークン数によって決定されるかについて理解を深めました。

以上はChatGPTによって生成してもらったTL;DRです。

OpenAI API

OpenAIはHTTP APIを提供しています。 そのAPIを使うためのライブラリとして、公式にはPython、Node.js用のライブラリがあり、Javaを含む他の言語用にはコミュニティのライブラリが存在します。

仕様はOpenAPIとして公開されています。

今回は、openai-nodeを使い、TypeScriptでAPIを呼び出してみます。

APIの基礎知識

費用

APIの費用は、利用するモデルによって決まるトークンあたりの費用と、入出力トークン数によって決まります。

モデル

OpenAIでは複数のモデルを用意しており、自然言語をアウトプットするGPT-4GPT-3.5等が代表的です。他にも自然言語から画像を生成するDALL·Eや自然言語をベクトルに変換するEmbeddingsもあります。 またFine-tuningとして、davincicuriebabbageadaに対しては、学習させることで自分好みのモデルへと成長させることが可能です。

これらのモデルとコンテキスト長ごとに、1Kトークンあたりの単価が異なります。

6/17時点では以下のようになっており、コンテキストの小さい方でGPT-3.5と比較とGPT-4を比較すると、Inputで20倍、Outputで30倍のコストとなることがわかります。

Model Input (1K tokenあたり) Output (1K tokenあたり)
gpt-3.5-turbo (4K context) $0.0015 $0.002
gpt-3.5-turbo (16K context) $0.003 $0.004
GPT-4 (8K context) $0.03 $0.06
GPT-4 (32K context) $0.06 $0.12

トークン

ではそもそもトークンとは何かというと、自然言語をベクトル化していく単位となる文字列です。 OpenAI Platformでは以下のように説明されています。

Tokens represent commonly occurring sequences of characters.

OpenAI Platformでは、文章に対して実際のトークンがどうなるかを試す機能が提供されています。例えばtokenizationtokenizationという2つのトークンに分割されます。

あくまで概算ですが、英語については4文字が1トークン相当になるとされています。

A helpful rule of thumb is that one token generally corresponds to ~4 characters of text for common English text. This translates to roughly ¾ of a word (so 100 tokens ~= 75 words).

https://platform.openai.com/tokenizer

僕は日本語を主としているため、日本語のトークン数は当然気になるところです。 OpenAIが利用しているtokenizerはtiktokenであるため、これを用いればある程度の精度でトークン数を求められそうです。

このあたりはすでに先人が実施してくれており、この結果を信じるとおよそ日本語1文字が1トークンくらい、という印象です。

実際にAPIを使ってみる

Chat Completion APIとCompletion API

ChatGPTで利用されているような、プロンプトに対してレスポンスを得るタイプのAPIとして以下2つのAPIが存在します。

  • Chat Completion API
  • Completion API

最初はこの2つの違いが何か、というところに迷いました。 結論から言えば、gpt-4gpt-3.5-turboを用いるのであれば前者のChat Completion API一択です。text-davinci-003のような2022年までのモデルではCompletion APIを使うことになります。

Our latest models, gpt-4 and gpt-3.5-turbo, are accessed through the chat completions API endpoint. Currently, only the older legacy models are available via the completions API endpoint.

OpenAI Platform

Chat Completion API

Chat Completion APIのAPI仕様はOpenAI Platformにあります。

主となるリクエストパラメータはmessagesです。ここでは、「誰が」(role)「どのような内容を発したか」(content)を指定します1。これは配列として与えることができ、それによって会話のコンテキストを提供します。

roleとしては以下の種類があります。

role 概要
system 会話の前に、アシスタントのペルソナを指定する。「あなたは弁護士です」など。 未指定の場合は「You are a helpful assistant.」と指示したような一般的な振る舞いとなる。
user 会話におけるアシスタントに対する要望や、質問、アシスタントのレスポンスに対する回答等を指定する。
assistant アシスタントとしてのユーザとの対話内容。
function

つまり誰が何を言ったのかの配列をリクエストパラメータとして渡すことで、チャットを再現するわけですね。

TypeScriptで書いてみる

大まかな内容は飲み込めたので、TypeScriptでChat Completion APIを使ってみましょう。 TypeScriptの型情報はdistディレクトリのd.ts周りを読めば良いでしょう。

選択できるモデルについては以下コマンドで抽出できます。僕はGPT-4 API waitlist待機中なので、gpt-3.5-turboを選択しました。

$ curl https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY" | jq -r '.data[].id'
import { ChatCompletionRequestMessageRoleEnum, Configuration, OpenAIApi } from "openai";
import * as dotenv from "dotenv";

// .envファイルに記載したAPIキーをロードする
dotenv.config();

const openai = new OpenAIApi(new Configuration({
    apiKey: process.env.OPENAI_API_KEY
}));
try {
    const content = "システムインテグレータにとっての、OpenAIのEmbeddings APIを利用するユースケースを示してください";

    // OpenAI APIを利用して情報を取得する。
    // 生成されるテキストが一貫性を持つように、temperatureは0に設定
    const chatCompletion = await openai.createChatCompletion({
        model: "gpt-3.5-turbo",
        messages: [
            { role: ChatCompletionRequestMessageRoleEnum.System, content: `
            あなたはシステムインテグレータに勤めるシステムエンジニアで、経営者にGPTの魅力を伝えるプレゼンをしています。自然言語処理に詳しくない経営者に対してできるだけ伝わりやすく、かつ、魅力的に説明する必要があります。
            `
            },
            { role: ChatCompletionRequestMessageRoleEnum.User , content: content}
        ],
        temperature: 0
    });

    const data = chatCompletion.data;
    console.log(data.choices[0].message?.content);

    console.log(`prompt_tokens: ${data.usage?.prompt_tokens}`);
    console.log(`completion_tokens: ${data.usage?.completion_tokens}`);
    console.log(`total_tokens: ${data.usage?.total_tokens}`);
} catch (error: any) {
    if (error.response) {
        console.log(`${error.response.status}, ${error.response.data.error.message}`);
    }
}

上記スクリプトを実行すると、以下のようになりました。

$ npm run build
$ node dst/index.js
OpenAIのEmbeddings APIは、自然言語処理においてテキストデータを分析するための強力なツールです。以下に、システムインテグレータがEmbeddings APIを利用するユースケースをいくつか示します。

1. テキスト分類
Embeddings APIを使用することで、テキストデータを分類することができます。例えば、ある企業が顧客からのフィードバックを分析したい場合、Embeddings APIを使用して、フィードバックがポジティブかネガティブかを自動的に分類することができます。

2. 意味解析
Embeddings APIを使用することで、テキストデータの意味を解析することができます。例えば、ある企業が顧客からの問い合わせを分析したい場合、Embeddings APIを使用して、問い合わせ内容に対する回答を自動的に生成することができます。

3. 要約生成
Embeddings APIを使用することで、テキストデータを要約することができます。例えば、ある企業が大量のレポートを分析したい場合、Embeddings APIを使用して、レポートの要約を自動的に生成することができます。

4. 言語翻訳
Embeddings APIを使用することで、テキストデータを異なる言語に翻訳することができます。例えば、ある企業が海外の顧客と取引をする場合、Embeddings APIを使用して、顧客からの問い合わせを自動的に翻訳することができます。

以上のように、Embeddings APIは自然言語処理において非常に有用なツールであり、システムインテグレータが様々な分野で活用することができます。
prompt_tokens: 165
completion_tokens: 553
total_tokens: 718

  1. 他にもFunction Callingで使われるパラメータもありますが、今回は割愛します。