Kong Gateway(OSS)を用いた実践例(1)
先述したユースケースのうち、「API Key、推論パラメータ、プロンプトの中央管理」「統一的なセキュリティ対策」「オブザーバビリティ」の3つについて、Kong Gateway(OSS)を用いて実装する例をご紹介します。ハンズオンの実行には、Docker、 Docker Composeが必要となるため、事前にインストールをお願いします[2]。また、実際にLLM APIを呼び出すため、OpenAIのAPI Keyも必要になります。
Kong Gatewayとは
Kong Gatewayとは、Kong社が提供している API Gateway製品です。Nginx、OpenResty をベースに構築されており、高いパフォーマンスと拡張性を持っています。OSS版と Enterprise版があり、Enterprise版ではOSS版に比べさらに多くの機能が提供されています。
まずは、ハンズオンを実施するための環境を作成します。以下のリポジトリをクローンし、提供されているcompose.yamlを用いて環境を立ち上げます。
# ハンズオン用資材のクローン
git clone https://github.com/shukawam/codezine-ai-gateway-handson.git
# ディレクトリの移動
cd codezine-ai-gateway-handson
# 環境の立ち上げ
docker compose up -d
docker compose up -dコマンドを実行すると、Kong Gatewayのコンテナと状態管理用のPostgreSQLコンテナ、Pythonの実行環境であるJupyter Notebookが起動します。
docker compose ps
実行結果は以下の通りです。
Kong Gatewayからは、いくつかのポートが公開されています。
-
8000:プロキシポートであり、実際のAPIトラフィックはこのポートを通して処理されます -
8001:管理API用のポートであり、Kong Gatewayの設定や管理をAPI経由で行うために使用します(今回は使用しません) -
8002:Kong Managerと呼ばれるWebベースの管理インタフェース用のポートです -
8100:ステータスAPIと呼ばれるKong Gatewayの稼働状況を確認するためのポートです
例えば、ご自身のブラウザでhttp://localhost:8002へアクセスすると、Kong Managerの画面が表示されます。
API Key、推論パラメータ、プロンプトを中央管理する
ご自身のブラウザでPythonの実行環境であるJupyter Notebookにアクセスします。URLは、http://localhost:8080です。
まずは、01_openai.ipynbノートブックを開き、以下のコードを実行します。
import os from openai import OpenAI client = OpenAI( api_key=os.getenv("OPENAI_API_KEY") ) stream = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "あなたは優秀なアシスタントです"}, {"role": "user", "content": "日本で一番高い山はなんですか?"} ], max_tokens=1024, temperature=0.7, stream=True ) for chunk in stream: print(chunk.choices[0].delta.content, end="")
上記のコードは、OpenAI SDKを利用してOpenAIのAPIを直接呼び出す例です。中身を確認してみると、OpenAIのクライアント宣言にAPI Keyが環境変数経由で設定されていることがわかります。モデルを実行するための推論パラメータ(max_tokensやtemperatureなど)もコード内で直接指定がされています。また、プロンプトもコード内で直接指定がされています。これをKong Gatewayを経由した呼び出しにすると以下のよう(02_openai_with_kong_gateway.ipynb)になります。
import os from openai import OpenAI client = OpenAI( api_key="dummy", base_url=os.getenv("GATEWAY_PROXY_ENDPOINT", "http://localhost:8000") + "/chat" ) stream = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "user", "content": "日本で一番高い山はなんですか?"} ], ) for chunk in stream: print(chunk.choices[0].delta.content, end="")
ポイントをいくつか解説します。
一つ目は、環境変数から読み込んでいたOpenAIのAPI Keyにdummyという文字列が設定されている点です。Kong GatewayのレイヤーでAPI Keyを統一的に設定するため、クライアントアプリケーションでは、この値を設定する必要がありません。ただし、OpenAI SDKの仕様上、空文字を設定することができないため、dummyという値を設定しています。
二つ目は、base_urlパラメータにKong Gatewayのプロキシエンドポイントを指定している点です。これにより、OpenAIのAPIを直接呼び出すのではなく、Kong Gatewayを経由して呼び出すことができます。
三つ目は、推論パラメータや一部のプロンプト(system)がコード内から削除されている点です。これらは、Kong Gatewayのレイヤーで設定されるため、クライアントアプリケーションでは指定する必要がありません。
では、これらの設定をKong Gatewayでどのように行うのかを説明します。まずは、Kong Managerの画面を開き、サイドバーからGateway Servicesを選択します。
+ New Gateway Serviceボタンをクリックし、以下のように入力し新しいGateway Service[3]を作成します。
-
Name:
chat-service -
Upstream URL:
https://example.com
[3] Kong Gateway がプロキシするバックエンドサービス(ここでは、OpenAI API)を定義するためのエンティティのこと
ここで、「Upstream URLにOpenAIのエンドポイントを指定していないのはおかしいのでは?」と思われる読者の方もいるかもしれませんが、この後に設定するAI ProxyというプラグインによってUpstream URLは上書きされるため、ここでは入力不備にならないようなダミーのURLを設定しています。次に作成したGateway Serviceの詳細画面から Route[4]を追加します。
[4] Gateway Service に対するルーティングルールを定義するためのエンティティのこと
+ New Routeボタンをクリックし、以下のように入力し新しいRouteを作成します。
-
Name:
chat-route -
Paths:
/chat
この状態で作成した/chatというRouteへアクセスすると、chat-serviceという Gateway Service(https://example.com) へルーティングされます。実際にKong Gateway経由でリクエストを送ってみると以下のようになります。
curl http://localhost:8000/chat
実行結果
<!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
次に、このGateway Serviceに対してAI Proxyというプラグインを追加します。このプラグインは、OpenAI形式のリクエストを受け取り、指定されたLLMプロバイダー(例えば、CohereやGeminiなど)へリクエストを転送する機能を提供します。また、API Keyや推論パラメータについても本プラグインで統一的に設定をすることができます。
サイドバーからPluginsを選択します。
+ New Pluginボタンをクリックし、検索窓でAI Proxyと入力し、表示されたプラグインを選択します。
以下のように入力し、プラグインを設定します。
-
Scope:
Scoped-
Gateway Service:
chat-service
-
Gateway Service:
-
Auth.Header Name:
Authorization -
Auth.Header Value:
Bearer <your-openai-api-key> -
Logging.Log.Payloads:
チェックを入れる -
Logging.Log.Statistics:
チェックを入れる -
Model.Name:
gpt-4o-mini -
Model.Options.Max Tokens:
1024 -
Model.Options.Temperature:
0.7 -
Model.Provider:
openai -
Route Type:
llm/v1/chat
一連の設定によって以下の構成が完成しました。
これで、Kong Gateway経由でOpenAIのAPIを呼び出す準備が整いました。試しに、先ほどと同様に/chatへアクセスしてみると、プラグインの設定前とは異なるレスポンスが返ってくることが確認できます。
curl http://localhost:8000/chat
実行結果は以下の通りです。
{"error":{"message":"request body doesn't contain valid prompts"}}
エラーメッセージの通り、リクエストボディに有効なプロンプトが含まれていないため、OpenAI の API からエラーが返ってきています。有効なプロンプトを含めると以下のようになります。
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "日本で一番高い山はなんですか?"}
]
}'
実行結果は以下の通りです。
{
"id": "chatcmpl-Cs20ZZXdz4ThUJG7Soa7HGEkkoj80",
"object": "chat.completion",
"created": 1766993467,
"model": "gpt-4o-mini-2024-07-18",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "日本で一番高い山は富士山(ふじさん)です。標高は3,776メートルで、静岡県と山梨県の境に位置しています。富士山はその美しい形状と文化的な重要性から、多くの人々に親しまれています。",
"refusal": null,
"annotations": []
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 19,
"completion_tokens": 69,
"total_tokens": 88,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default",
"system_fingerprint": "fp_29330a9688"
}
最後にJupyter Notebookに戻り、02_openai_with_kong_gateway.ipynbのコードを実行してみると、OpenAIのAPIが呼び出され、応答が返ってくることが確認できます。
