API Gateway向けのChatGPTカスタムプラグインの構築

Bobur Umurzokov

Bobur Umurzokov

July 12, 2023

Technology

ChatGPTプラグインは、ChatGPTを外部APIに接続する橋渡しとして機能し、これらのAPIのデータをインテリジェントに利用します。これらのプラグインにより、ChatGPTはスポーツの結果、株式市場データ、最新ニュースなどの最新情報を他のAPIから取得したり、フライトの予約や食事の注文などのアクションをユーザーが実行するのを支援したりするなど、さまざまなタスクを実行できます。一方、API Gatewayは、開発者がAPIを大規模に構築、デプロイ、管理するための強力なツールです。これは、ChatGPTとバックエンドサービスの間のゲートウェイとして機能し、認証、レート制限、リクエスト/レスポンスの変換などの機能を提供します。

前回の投稿では、API GatewayがChatGPTプラグイン開発者にとってどのように役立つか、APIエンドポイントを公開、保護、管理、監視する方法について探りました。この投稿では、API Gateway向けのChatGPTプラグインを開発するための簡単で直接的な方法をステップバイステップでガイドします。おまけとして、プラグインをChatGPTに追加して試す方法も学べます。それでは、リラックスして、この旅に出発しましょう!

API Gateway向けChatGPTプラグインの作成方法

OpenAIウェブサイトのはじめにガイドに記載されているように、新しいカスタムChatGPTプラグインを構築するには、次の一般的な3つのステップに従う必要があります:

  1. OpenAPI仕様を実装したAPIを開発するか、既存のAPIを使用します。
  2. OpenAPI YAMLまたはJSON形式でAPIをドキュメント化します。
  3. プラグインに関する重要な情報を含むJSONプラグインマニフェストファイルを生成します。

上記のステップに従って、バックエンドAPIサービスのAPI Gatewayとして機能するカスタムプラグインをChatGPT向けに構築します。例として、ChatGPTユーザーインターフェースで、ユーザーが既存のConference APIの前にAPI Gatewayを導入して、スピーカーのセッションやトピックの詳細を取得したい場合、プラグインはチャットでコマンドを受け取り、ユーザーのリクエストをApache APISIXのAdmin APIに転送し、ユーザーが指定した入力構成でRouteを作成します。これは、Chatbotを使用してAPI Gatewayの機能を設定する別のアプローチです。以下のサンプル出力を参照してください:

Chatbotを使用してAPI Gatewayの機能を設定

コマンドが正常に実行されると、APISIXはルートを作成し、ConferenceバックエンドAPIのUpstreamを登録します。これにより、API GatewayのドメインとURLパスにアクセスして、Gateway経由でレスポンスを取得できます。たとえば、http://localhost:9080/speaker/1/sessionsエンドポイントへのGETリクエストは、Conference APIからスピーカーのすべてのセッションを返します。また、ChatGPTに直接問い合わせることで、すべてのルートを取得する、IDでルートを取得する、既存のルートを更新する、プラグインとアップストリームを使用してルートを作成するなどの基本的な操作も実行できます。

さまざまなコンポーネント間のデータフローを理解するために、提供されたアーキテクチャ図を参照してください:

前提条件

完全なAPI Gatewayプラグインのコードリポジトリはこちらにあります。コードスニペット、ファイルを含むステップを1つずつ見ていき、API Gatewayの設定、OpenAPI定義でのAPIのドキュメント化、プラグインマニフェストファイルの作成方法を理解しましょう。

このプラグインの開発に使用された技術スタックは以下の通りです:

  1. 既存の公開Conference APIで、デモではスピーカーのセッショントピック情報を取得するために2つのAPIエンドポイントを使用します。ブラウザで他のAPIを発見することもできます。
  2. Apache APISIX API Gatewayを使用して、Admin APIを公開し、APIトラフィックを管理します。
  3. Pythonスクリプトを使用してプラグインを実行し、プラグインマニフェスト、OpenAPI仕様、プラグインロゴファイルをローカルホストURL http://localhost:5000/ でホストします。
  4. プロジェクトでは、Dockerを使用して、APISIX、etcd、およびPythonスクリプトを単一のdocker compose upコマンドでビルド、デプロイ、実行します。

