「リアルタイムデータのためのPythonでのChatGPT APIの使用方法」

PythonでのChatGPT APIのリアルタイムデータの使用方法

OpenAIのGPTは、世界的に最も優れたAIツールとして登場し、その訓練データに基づいてクエリに対応することが得意です。ただし、以下のような未知のトピックに関する質問には答えることができません:

  • 2021年9月以降の最新のイベント
  • 非公開のドキュメント
  • 過去の会話からの情報

このタスクは、頻繁に変更されるリアルタイムのデータを扱う場合にさらに複雑になります。さらに、GPTには広範なコンテンツを入力することはできず、データを長期間保持することもできません。この場合、回答プロセスに文脈を与えるために、効率的にカスタムLLM(言語学習モデル)アプリを構築する必要があります。この記事では、PythonのオープンソースLLMアプリライブラリを利用して、そのようなアプリケーションを開発する手順を説明します。ソースコードはGitHubにあります(「セール用ChatGPT Python APIを構築する」セクションの下にリンクがあります)。

学習目標

以下の内容を記事全体で学ぶことができます:

  • なぜChatGPTにカスタムデータを追加する必要があるのか
  • 埋め込み、プロンプトエンジニアリング、ChatGPTを使用した質問応答の改善方法
  • LLMアプリを使用してカスタムデータを持つ独自のChatGPTを構築する方法
  • リアルタイムの割引やセール価格を検索するためのChatGPT Python APIを作成する方法

なぜChatGPTにカスタムの知識ベースを提供するのか?

ChatGPTを強化する方法について説明する前に、手動の方法を探求し、それらの課題を特定しましょう。通常、ChatGPTはプロンプトエンジニアリングを通じて拡張されます。さまざまなオンライン市場からリアルタイムの割引/セール/クーポンを見つけたい場合を想定してみましょう。

たとえば、ChatGPTに「アディダスのメンズシューズの今週の割引を見つけてもらえますか?」と尋ねると、カスタムな知識を持たないChatGPT UIインターフェースからは次のような標準的な回答が得られます:

明らかなように、GPTは割引の場所や種類などの詳細に関しては一般的なアドバイスを提供していますが、具体性に欠けています。ここでモデルをサポートするために、信頼できるデータソースから割引情報を追加します。実際の質問を投稿する前に、初期のドキュメントコンテンツをChatGPTに追加する必要があります。このサンプルデータはAmazonの商品ディールデータセットから収集し、1つのJSONアイテムだけをプロンプトに挿入します:

期待される出力が得られていることがわかります。これは非常に簡単に実現できます。なぜなら、ChatGPTは文脈を認識しているからです。ただし、この方法の問題点は、モデルの文脈が制限されることです(GPT-4の最大テキスト長は8,192トークンです)。この戦略は、入力データが膨大な場合に問題を引き起こす可能性があります。セールで見つかるアイテムは数千に及ぶ可能性があり、この大量のデータを入力メッセージとして提供することはできません。また、データを収集した後は、データの品質と関連性を確保するためにデータをクリーニング、整形、前処理する必要があります。

OpenAIのChat Completionエンドポイントを利用するか、ChatGPT用のカスタムプラグインを構築すると、以下のような別の問題が発生します:

  • コスト – より詳細な情報や例を提供することで、モデルの性能は向上するかもしれませんが、その場合のコストも高くなります(GPT-4の場合、10,000トークンの入力と200トークンの出力の場合、1回の予測に対するコストは0.624ドルです)。同じリクエストを繰り返し送信すると、コストが増える可能性があります。ローカルキャッシュシステムを利用しない限り。
  • レイテンシ – OpenAIなどのChatGPT APIを本番環境で利用する際の課題は、予測可能性がないことです。一貫したサービスの提供は保証されません。
  • セキュリティ – カスタムプラグインを統合する際には、各APIエンドポイントをOpenAPI仕様で指定する必要があります。これにより、内部APIのセットアップをChatGPTに公開することになります。多くの企業はこのリスクを懐疑的に見ています。
  • オフライン評価 – 開発者にとって、コードとデータの出力に対してオフラインテストを実施したり、データフローをローカルで再現したりすることは難しいです。なぜなら、システムへの各リクエストごとに異なる応答が返される可能性があるからです。

