はじめに
組織はアプリケーションを強化するためにOpenAI APIのような高度なAPIに依存しています。これらのAPIはAIや機械学習モデルとの対話を可能にします。しかし、API呼び出しのコストを決定するAPIトークンの管理は困難です。過剰使用は高コストにつながり、一方で過小使用ではリソースを無駄にしてしまいます。
この課題に対処するため、トークン使用状況を可視化するダッシュボードを提案します。データ管理にはGridDB、バックエンド開発にはNode.js、フロントエンドUIにはReactを活用します。このドキュメントは、問題を理解し、解決策を構想し、選択した技術で効果的に実装するためのガイドを提供することを目的としています。
このブログの目的
このドキュメントの主な目的は、GridDB、Node.js、React を使用して OpenAI API トークンの使用状況ダッシュボードを構築するための徹底的かつ体系的なガイドを提供することです。
セットアップと実行
GitHub リポジトリからソースコードをクローンします。
git clone https://github.com/junwatu/openai-tokens-dashboard.git
GridDB と Node.js LTS 18 がインストールされていることを確認してください。 インストールされていない場合は、このブログ記事の インストール セクションを参照してください。
ディレクトリを openai-tokens-dashboard
フォルダに変更し、.env
ファイルを作成または編集します。OpenAI API にアクセスできるはずです。キーを作成し、作成した OpenAI API キーを OPENAI_API_KEY
環境変数に設定します。
OPENAI_API_KEY=put_your_key_here
ルートプロジェクト、server
ディレクトリ、ui
ディレクトリにて依存関係含めてnpmパッケージをインストールします。
cd openai-tokens-dashboard
npm install
cd server
npm install
cd ../ui
npm install
ディレクトリを server
に変更し、ダッシュボードサーバーを実行します。
cd server
npm run start
別のターミナルを開き、ディレクトリをルートプロジェクトから ui
ディレクトリに変更して、ダッシュボードの UI 開発を実行します。
cd ui
npm run dev
サーバーとクライアントが起動している場合は、ブラウザーを開き、http://localhost:5173
に移動します。
すべてが順調に進んでいれば、上のスクリーンショットのようなウェブ・ユーザー・インターフェイスが表示されます。
OpenAI APIを深く掘り下げる
トークン使用状況ダッシュボードにOpenAI APIを効果的に統合して利用するには、APIの特徴、機能、利用可能なエンドポイントを理解することが不可欠です。これにより、トークンの使用データを取得し、コストを計算し、ダッシュボードにアップデートを提供することが可能になります。
ここでは、OpenAI APIの主な主要点について詳しく見ていきます。
-
APIドキュメント: OpenAIが提供するAPIの公式ドキュメントを確認することから始めましょう。このプロジェクトではチャット補完を使います。チャットAPIのドキュメントには、利用可能なエンドポイント、リクエスト/レスポンスフォーマット、特定のガイドラインや制限事項の概要が記載されています。
-
コスト: OpenAIはリリースしているモデルごとに異なる価格体系を持っています。私たちのプロジェクトでは、
gpt-3.5-turbo
またはgpt-3.5-turbo-16k
モデルを利用します。これらのモデルのコストテーブルは以下の通りです:Model Input Output 4K context $0.0015 / 1K tokens $0.002 / 1K tokens 16K context $0.003 / 1K tokens $0.004 / 1K tokens
OpenAI APIを深く掘り下げることで、その機能を包括的に理解し、それに応じてトークン使用ダッシュボードを設計することができます。
核心的な問題: トークンの使用コスト
OpenAI API トークンの理解
OpenAI の API は、リクエストを処理する際の基本的な作業単位としてトークンを使用します。基本的に、トークンはAPIが読み取って処理するテキストの塊です。トークンは厳密には単語、文字、バイトに相当しませんが、計算作業の尺度として考えることができます。
テキストをトークンに分割するトークン化プロセスは、モデルが使用する特定のアルゴリズムに従います。例えば英語の場合、トークンは1文字という短いものから、"a "や "apple "のような1単語という長いものまであります。しかし、すべての単語が1つのトークンではないことに注意する必要があります。例えば、"chatbot "という単語は1つのトークンですが、"ChatGPT "のような単語は、テキストをトークン化するためにモデルがどのようにトレーニングされたかに基づいて、複数のトークン("Chat"、"##G"、"##PT")に分割されるかもしれません。
APIコールのトークンの数は、コールのコストとコールが全く機能するかどうかの両方に大きく影響します。OpenAIはトークンごとに課金し、モデルには1回の呼び出しで処理できるトークンの上限があります。例えば、2021年9月現在、gpt-3.5-turbo
モデルは1回の呼び出しで4096トークンが上限です。
トークンの数え方を理解することは、コストを管理し、APIコールが意図したとおりに動作することを保証するために非常に重要です。コストを管理し、OpenAI API を効率的に使用するためには、トークンがどのように機能し、API 呼び出しにどのように影響し、どのように正確にカウントするかを理解することが不可欠です。
トークン使用によるコストへの影響
OpenAI API を使用するコストは、API 呼び出し中に処理されたトークンの数に直接リンクしています。この価格モデルは、テキストの生成、テキストの翻訳、その他のタスクの実行など、APIリクエストの種類に関係なく当てはまります。
各APIコールは一定数のトークンを消費します。トークンには、モデルに生成を依頼するメッセージ内のトークンだけでなく、提供するプロンプト内のトークンや、特別な指示やフォーマットのために予約されたトークンも含まれます。したがって、API呼び出しで使用されるトークンの総数は、入力プロンプト内のトークン、生成されるメッセージ、および特別な指示の合計となります。
トークン使用量の監視と管理の必要性
トークンの使用量とコストには直接的な相関関係があり、APIコールの成功にも影響することから、OpenAIのAPIを使用する際にはトークンの使用量を監視・管理することが非常に重要であることは明らかです。これが重要な理由はいくつかあります。
-
予算の見積もり: トークンの使用状況を監視することで、ユーザーは自分の使用パターンが予算とどのように整合しているかを知ることができます。新しいアプリケーションを設計するために、トークンのコストを見積もることができれば、非常に価値があります。
-
API利用の最適化: トークンを監視することで、APIがどの程度効率的に使用されているかについての貴重な洞察を得ることができます。例えば、制御命令やフォーマットのために大量のトークンが使用されている場合、ユーザはアプリケーションの機能を犠牲にすることなく、トークン数を減らすために使用方法を改善できるかもしれません。
トークン使用状況ダッシュボード
トークン使用状況ダッシュボードの役割と利点
トークン使用状況ダッシュボードは、ユーザが OpenAI API 呼び出しのトークン使用状況を監視・管理するためのツールです。このようなダッシュボードは、トークンの使用状況に関する洞察を提供し、OpenAI API の使用に関連する意思決定プロセスをサポートする上で重要な役割を果たします。トークン使用状況ダッシュボードを実装する主な利点は以下の通りです。
-
モニタリング: トークン使用状況ダッシュボードは、トークンの使用状況に関する最新情報を提供することができます。
-
使いやすさ: 優れたデザインのダッシュボードは、トークンの使用状況を視覚的にわかりやすく表示します。これにより、技術的なユーザもそうでないユーザもアクセスしやすくなり、幅広い理解とより効果的な意思決定が促進されます。
次のセクションでは、このダッシュボードを構築する技術としてGridDB、Node.js、Reactが選ばれた理由と、これらの利点を達成するためにそれらがどのように貢献しているかについて掘り下げていきます。
なぜGridDB、Node.js、Reactなのか?
効率的でユーザーフレンドリーなトークン使用状況ダッシュボードを構築する上で、テクノロジーの選択は極めて重要です。このプロジェクトでは、 GridDB、Node.js、React を主要なテクノロジーとして選択しました。その理由は以下の通りです。
GridDB
GridDBは、IoTやビッグデータ向けに最適化された、拡張性の高いインメモリNoSQL時系列データベースです。大量の構造化データの保存と検索に適しており、トークンの使用データを長期的に管理・追跡するのに最適です。
主な利点は以下の通りです:
-
スケーラビリティ: GridDBは優れたスケーラビリティを備えており、大量のデータを容易に扱うことができます。これは、トークンの使用状況をリアルタイムで監視したり、トレンド分析のために過去のデータを保存したりする上で非常に重要です。
-
スピード: GridDBはインメモリデータベースであるため、高速なデータ処理が可能です。これにより、リアルタイムのモニタリングや迅速な意思決定に不可欠な、タイムリーな更新と迅速なレスポンスを実現します。
-
信頼性: GridDB の堅牢なアーキテクチャは、高可用性とデータの一貫性を保証し、トークン使用状況ダッシュボードの信頼できる基盤を提供します。
Node.js
Node.js は、Chrome の V8 JavaScript エンジン上に構築された強力な JavaScript ランタイムです。Node.jsはスケーラブルなネットワーク・アプリケーションを構築するように設計されており、トークン使用量ダッシュボードのバックエンドを実装するのに最適です。Node.jsを選択した理由は以下の通りです。
-
パフォーマンス: Node.jsは、イベント駆動、ノンブロッキングI/Oモデルを使用しているため、軽量で効率的です。これは、我々のトークン使用量ダッシュボードのような、分散デバイス間で実行されるデータ集約的なリアルタイム・アプリケーションに最適です。
-
コミュニティ・サポート: Node.jsには大規模で活発なコミュニティがあり、開発のスピードアップや一般的な問題を解決するためのライブラリやフレームワークが豊富に用意されています。
-
統合: Node.jsはGridDBやReactとシームレスに統合でき、スタック全体で統一されたJavaScript開発環境を提供します。
-
コスト: Node.jsの優れた点は、JavaScriptをメイン言語として、バックエンドからクライアントサイドまで、完全に機能するWebアプリケーションを開発できることです。
React
Reactは、ユーザーインターフェイス、特にシングルページのアプリケーションを構築するためのJavaScriptライブラリです。Facebookと個々の開発者や企業のコミュニティによって管理されています。Reactを選ぶ理由は以下の通りです。
-
コンポーネントベース: Reactは、開発者が独自の状態を管理するカプセル化されたコンポーネントを構築し、それらを組み合わせて複雑なUIを作ることを可能にします。これは、さまざまなインタラクティブ要素を持つダッシュボードの構築に最適です。
-
効率性: Reactは、メモリ内のデータ構造キャッシュを作成し、結果の差分を計算し、ブラウザの表示DOMを効率的に更新します。その結果、高速で応答性の高いユーザー・インターフェースが実現されます。
-
人気とサポート: React は広く使用されており、強力なコミュニティがあるため、トークン使用状況ダッシュボードのフロン トエンドを構築するための安全で信頼できる選択肢となります。
GridDB、Node.js、React を組み合わせることで、トークン使用状況ダッシュボードを構築するための強力で効率的、かつ信頼性の高いスタックが提供されます。
ダッシュボードの設計
ソリューションの構造化
OpenAI API トークン使用状況ダッシュボードを効果的に実装するには、スケーラビリティ、保守性、拡張性を確保する強固なアーキテクチャ設計を確立する必要があります。
以下は、提案されているソリューションのアーキテクチャ設計の概要です。
1. クライアント・サーバー・アーキテクチャー:このソリューションはクライアント・サーバー・アーキテクチャーを採用し、クライアント・サイドがユーザー・インターフェースのレンダリングとユーザーとのインタラクションを担当し、サーバー・サイドがデータ処理、ストレージ、外部APIとの通信を担当します。
2. フロントエンド(クライアントサイド):
- React: フロントエンドはReact JavaScriptライブラリを使用して開発されます。Reactのコンポーネント・ベースのアプローチと仮想DOMは、効率的なレンダリングを可能にし、レスポンシブなユーザー・インターフェースを保証します。
3. バックエンド(サーバーサイド):
- Node.js: バックエンドは、一般的なサーバーサイドJavaScriptランタイムであるNode.jsを使用して構築されます。Node.jsはイベント駆動、ノンブロッキングI/Oモデルを提供し、同時リクエストやリアルタイム更新の処理に適しています。
- Express.js: Node.js用のウェブ・アプリケーション・フレームワークであるExpress.jsを使用して、RESTful APIの開発を簡素化し、ルーティング、ミドルウェア、リクエスト/レスポンスを処理します。
- GridDB: 高性能インメモリデータベースであるGridDBは、データ管理とストレージに利用されます。GridDBの分散アーキテクチャとスケーラビリティ機能は、大量のトークン利用データの処理に適しています。
- OpenAI APIの統合: サーバーサイドのコードは、トークン利用データを取得するためにOpenAI APIと統合します。この統合には、APIリクエスト、認証処理、レスポンスデータの解析が含まれます。
4. データフロー
- クライアントサイドは、Node.js バックエンドによって公開される RESTful API エンドポイントを通じてサーバーサイドと通信します。
- サーバーサイドはGridDBとやり取りし、トークンの利用データを効率的に保存・取得します。
- また、OpenAIのAPIとも連携し、トークンの利用状況をリアルタイムで取得します。
- 処理されたデータはJSONレスポンスとしてクライアントサイドに返され、ダッシュボードのユーザーインターフェイスを更新するために使用されます。
フロントエンドとバックエンドを明確に分離することで、外部APIとの統合が容易になり、将来的なダッシュボードの拡張や追加にも対応できる強固な基盤を提供します。
インストール
GridDBのセットアップ
GridDBのセットアップは簡単です。Ubuntuへの新規インストールはこちらのリンクを、WindowsへのWSL(Windows Subsystem Linux)経由のインストールはこちらを参照してください。
既にインストールされている場合は、以下のコマンドでgriddbサービスが実行されているか確認してください。
sudo systemctl status gridstore
このUbuntu OSのコマンドライン出力は、griddbサービスが実行されていることを示しています。
● gridstore.service - GridDB database server.
Loaded: loaded (/lib/systemd/system/gridstore.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2023-07-04 04:47:12 +07; 9h ago
Main PID: 575 (gsserver)
Tasks: 34 (limit: 7017)
Memory: 144.7M
CGroup: /system.slice/gridstore.service
└─575 /usr/bin/gsserver --conf /var/lib/gridstore/conf
Jul 04 04:47:08 GenAI systemd[1]: Starting GridDB database server....
Jul 04 04:47:09 GenAI gridstore[381]: Starting gridstore service:
Jul 04 04:47:12 GenAI gridstore[526]: ..
Jul 04 04:47:12 GenAI gridstore[526]: Started node.
Jul 04 04:47:12 GenAI gridstore[381]: [ OK ]
Jul 04 04:47:12 GenAI systemd[1]: Started GridDB database server..
Node.js のセットアップ
このブログ記事で取り上げているプロジェクトでは、Node.js LTS バージョン 18 を使用しています。Node.jsがインストールされているかどうかを確認するには、以下のコマンドを実行してください。
node --version
Node.jsがインストールされていないか、古いバージョンを使っている場合は、公式サイトnodejs.orgからNode.js LTSをアップグレードまたはインストールすることをお勧めします。
OpenAI ダッシュボードのビルド
このプロジェクトアプリケーションのソースコードは、こちらから参照できます。
GridDBとNode.jsの統合
Node.jsはシンプルなサーバーとして機能するが、Express.jsのようなフレームワークを使用することで、データの解析や経路管理を簡素化することができ、メンテナンスが容易になります。Node.jsサーバーとGridDBデータベースを接続するアプリケーションの中核は、griddb.cjs
ファイルです。このファイルはプロジェクトの lib
ディレクトリにあります。このファイル内の関数により、GridDB の初期化、データの保存、データのクエリなどを行うことができます。
GridDB を初期化するには、Node.js サーバで griddb.cjs
をインポートします。
// in the routes.js file
import * as GridDB from './libs/griddb.cjs';
const { collectionDb, store, conInfo, containerName } =
await GridDB.initGridDbTS();
データを保存するには、以下の機能を使います。
async function saveData({ prompt, cost, details }) {
const id = generateRandomID();
// Data is saved as an array
const content = [parseInt(id), prompt, cost, details];
const saveStatus = await GridDB.insert(content, collectionDb);
console.log(`GridDB save operation: ${saveStatus.status}`);
if (saveStatus.status) {
return { status: saveStatus, operation: 'save' };
} else {
return { status: saveStatus, operation: 'save' };
}
}
saveData
関数は、GridDBのデータを以下のフィールドを持つコレクションとして保存します。
- id: コレクションの ID (整数型)
- prompt: プロンプト(文字列)
- cost: 各 OpenAI API 呼び出しのコスト (文字列)
- details: トークンの詳細データ (文字列)
データは配列 content
として保存することと、GridDB からすべてのデータをクエリすることが重要です。
const data = await GridDB.queryAll(conInfo, store);
接続情報 conInfo
とストアまたはコレクション store
は griddb.cjs
内の関数によって自動的に提供されます。必要に応じて、そのデータをさらに処理するために利用することができます。
このアプリケーションの Node.js サーバーには 3 つの主要なルートがあります。
Routes | Operation | Purpose |
---|---|---|
http://localhost:2001/api | GET | Show all the data in the GridDB database |
http://localhost:2001/api | POST | Call OpenAI API and save the data response in the GridDB database |
http://localhost:2002/api/totalcost | GET | Get the cost data for all prompts |
OpenAI APIでトークンを管理する
OpenAI APIとNode.jsの統合は、公式ライブラリopenai-node
の助けを借りて実現できます。このプロジェクトで使用するデフォルトのOpenAIモデルは gpt-3.5-turbo-16k
です。
// services/prompt.js
import { Configuration, OpenAIApi } from 'openai';
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
//...
const completion = await openai.createChatCompletion({
model: 'gpt-3.5-turbo-16k',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: prompt },
],
max_tokens: 1000,
});
トークンのコスト計算は priceTag
リファレンスに基づきます。
const priceTag = {
prompt: 0.003,
completion: 0.004,
};
OpenAIのモデルを変更した場合は、プライスタグリファレンス(こちらを参照)も変更するようにしてください。
ダッシュボードのUIをReactで構築する
OpenAI APIトークン使用状況ダッシュボードの直感的でユーザーフレンドリーなインターフェースを確保するために、Reactの力を活用します。
ウェブアプリケーションのユーザーインターフェースは、主に2つの部分から構成されます。
-
プロンプト入力: このセクションでは、OpenAI APIのプロンプトを入力します。
-
ダッシュボード: このセクションはトークンの使用量を表示し、関連するコストの見積もりを提供します。トークンとコストのデータを表示するための UI 要素は 3 つあります。
-
Cost: 現在のプロンプト・コストを示します。
-
Tokens: 現在のトークン数を示します。
-
All Total Cost: GridDB データベースから取得したコスト合計を示します。
-
ダッシュボードのユーザーインターフェースのソースコードは ui
ディレクトリにあります。Reactを使えば、データのためのインタラクティブなユーザーインターフェースを驚くほど簡単に構築できます。先ほどのNode.jsサーバールートで見たように、ダッシュボードからデータを保存したり読み込んだりするために、それらを簡単に利用することができます。Node.js サーバールートを呼び出してレスポンスデータを処理するには、fetch
WebAPI を使用するだけです。
fetch('http://localhost:2001/api', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ input: inputText }),
})
.then((response) => response.json())
.then((data) => {
console.log(data);
setUsageData(data.data.usage);
// Update totalTokens
const promptTokensInK = data.data.usage.prompt_tokens / 1000;
const completionTokensInK = data.data.usage.completion_tokens / 1000;
const promptTokensCost = promptTokensInK * 0.003;
const completionTokensCost = completionTokensInK * 0.004;
setTotalTokens(data.data.usage.total_tokens);
setTotalCost(promptTokensCost + completionTokensCost);
})
.catch((error) => {
console.error(error);
});
inputText
には、OpenAI APIのプロンプトデータを入力します。OpenAI API には特定のレスポンス・フォーマットがあることに注意してください。
{
id: 'chatcmpl-7YMGXEuuR4Wi7HKNFa5XAbTL5hWgb',
object: 'chat.completion',
created: 1688423097,
model: 'gpt-3.5-turbo-16k-0613',
choices: [ { index: 0, message: [Object], finish_reason: 'stop' } ],
usage: { prompt_tokens: 148, completion_tokens: 6, total_tokens: 154 }
}
サーバーサイドでもクライアントサイドでも、データを処理するのは簡単だ。Reactでデータを表示するには、useState
を使って自動的にUIを更新することができます。
const [totalTokens, setTotalTokens] = useState(0);
// Set total tokens to update Tokens ui
setTotalTokens(data.data.usage.total_tokens);
このプロジェクトでは、ダッシュボード・アプリケーションのために特別に作られた Tremor UIを使用しています。 こちらをご覧ください。
<Card>
<div className="h-24">
<Title>Tokens</Title>
<Metric>{totalTokens}</Metric>
<Flex className="mt-2">
{usageData ? (
<Text>
{usageData.prompt_tokens} Prompt{' '}
{usageData.completion_tokens} Completion{' '}
</Text>
) : (
<p>Loading...</p>
)}
</Flex>
</div>
</Card>
結論
このブログ記事のプロジェクトはMVPに過ぎません。履歴やログの表示、データの視覚化の改善、より優れた分析ビューなどの機能を追加することで、さらに強化することができます。