プラグインを作成するために、一連のステップを実行します。パート1では、APISIXの設定に焦点を当てます。パート2では、ChatGPTプラグイン自体の開発を行い、パート3では、プラグインをChatGPTに接続してテストします。ステップは順番に提示されていますが、内容に慣れている場合は任意のステップをスキップしても構いません。

パート1: Apache APISIXの設定

ステップ1: APISIX設定の定義

まず、APISIX設定ファイルを作成します。APISIXの設定は、通常YAMLで記述される静的設定ファイルを含むさまざまな方法で定義できます。apisix.ymlファイルに、設定例を提供しています:

deployment:
  etcd:
    host:
      - "http://etcd:2397"
  admin:
    admin_key_required: false
    allow_admin:
      - 0.0.0.0/0

上記のapisix.ymlファイルが何を意味するかは、ChatGPTに相談することもできます。基本的に、この設定はAPISIXのデプロイメントモードを定義しています。ここでは、APISIXがAdmin APIから取得した設定詳細をetcdストレージに保存する従来のオプションを使用しています。また、デモのためにAdminキーadmin_key_requiredを無効にしています。

ステップ2: Docker ComposeにAPISIXとetcdを登録

最後のステップでは、docker-compose.ymlファイルを作成し、APISIXとetcdをサービスとして登録してビルド、デプロイ、実行します。APISIX Admin APIはポート9180で利用可能で、Gatewayはポート9080でアクセスできます。

version: "3"

services:
  apisix:
    image: apache/apisix:3.3.0-debian
    volumes:
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
    restart: always
    ports:
      - "9080:9080"
      - "9180:9180"
    depends_on:
      - etcd
  etcd:
    image: bitnami/etcd:3.5.9
    environment:
      ETCD_ENABLE_V2: "true"
      ALLOW_NONE_AUTHENTICATION: "yes"
      ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2397"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2397"

パート2: ChatGPTプラグインの開発

ステップ1: プラグインマニフェストの作成

