AI搭載のJavaアプリをAPI Managementで管理する
June 22, 2023
この記事では、OpenAIのChatGPT APIをSpring Bootアプリケーションと統合し、オープンソースのAPIゲートウェイであるApache APISIXを使用してAPIを管理する方法を探求します。この統合により、OpenAIが開発した最先端の言語モデルであるChatGPTの力をSpring Bootアプリケーションで活用できるようになります。また、APISIXはAPIを管理するための堅牢でスケーラブルかつ安全な方法を提供します。
OpenAI ChatGPT API
OpenAIのChatGPT APIは、ChatGPTモデルの機能を独自のアプリケーションやサービスに統合するために使用できる強力なツールです。このAPIを使用すると、一連のメッセージを送信し、REST経由でAIモデルが生成したメッセージを受け取ることができます。このAPIは、チャットボットでのテキスト応答の生成、コード補完、画像生成、または会話型インターフェースでの質問への回答など、さまざまなAPIを提供します。このチュートリアルでは、チャット補完APIを使用して、プロンプトに対する応答を生成します(基本的には何でも質問できます)。チュートリアルを開始する前に、APIキーを使用してAPIに認証する方法や、APIリクエストのパラメータとレスポンスの形式について理解を深めるためにAPIを探索してみてください。
チャット補完APIへのサンプルcURLリクエストは次のようになります。OPENAI_API_KEY
を自分のAPIキーに置き換え、APIを呼び出す際にAuthorizationヘッダーに配置します。
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "What is Apache APISIX?"}]
}'
以下はサンプルのJSONレスポンスです:
{
"id": "chatcmpl-7PtycrYOTJGv4jw8FQPD7LCCw0tOE",
"object": "chat.completion",
"created": 1686407730,
"model": "gpt-3.5-turbo-0301",
"usage": {
"prompt_tokens": 15,
"completion_tokens": 104,
"total_tokens": 119
},
"choices": [
{
"message": {
"role": "assistant",
"content": "Apache APISIXは、マイクロサービスやAPIの管理とルーティングを容易にするために設計された、動的でリアルタイムの高性能APIゲートウェイです。ロードバランシング、レートリミット、認証、認可、トラフィック制御などの機能を提供し、マイクロサービスやAPIの管理を簡素化します。Apache APISIXはNginxサーバー上に構築されており、低遅延と高可用性で高いレベルのトラフィックをサポートできます。オープンソースで、Apache 2.0ライセンスの下でリリースされています。"
},
"finish_reason": "stop",
"index": 0
}
]
}
プロジェクトコード例
このチュートリアルは2つの部分で構成されています。最初の部分では、Spring Bootアプリケーションのセットアップと、チャット補完APIへのAPI呼び出しをプログラムで処理する新しいAPIエンドポイントの作成について説明します。2番目の部分では、APISIXのセキュリティやトラフィック制御などの機能をSpring Boot APIに導入します。このチュートリアルの完全なコード例は、GitHubリポジトリapisix-java-chatgpt-openaiapiで利用できます。
前提条件
開始する前に、以下を確認してください:
- OpenAI APIキーを作成する:OpenAI APIにアクセスするには、APIキーを作成する必要があります。OpenAIのウェブサイトにログインし、APIキー管理ページに移動して作成できます。
- Dockerがマシンにインストールされていること:APISIXとSpring Bootを実行するために必要です。
ステップ1: Spring Bootアプリケーションのセットアップ
まず、新しいSpring Bootアプリケーションをセットアップします。Spring Initializrを使用して、必要な依存関係を含む新しいMavenプロジェクトを生成できます。このチュートリアルでは、Spring Boot Starter Webの依存関係が必要です。ChatGPT APIを統合するために、OpenAI Javaクライアントを使用します。https://github.com/TheoKanning/openai-javaというオープンソースの[コミュニティライブラリ](https://platform.openai.com/docs/libraries/community-libraries)があります。これは、JavaでOpenAIのGPT APIクライアントを作成し呼び出すサービスクラスを提供します。もちろん、OpenAI APIとやり取りする独自の実装をSpringで書くこともできます。他のプログラミング言語のクライアントライブラリも参照してください。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId>
<artifactId>service</artifactId>
<version>0.12.0</version>
</dependency>
</dependencies>
ステップ2: コントローラークラスの作成
ChatCompletionController.javaクラスでは、OpenAIサービスを使用してChatGPT APIにリクエストを送信できます。
import com.theokanning.openai.completion.chat.ChatCompletionChoice;
import com.theokanning.openai.completion.chat.ChatCompletionRequest;
import com.theokanning.openai.completion.chat.ChatMessage;
import com.theokanning.openai.completion.chat.ChatMessageRole;
import com.theokanning.openai.service.OpenAiService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ChatCompletionController {
@Value("${openai.model}")
private String model;
@Value("${openai.api.key}")
private String openaiApiKey;
@PostMapping("/ai-chat")
public String chat(@RequestBody String prompt) {
OpenAiService service = new OpenAiService(openaiApiKey);
final List<ChatMessage> messages = new ArrayList<>();
final ChatMessage systemMessage = new ChatMessage(
ChatMessageRole.USER.value(), prompt);
messages.add(systemMessage);
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest
.builder()
.model(model)
.messages(messages)
.maxTokens(250)
.build();
List<ChatCompletionChoice> choices = service
.createChatCompletion(chatCompletionRequest).getChoices();
if (choices == null || choices.isEmpty()) {
return "No response";
}
return choices.get(0).getMessage().getContent();
}
}
Chat APIエンドポイント/ai-chat
はPOSTリクエストを処理し、チャットリクエストを作成してOpenAI APIに送信します。その後、APIレスポンスの最初のメッセージを返します。
ステップ3: アプリケーションプロパティの定義
次に、APIのプロパティ(model
やAPIキー
など)を*application.properties*ファイルに指定します:
openai.model=gpt-3.5-turbo
openai.api.key=YOUR_OPENAI_API_TOKEN
ステップ4: Spring Bootアプリの実行
これでApplication.javaを実行し、PostmanやcURLコマンドでテストできます。
ご覧の通り、アプリケーションはプロンプトリクエストの本文にある質問に対する応答を生成しました。
ステップ5: Dockerfileの作成
Spring BootアプリケーションをDockerコンテナでラップし、docker-compose.ymlで他のAPISIXコンテナと一緒に使用します。そのために、JARをビルドして実行するためのDockerfileを作成します。Spring BootアプリのDocker化チュートリアルを参照してください。その後、docker compose yamlファイルにサービスを登録します。
openaiapi:
build: openaiapi
ports:
- "8080:8080"
networks:
apisix:
ステップ6: Apache APISIXのセットアップ
APISIXをセットアップするには、docker compose up
コマンドを実行するだけです。なぜなら、docker-compose.ymlですべての必要なサービスを定義しているからです。このファイルでは、APISIX用の1つのコンテナと、前のステップで実装したSpring Bootアプリケーション用の1つのコンテナを定義しています。このサンプルプロジェクトでは、APISIXをスタンドアロンモードで実行します。他にもAPISIXのインストールオプションやデプロイメントモードがあります。これで、APISIXはlocalhost:9080
で、Spring Bootアプリは**localhost:8080
**で実行されています。
ステップ7: APISIXでAPIを保護する
APISIXがセットアップされたら、既存のSpring Boot API /ai-chat
にセキュリティ機能を追加して、許可されたAPIコンシューマーのみがこのAPIにアクセスできるようにします。APISIXは、APIを保護するためのいくつかのプラグインを提供しています。例えば、jwt-authプラグインを使用して、すべてのリクエストにJWTトークンを要求することができます。以下は、apisix.yml
ファイルを使用して、アップストリームとプラグインを含むルートを追加する例です:
upstreams:
- id: 1
type: roundrobin
nodes:
"openaiapi:8080": 1
routes:
- uri: /ask-me-anything
upstream_id: 1
plugins:
proxy-rewrite:
uri: /ai-chat
jwt-auth: {}
- uri: /login
plugins:
public-api:
uri: /apisix/plugin/jwt/sign
consumers:
- username: appsmithuser
plugins:
jwt-auth:
key: appsmithuser@gmail.com
secret: my-secret-key
アップストリーム、ルート、コンシューマーオブジェクトとルーティングルールをAPISIX設定に指定すると、DockerでAPISIXノードサービスが起動した直後に設定ファイルがメモリにロードされます。Apisixは定期的にファイルの内容が更新されたかどうかを検出し、更新があれば自動的に変更をリロードします。
この設定では、1つのアップストリーム、2つのルート、1つのコンシューマーオブジェクトを追加しました。最初のルートでは、/ask-me-anything
(これはカスタムURIパスで、任意のURIを定義できます)へのすべてのリクエストに、ヘッダーにAuthorization: JWT_TOKEN
を含める必要があります。その後、APISIXはproxy-rewriteプラグインの助けを借りて、カスタムURIパスを実際のAPI /ai-chat
に自動的に書き換え、localhost:8080
で実行されているSpring Bootアプリケーションにリクエストを転送します。
APISIXルートにリクエストを送信しようとすると、認証エラーが返されます:
curl -i http://localhost:9080/ask-me-anything -X POST -d '
{
"prompt":"What is Apache APISIX?"
}'
上記のリクエストの結果:
HTTP/1.1 401 Unauthorized
{"message":"Missing JWT token in request"}
2番目のルート設定では、public-apiプラグインを有効にして、新しいエンドポイント/login
を公開し、新しいJWTトークンを署名します。APISIXは、APIコンシューマーやクライアントアプリから新しいトークンを生成および検証するためのアイデンティティプロバイダーとして機能できます。ステップ8で、APIコンシューマーの新しいトークンを要求する方法を説明します。
- uri: /login
plugins:
public-api:
uri: /apisix/plugin/jwt/sign
同じ設定ファイルで、/ask-me-anything
AI搭載APIを使用するAPIコンシューマーを登録し、ユーザーは自分のシークレットを使用してAPISIXにJWTトークンを生成してAPIにアクセスできます:
consumers:
- username: appsmithuser
plugins:
jwt-auth:
key: appsmithuser@gmail.com
secret: my-secret-key
ステップ8: 新しいJWTトークンの要求
これで、既存のAPIコンシューマーのキーを使用して新しいJWTトークンを要求できます:
curl -i http://127.0.0.1:9080/login?key=user-key -i
APISIXから新しいトークンがレスポンスとして返されます:
Server: APISIX/3.0.0
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY4NjU5MjE0NH0.4Kn9c2DBYKthyUx824Ah97-z0Eu2Ul9WGO2WB3IfURA
ステップ9: JWTトークンを使用してAPIにリクエストする
最後に、前のステップで取得したJWTトークンをヘッダーに含めて、API /ask-me-anything
にリクエストを送信できます。
curl -i http://localhost:9080/ask-me-anything -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY4NjU5Mjk4N30.lhom9db3XMkcVd86ScpM6s4eP1_YzR-tfmXPckszsYo' -X POST -d '
{
"prompt":"What is Apache APISIX?"
}'
またはPostmanを使用して、AIのレスポンスを取得できますが、今回はAPISIXゲートウェイを経由してレスポンスが返されます:
結論
このチュートリアルでは、OpenAI ChatGPT APIを使用してプロンプトに対する応答を生成する方法を探求しました。プロンプトに対する応答を生成するためにAPIを呼び出すSpring Bootアプリケーションを作成しました。次に、既存のapisix.ymlファイルを更新して、統合に追加機能を導入できます。また、with-frontendというブランチをチェックアウトして、プロジェクトを実行し、Appsmithを使用して構築されたUIインターフェースをAPISIXと連携させて動作させることができます。