埋め込み、プロンプトエンジニアリング、ChatGPTを使用した質問応答

インターネット上で見つかる有望なアプローチは、LLMを利用して埋め込みを作成し、その後、検索や質問応答システムなどのアプリケーションをこの埋め込みを使用して構築することです。つまり、Chat Completionエンドポイントを使用してChatGPTにクエリを行う代わりに、以下のようなクエリを行います:

以下の割引データ:{input_data}を与えられた場合、このクエリに答えてください:{user_query}

概念は簡単です。直接質問を投稿する代わりに、まずメソッドは各入力ドキュメント(テキスト、画像、CSV、PDF、またはその他のデータの種類)のためにOpenAI APIを使用してベクトル埋め込みを作成し、生成された埋め込みを高速検索および格納するためのvector databaseにインデックスを作成し、ベクトルデータベースから関連ドキュメントを検索して取得するためにユーザーの質問を活用します。これらのドキュメントは、質問とともにChatGPTに提示されます。この追加のコンテキストにより、ChatGPTは内部データセットでトレーニングされたかのように応答することができます。

一方、PathwayのLLMアプリを使用する場合、ベクトルデータベースを使用する必要はありません。これは、互換性のあるストレージからデータを直接リアルタイムで読み取り、ベクトルドキュメントデータベースをクエリする必要がないため、準備作業やインフラストラクチャ、複雑さの増加などのコストがかかりません。ソースとベクトルを同期させるのは面倒です。また、アンダーラインで示されている入力データが時間の経過とともに変化し、再インデックスが必要な場合にはさらに困難です。

LLMアプリを使用したカスタムデータを使用したChatGPT

以下の簡単な手順は、LLMアプリを使用してデータパイプラインアプローチを説明し、LLMアプリを使用したデータのChatGPTアプリを構築する方法を説明しています。

  1. 収集:アプリは様々なデータソース(CSV、JSON Lines、SQLデータベース、Kafka、Redpanda、Debeziumなど)からデータをリアルタイムで読み込みます(ストリーミングモードが有効になっている場合)。大容量のデータセットをより管理しやすい構造化されたドキュメントスキーマにマッピングします。
  2. 前処理:オプションで、重複するデータ、関係のない情報、ノイズのあるデータを削除し、応答の品質に影響を与える可能性のあるデータフィールドを抽出して簡単なデータクリーニングを行います。また、この段階で、プライバシーデータをマスクしたり非表示にしたりして、ChatGPTに送信されないようにすることもできます。
  3. 埋め込み:各ドキュメントはOpenAI APIで埋め込まれ、埋め込まれた結果を取得します。
  4. インデックス作成:生成された埋め込みに対してリアルタイムでインデックスを作成します。
  5. 検索:APIフレンドリーなインターフェースからのユーザーの質問が与えられた場合、OpenAI APIからクエリの埋め込みを生成します。埋め込みを使用して、クエリに関連するベクトルインデックスをリアルタイムで取得します。
  6. 質問:質問と最も関連のあるセクションをGPTにメッセージとして挿入します。GPTの回答(チャット補完エンドポイント)を返します。

販売のためのChatGPT Python APIの構築

前のセクションでLLMアプリの動作プロセスの概要がわかったら、次の手順に従ってディスカウント検索アプリを構築する方法を理解できます。プロジェクトのソースコードはGitHubで入手できます。アプリをすばやく使用開始する場合は、この部分をスキップし、リポジトリをクローンし、README.mdファイルの指示に従ってコードサンプルを実行することができます。

サンプルプロジェクトの目標

エンタープライズ検索に関するこの記事を参考にして、サンプルアプリは、PythonでHTTP REST APIエンドポイントを公開し、ユーザーのクエリに応えるためにさまざまなソース(CSV、Jsonlines、API、メッセージブローカー、またはデータベース)から最新の取引を取得し、OpenAI APIの埋め込みとチャット補完エンドポイントを活用してAIアシスタントの応答を生成する必要があります。

ステップ1:データ収集(カスタムデータインジェスション)

簡単にするために、任意のJSON Linesをデータソースとして使用できます。アプリはdiscounts.jsonlなどのJSON Linesファイルを使用し、ユーザーのクエリを処理する際にこのデータを使用します。データソースでは、各行にdocオブジェクトがあることを期待しています。最初に入力データをJsonlinesに変換することを忘れないでください。以下に、単一の行を持つJsonlineファイルの例を示します:

{"doc": "{'position': 1, 'link': 'https://www.amazon.com/deal/6123cc9f', 'asin': 'B00QVKOT0U', 'is_lightning_deal': False, 'deal_type': 'DEAL_OF_THE_DAY', 'is_prime_exclusive': False, 'starts_at': '2023-08-15T00:00:01.665Z', 'ends_at': '2023-08-17T14:55:01.665Z', 'type': 'multi_item', 'title': 'Deal on Crocs, DUNLOP REFINED(\u30c0\u30f3\u30ed\u30c3\u30d7\u30ea\u30d5\u30a1\u30a4\u30f3\u30c9)', 'image': 'https://m.media-amazon.com/images/I/41yFkNSlMcL.jpg', 'deal_price_lower': {'value': 35.48, 'currency': 'USD', 'symbol': '$', 'raw': '35.48'}, 'deal_price_upper': {'value': 52.14, 'currency': 'USD', 'symbol': '$', 'raw': '52.14'}, 'deal_price': 35.48, 'list_price_lower': {'value': 49.99, 'currency': 'USD', 'symbol': '$', 'raw': '49.99'}, 'list_price_upper': {'value': 59.99, 'currency': 'USD', 'symbol': '$', 'raw': '59.99'}, 'list_price': {'value': 49.99, 'currency': 'USD', 'symbol': '$', 'raw': '49.99 - 59.99', 'name': 'List Price'}, 'current_price_lower': {'value': 35.48, 'currency': 'USD', 'symbol': '$', 'raw': '35.48'}, 'current_price_upper': {'value': 52.14, 'currency': 'USD', 'symbol': '$', 'raw': '52.14'}, 'current_price': {'value': 35.48, 'currency': 'USD', 'symbol': '$', 'raw': '35.48 - 52.14', 'name': 'Current Price'}, 'merchant_name': 'Amazon Japan', 'free_shipping': False, 'is_prime': False, 'is_map': False, 'deal_id': '6123cc9f', 'seller_id': 'A3GZEOQINOCL0Y', 'description': 'Deal on Crocs, DUNLOP REFINED(\u30c0\u30f3\u30ed\u30c3\u30d7\u30ea\u30d5\u30a1\u30a4\u30f3\u30c9)', 'rating': 4.72, 'ratings_total': 6766, 'page': 1, 'old_price': 49.99, 'currency': 'USD'}"}

クールな部分は、アプリが常にデータフォルダの変更を認識していることです。別のJSON Linesファイルを追加すると、LLMアプリは自動的にAIモデルの応答を更新します。

ステップ2:データの読み込みとマッピング

PathwayのJSON Lines入力コネクタを使用して、ローカルのJSONlinesファイルを読み込み、データエントリをスキーマにマッピングし、Pathwayテーブルを作成します。app.pyでの完全なソースコードを参照してください。

...
sales_data = pw.io.jsonlines.read(
    "./examples/data",
    schema=DataInputSchema,
    mode="streaming"
)

各データ行を構造化されたドキュメントスキーマにマップします。app.pyでの完全なソースコードを参照してください。

class DataInputSchema(pw.Schema):
    doc: str

ステップ3:データの埋め込み

各ドキュメントはOpenAI APIで埋め込まれ、埋め込まれた結果を取得します。embedder.pyでの完全なソースコードを参照してください。

...
embedded_data = embeddings(context=sales_data, data_to_embed=sales_data.doc)

ステップ4:データのインデックス作成

次に、生成された埋め込みに対してインスタントインデックスを構築します。

index = index_embeddings(embedded_data)

ステップ5:ユーザクエリの処理とインデックス作成

RESTエンドポイントを作成し、APIリクエストのペイロードからユーザクエリを取得し、OpenAI APIでユーザクエリを埋め込みます。

...
query, response_writer = pw.io.http.rest_connector(
    host=host,
    port=port,
    schema=QueryInputSchema,
    autocommit_duration_ms=50,
)

embedded_query = embeddings(context=query, data_to_embed=pw.this.query)

ステップ6:類似性検索とプロンプトエンジニアリング

インデックスを使用して類似性検索を実行し、クエリの埋め込みに対して最も関連性の高いマッチを特定します。次に、ユーザのクエリと取得した関連データの結果をマージするプロンプトを構築し、ChatGPTのCompletionエンドポイントにメッセージを送信して適切で詳細な応答を生成します。

responses = prompt(index, embedded_query, pw.this.query)

私たちは、prompt.pyでプロンプトを作成し、ChatGPTに内部知識を追加する際に同じインコンテキスト学習アプローチを取りました。

prompt = f"次の割引データが与えられた場合:\\n {docs_str} \\nこのクエリに回答してください:{query}"

ステップ7:応答の返却

最後のステップは、APIの応答をユーザに返却するだけです。

# Build prompt using indexed data
responses = prompt(index, embedded_query, pw.this.query)

ステップ9:すべてをまとめる

上記のすべてのステップをまとめると、カスタム割引データ用のLLM対応Python APIがapp.pyの実装として準備されます。

import pathway as pw

from common.embedder import embeddings, index_embeddings
from common.prompt import prompt


def run(host, port):
    # APIからのユーザーの質問としてクエリを取得する
    query, response_writer = pw.io.http.rest_connector(
        host=host,
        port=port,
        schema=QueryInputSchema,
        autocommit_duration_ms=50,
    )

    # jsonlinesファイルなどの外部データソースからのリアルタイムデータ
    sales_data = pw.io.jsonlines.read(
        "./examples/data",
        schema=DataInputSchema,
        mode="streaming"
    )

    # OpenAI Embeddings APIを使用して各ドキュメントの埋め込みを計算する
    embedded_data = embeddings(context=sales_data, data_to_embed=sales_data.doc)

    # リアルタイムで生成された埋め込みに対してインデックスを構築する
    index = index_embeddings(embedded_data)

    # OpenAI Embeddings APIからクエリの埋め込みを生成する
    embedded_query = embeddings(context=query, data_to_embed=pw.this.query)

    # インデックスされたデータを使用してプロンプトを構築する
    responses = prompt(index, embedded_query, pw.this.query)

    # プロンプトをChatGPTに送信し、生成された回答を取得する
    response_writer(responses)

    # パイプラインを実行する
    pw.run()


class DataInputSchema(pw.Schema):
    doc: str


class QueryInputSchema(pw.Schema):
    query: str

(オプション) ステップ10: インタラクティブなUIの追加

アプリをよりインタラクティブで使いやすくするために、Streamlitを使用してフロントエンドアプリを構築することができます。このapp.pyファイルで実装を確認してください。

アプリの実行

README.md(前述のリンク)ファイルの「プロジェクトの実行方法」セクションに記載されている手順に従って、割引に関する質問をすることができます。APIは追加した割引データソースに応じて応答します。

UIを使用してGPTにこの知識を与えた後、どのように返答するかをご覧ください:

このアプリは、Rainforest APIとdiscounts.csvファイルの両方のドキュメントを考慮に入れ(これらのソースからデータをリアルタイムでマージします)、クエリの処理時にこのデータを使用します。

さらなる改善点

割引などの特定ドメインの知識をChatGPTに追加することで、LLMアプリのいくつかの機能を発見しました。以下のようなさらなることが可能です:

  • 外部APIからの追加データを組み込むことができます。さらに、Jsonlines、PDF、Doc、HTML、またはテキスト形式などのさまざまなファイル、PostgreSQLやMySQLなどのデータベース、Kafka、Redpanda、またはDebedizumなどのプラットフォームからストリームデータを取得することもできます。
  • 売価の変動を観察するためのデータスナップショットを維持することができます。Pathwayには、2つの変更間の差分を計算する組み込みの機能があります。
  • API経由でデータにアクセスするだけでなく、LLMアプリでは他の下流コネクタ(BIおよび分析ツールなど)に処理済みデータを転送することもできます。たとえば、価格変動を検出するとアラートを受け取るように設定できます。

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more