すべてのプラグインには、プラグインの名前、説明、ロゴアセットなどの重要な情報を提供するai-plugin.jsonマニフェストファイルが必要です。各マニフェストファイルのフィールドについて詳しくはこちらを参照し、OpenAIはモデル説明(description_for_model)を作成するためのベストプラクティスも提供しています。ChatGPT UIにプラグインをインストールすると、インターフェースはドメイン(http://localhost:5000/.well-known/ai-plugin.json)でマニフェストファイルを探します。これにより、ChatGPTはプラグインとの対話方法を理解します。

ai-plugin.jsonという新しいファイルを作成し、次のコードを貼り付けます:

{
    "schema_version": "v1",
    "name_for_human": "APISIX plugin for ChatGPT",
    "name_for_model": "apigatewayplugin",
    "description_for_human": "API Gateway plugin to manage your backend APIs.",
    "description_for_model": "Create, retrive, manage APISIX routes, upstreams, and plugins",
    "auth": {
        "type": "none"
    },
    "api": {
        "type": "openapi",
        "url": "http://localhost:5000/openapi.yaml"
    },
    "logo_url": "http://localhost:5000/logo.png",
    "contact_email": "support@example.com",
    "legal_info_url": "http://www.example.com/legal"
}

ファイルには、http://localhost:5000/openapi.yamlファイルへのURLも指定されています。

ユーザーがChatGPTと対話すると、ChatGPTはopenapi.yamlファイルを参照してエンドポイントの説明を理解します。この情報に基づいて、ChatGPTはユーザーのプロンプトに応じて最も適切なエンドポイントを利用することを決定します。

ステップ2: OpenAPI仕様の作成

OpenAPI仕様は、REST APIを記述するための標準です。プラグインがモデルと通信するために使用する各APIエンドポイントを指定するために使用されます。詳細はこちらを参照してください。openapi.yamlファイルの例を以下に示します:

openapi: 3.1.0
info:
  title: APISIX Admin API
  description: >-
    APISIX Admin API is a RESTful API that allows you to create and manage
    APISIX resources.
  version: 3.3.0
servers:
  - url: http://localhost:5000
    description: Dev Environment
tags:
  - name: Route
    description: |-
      A route defines a path to one or more upstream services.
      See [Routes](/apisix/key-concepts/routes) for more information.

paths:
  /apisix/admin/routes:
    get:
      operationId: getAllRoutes
      summary: Get All Routes
      deprecated: false
      description: Get all configured routes.
      tags:
        - Route
...
# GitHubリポジトリで完全版を参照

上記のOpenAPI仕様は、実際のAdmin APIスキーマからの抜粋であり、必要に応じてさらにAPIスキーマを追加できます。プラグインデモでは、ルート関連のパスのみを使用しました。

ステップ3: プラグインの静的ファイルのエンドポイントを追加(ローカルホストの場合)

次に、FlaskアプリをPythonで作成し、プラグインのロゴマニフェストOpenAPI仕様をエンドポイントとして公開します。ChatGPTはAPIエンドポイントを呼び出して、カスタムプラグインに必要なすべての情報を取得します:

import requests
import os

import yaml
from flask import Flask, jsonify, request, send_from_directory
from flask_cors import CORS

app = Flask(__name__)

PORT = 5000

# 注意:CORSを設定してchat.openapi.comを許可することは、ChatGPTがプラグインにアクセスするために必要です
CORS(app, origins=[f"http://localhost:{PORT}", "https://chat.openai.com"])

api_url = 'http://apisix:9180'

@app.route('/.well-known/ai-plugin.json')
def serve_manifest():
    return send_from_directory(os.path.dirname(__file__), 'ai-plugin.json')

@app.route('/openapi.yaml')
def serve_openapi_yaml():
    with open(os.path.join(os.path.dirname(__file__), 'openapi.yaml'), 'r') as f:
        yaml_data = f.read()
    yaml_data = yaml.load(yaml_data, Loader=yaml.FullLoader)
    return jsonify(yaml_data)

@app.route('/logo.png')
def serve_openapi_json():
    return send_from_directory(os.path.dirname(__file__), 'logo.png')

# ChatGPTからAPI Gatewayへのリクエストをプロキシする
@app.route('/<path:path>', methods=['GET', 'POST'])
def wrapper(path):

    headers = {
    'Content-Type': 'application/json',
    }

    url = f'{api_url}/{path}'
    print(f'Forwarding call: {request.method} {path} -> {url}')

    if request.method == 'GET':
        response = requests.get(url, headers=headers, params=request.args)
    elif request.method in ['POST', 'DELETE', 'PATCH', 'PUT']:
        print(request.headers)
        response = requests.post(url, headers=headers, params=request.args, json=request.json)
    else:
        raise NotImplementedError(f'Method {request.method} not implemented in wrapper for {path=}')
    return response.content

if __name__ == '__main__':
    app.run(debug=True,host='0.0.0.0')

スクリプトが実行されると、APIドメインでファイルにアクセスできます:

  1. ai-plugin.jsonはURIパスhttp://localhost:5000/.well-known/ai-plugin.jsonで利用可能です。
  2. openapi.yamlはURIパスhttp://localhost:5000/openapi.yamlでアクセス可能です。
  3. logo.pngはURIパスhttp://localhost:5000/logo.pngで利用可能です。

上記のコードでCORSを有効にしたのは、ローカルでデプロイされたプラグインをChatGPTインターフェースでテストするためです。プラグインがリモートサーバーで実行されている場合、プロキシ部分は必要ありません。プラグインをリモートで実行する方法については、OpenAIドキュメントを参照してください。

ステップ4: PythonアプリをDocker化

PythonアプリをDockerで自動的に実行するために、Dockerfileを作成し、docker-compose.ymlファイルに登録します。PythonアプリをDocker化する方法についてはこちらを参照してください。

FROM python:3.9
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD ["python","main.py"]

最終的に、docker-compose.ymlファイルは次のようになります:

version: "3"

services:
  apisix:
    image: apache/apisix:3.3.0-debian
    volumes:
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
    restart: always
    ports:
      - "9080:9080"
      - "9180:9180"
    depends_on:
      - etcd
  
  etcd:
    image: bitnami/etcd:3.5.9
    environment:
      ETCD_ENABLE_V2: "true"
      ALLOW_NONE_AUTHENTICATION: "yes"
      ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2397"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2397"
  
  chatgpt-config:
    build: chatgpt-plugin-config
    ports:
      - '5000:5000'

パート3: ChatGPTにカスタムプラグインを統合

ステップ1: カスタムプラグインをデプロイ

カスタムプラグインの開発が完了したら、ローカルでデプロイして実行します。プロジェクトを開始するには、プロジェクトのルートディレクトリから次のコマンドを実行します:

docker compose up

プロジェクトを開始すると、Dockerは必要なイメージをダウンロードします。APISIX、etcd、およびPythonアプリ(chatgpt-config)サービスが実行されていることがわかります。

カスタムプラグインをデプロイ

ステップ2: カスタムプラグインをChatGPTインターフェースに接続

ChatGPTプラグインをデプロイし、プラグイン設定ファイルがAPI経由でアクセス可能になったので、テストする準備が整いました。Plusアカウントをお持ちの場合、GPT-4でプラグインを有効にする必要があります。設定に移動し、ベータオプションをクリックして「プラグインを有効にする」をクリックします。次に、ChatGPTの上部にあるプラグインポップバーをクリックし、「プラグインストア」に移動して「独自のプラグインを開発」を選択します。プラグインのローカルホストURL(localhost:5000)を提供します。

カスタムプラグインをChatGPTインターフェースに接続

「マニフェストファイルを検索」をクリックすると、すべてが正しく設定されている場合、ChatGPTがマニフェストとOpenAPI仕様ファイルを正常に検証することがわかります。

マニフェストファイルを検索

ステップ3: カスタムプラグインをテスト

これでプラグインがChatGPTインターフェースに接続されたので、簡単なコマンドを書くことができます:

すべてのルートを表示

APISIXにルートがないため、新しいルートを作成できます。ここでは、プロンプトで使用される言語に応じて、ChatGPTが適切なAPISIXエンドポイントを呼び出すことを選択します。詳細なコマンドを書いて、ChatGPTが正しくルートを作成できるようにしてください。

APISIXにルートを作成

ルートが作成されたので、GatewayエンドポイントにアクセスしてConferenceセッションの詳細を取得できます:http://localhost:9080/speaker/1/sessions。このConference APIを自分のバックエンドAPIに置き換えることもできます。

API Gatewayカスタムプラグインのその他のユースケース

ここで質問が浮かぶかもしれません:このプラグインでリクエストをルーティングする以外に何ができるのか? APISIXがAdmin API経由で提供する多くの機能を改善または追加することができます。Conference APIの前にAPI Gatewayを配置し、API Gatewayがプラグインからのすべてのリクエストを最初に処理するため、少なくとも以下のことが実現できます:

  • セキュリティ: Conference APIを保護したい場合、API Gatewayがない場合でも、OpenAIのプラグイン認証メソッドを使用して、ChatGPT UIとプラグイン間のデータ交換を保護できます。ただし、プラグインとバックエンドサービスの間の通信は、Pythonコードに何らかの横断的懸念を実装するまで保護されません。代わりに、API Gatewayを使用して認証、認可、レート制限などのセキュリティ対策を実装し、Conference APIを不正アクセスや潜在的な攻撃から保護できます。ChatGPTはAPI Gatewayと自由に通信できますが、API Gatewayとバックエンドサービスの間の通信は完全に安全です。
  • キャッシュ: 類似のConference APIレスポンスをキャッシュして、ChatGPTに迅速にデータを表示できます。
  • バージョニング: Conference APIの第2バージョンを作成して、設定やダウンタイムなしでChatGPTプラグインリクエストを最新のサービスにルーティングできます。
  • 負荷分散: 複数のConference APIインスタンスに着信リクエストを分散し、高可用性と効率的なリソース利用を確保できます。
  • リクエスト変換: Conference APIへのリクエストを変更し、データ変換、検証、またはRESTからGraphQLへのリクエスト変換、gRPCサービス呼び出しを可能にします。
  • 監視と分析: API Gatewayは堅牢な監視と分析プラグインを提供し、APIの使用状況、パフォーマンス、潜在的な問題に関する貴重な洞察を収集できます。

Apache APISIX API GatewayをChatGPTカスタムプラグインとバックエンドAPI間の通信のフロントドアとして使用したい場合は、このリポジトリChatGPTカスタムプラグインとバックエンドAPI間のAPI Gatewayをチェックしてください。

次のステップ

この投稿を通じて、基本的な機能を持つAPI Gateway向けのカスタムプラグインを作成する方法を学びました。サンプルプロジェクトを基盤として、openapi.yamlファイルにさらにAPISIX Admin API仕様を追加して、他のプラグインを使用およびテストし、API コンシューマーなどを追加することで、機能を改善できます。GitHubプロジェクトにプルリクエストを送信して貢献してください。

関連リソース

Tags: