次の方法で共有


チュートリアル: Azure App Service と Azure OpenAI (Spring Boot) を使用してチャットボットを構築する

このチュートリアルでは、Azure OpenAI と Java Spring Boot アプリケーションを統合し、それを Azure App Service にデプロイすることで、インテリジェントな AI アプリケーションを構築します。 Azure OpenAI にクエリを送信し、応答をブラウザーに送信する Spring Boot コントローラーを作成します。

ヒント

このチュートリアルでは Spring Boot を使用しますが、Azure OpenAI を使用してチャット アプリケーションを構築する主要な概念は、任意の Java Web アプリケーションに適用されます。 Tomcat や JBoss EAP など、App Service で別のホスティング オプションを使用している場合は、ここで示す認証パターンと Azure SDK の使用を好みのフレームワークに合わせて調整できます。

Azure App Service で実行されているチャットボットを示すスクリーンショット。

このチュートリアルでは、以下の内容を学習します。

  • Azure OpenAI リソースを作成し、言語モデルをデプロイします。
  • Azure OpenAI に接続する Spring Boot アプリケーションを構築します。
  • 依存関係の挿入を使用して、Azure OpenAI クライアントを構成します。
  • アプリケーションを Azure App Service にデプロイします。
  • 開発環境と Azure の両方で、パスワードレスのセキュリティで保護された認証を実装します。

[前提条件]

  • アクティブなサブスクリプションを持つ Azure アカウント
  • GitHub Codespaces を使用するための GitHub アカウント

1. Azure OpenAI リソースを作成する

このセクションでは、GitHub Codespaces を使用して、Azure CLI を使用して Azure OpenAI リソースを作成します。

  1. GitHub Codespaces に移動し、GitHub アカウントでサインインします。

  2. GitHub で のテンプレートを見つけて、[ このテンプレートを使用して 新しい空の Codespace を作成する] を選択します。

  3. Codespace ターミナルで、Azure CLI をインストールします。

    curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
    
  4. Azure アカウントにサインインします。

    az login
    

    ターミナルの指示に従って認証します。

  5. リソース グループ名、Azure OpenAI サービス名、および場所の環境変数を設定します。

    export RESOURCE_GROUP="<group-name>"
    export OPENAI_SERVICE_NAME="<azure-openai-name>"
    export APPSERVICE_NAME="<app-name>"
    export LOCATION="eastus2"
    

    Von Bedeutung

    リージョンは、選択したモデルのリージョンの可用性に関連付けられているため、重要です。 モデルの可用性と デプロイの種類の可用性 は、リージョンによって異なります。 このチュートリアルでは、 gpt-4o-miniを使用します。これは、標準の展開の種類の eastus2 で使用できます。 別のリージョンにデプロイする場合、このモデルは使用できないか、別のレベルが必要な場合があります。 リージョンを変更する前に、 モデルの概要テーブルとリージョンの可用性 を参照して、希望するリージョンでのモデルのサポートを確認してください。

  6. カスタム ドメインを使用してリソース グループと Azure OpenAI リソースを作成し、gpt-4o-mini モデルを追加します。

    # Resource group
    az group create --name $RESOURCE_GROUP --location $LOCATION
    # Azure OpenAI resource
    az cognitiveservices account create \
      --name $OPENAI_SERVICE_NAME \
      --resource-group $RESOURCE_GROUP \
      --location $LOCATION \
      --custom-domain $OPENAI_SERVICE_NAME \
      --kind OpenAI \
      --sku s0
    # gpt-4o-mini model
    az cognitiveservices account deployment create \
      --name $OPENAI_SERVICE_NAME \
      --resource-group $RESOURCE_GROUP \
      --deployment-name gpt-4o-mini \
      --model-name gpt-4o-mini \
      --model-version 2024-07-18 \
      --model-format OpenAI \
      --sku-name Standard \
      --sku-capacity 1
    # Cognitive Services OpenAI User role that lets the signed in Azure user to read models from Azure OpenAI
    az role assignment create \
      --assignee $(az ad signed-in-user show --query id -o tsv) \
      --role "Cognitive Services OpenAI User" \
      --scope /subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/$OPENAI_SERVICE_NAME
    

Azure OpenAI リソースが作成されたので、それを操作する Web アプリケーションを作成します。

2. Spring Boot Web アプリを作成して設定する

  1. Codespace ターミナルで、Spring Boot REST サンプルをワークスペースに複製し、初めて実行してみてください。

    git clone https://github.com/rd-1-2022/rest-service .
    mvn spring-boot:run
    

    GitHub Codespaces に、アプリが特定のポートで使用可能であることを示す通知が表示されます。 [ ブラウザーで開く ] を選択して、新しいブラウザー タブでアプリを起動します。白いラベルのエラー ページが表示されたら、Spring Boot アプリが動作しています。

  2. Codespace ターミナルに戻り、Ctrl + C キーを押してアプリを停止します。

  3. pom.xml を開き、次の依存関係を追加します。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-ai-openai</artifactId>
        <version>1.0.0-beta.16</version>
    </dependency>
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-core</artifactId>
        <version>1.55.3</version>
    </dependency>
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-identity</artifactId>
        <version>1.16.0</version>
        <scope>compile</scope>
    </dependency>
    
  4. Application.javaと同じディレクトリ (src/main/java/com/example/restservice) に 、ChatController.java という名前の Java ファイルを追加し、次の内容をコピーします。

    package com.example.restservice;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import com.azure.ai.openai.OpenAIAsyncClient;
    import com.azure.ai.openai.models.ChatChoice;
    import com.azure.ai.openai.models.ChatCompletionsOptions;
    import com.azure.ai.openai.models.ChatRequestMessage;
    import com.azure.ai.openai.models.ChatRequestUserMessage;
    import com.azure.ai.openai.models.ChatResponseMessage;
    import com.azure.core.credential.TokenCredential;
    import com.azure.identity.DefaultAzureCredentialBuilder;
    
    @Configuration
    class AzureConfig {
        // Reads the endpoint from environment variable AZURE_OPENAI_ENDPOINT
        @Value("${azure.openai.endpoint}")
        private String openAiEndpoint;
    
        // Provides a credential for local dev and production
        @Bean
        public TokenCredential tokenCredential() {
            return new DefaultAzureCredentialBuilder().build();
        }
    
        // Configures the OpenAIAsyncClient bean
        @Bean
        public OpenAIAsyncClient openAIClient(TokenCredential tokenCredential) {
            return new com.azure.ai.openai.OpenAIClientBuilder()
                    .endpoint(openAiEndpoint)
                    .credential(tokenCredential)
                    .buildAsyncClient();
        }
    }
    
    @Controller
    public class ChatController {
        private final OpenAIAsyncClient openAIClient;
    
        // Inject the OpenAIAsyncClient bean
        public ChatController(OpenAIAsyncClient openAIClient) {
            this.openAIClient = openAIClient;
        }
    
        @RequestMapping(value = "/", method = RequestMethod.GET)
        public String chatFormOrWithMessage(Model model, @RequestParam(value = "userMessage", required = false) String userMessage) {
            String aiResponse = null;
            if (userMessage != null && !userMessage.isBlank()) {
    
                // Create a list of chat messages
                List<ChatRequestMessage> chatMessages = new ArrayList<>();
                chatMessages.add(new ChatRequestUserMessage(userMessage));
    
                // Send the chat completion request
                String deploymentName = "gpt-4o-mini";
                StringBuilder serverResponse = new StringBuilder();
                var chatCompletions = openAIClient.getChatCompletions(
                    deploymentName, 
                    new ChatCompletionsOptions(chatMessages)
                ).block();
                if (chatCompletions != null) {
                    for (ChatChoice choice : chatCompletions.getChoices()) {
                        ChatResponseMessage message = choice.getMessage();
                        serverResponse.append(message.getContent());
                    }
                }
                aiResponse = serverResponse.toString();
            }
            model.addAttribute("aiResponse", aiResponse);
            return "chat";
        }
    }
    

    ヒント

    このチュートリアルのファイルを最小限に抑えるために、このコードでは Spring @Configuration クラスと @Controller クラスを 1 つのファイルに結合します。 運用環境では、通常、保守容易性のために構成とビジネス ロジックを分離します。

  5. src/main/resourcesテンプレート ディレクトリを作成し、チャット インターフェイスの次のコンテンツを含む chat.html を追加します。

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Azure OpenAI Chat</title>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    </head>
    <body>
    <div class="container py-4">
        <h2 class="mb-4">Azure OpenAI Chat</h2>
        <form action="/" method="get" class="d-flex mb-3">
            <input name="userMessage" class="form-control me-2" type="text" placeholder="Type your message..." autocomplete="off" required />
            <button class="btn btn-primary" type="submit">Send</button>
        </form>
        <div class="mb-3">
            <div th:if="${aiResponse}" class="alert alert-info">AI: <span th:text="${aiResponse}"></span></div>
        </div>
    </div>
    </body>
    </html>
    
  6. ターミナルで、OpenAI エンドポイントを取得します。

    az cognitiveservices account show \
      --name $OPENAI_SERVICE_NAME \
      --resource-group $RESOURCE_GROUP \
      --query properties.endpoint \
      --output tsv
    
  7. CLI 出力から値を含む AZURE_OPENAI_ENDPOINT を追加して、アプリをもう一度実行します。

    AZURE_OPENAI_ENDPOINT=<output-from-previous-cli-command> mvn spring-boot:run
    
  8. [ ブラウザーで開く ] を選択して、新しいブラウザー タブでアプリを起動します。

  9. テキスト ボックスにメッセージを入力し、[送信] を選択し、アプリに数秒待って Azure OpenAI からのメッセージに返信します。

アプリケーションは DefaultAzureCredential を使用します。このアプリケーションでは、トークン認証に Azure CLI サインイン ユーザーが自動的に使用されます。 このチュートリアルの後半では、Web アプリを Azure App Service にデプロイし、マネージド ID を使用して Azure OpenAI リソースに安全に接続するように構成します。 コード内の同じ DefaultAzureCredential がマネージド ID を検出し、認証に使用できます。 追加のコードは必要ありません。

3. Azure App Service にデプロイし、OpenAI 接続を構成する

アプリがローカルで動作したので、それを Azure App Service にデプロイし、マネージド ID を使用して Azure OpenAI へのサービス接続を設定しましょう。

  1. Maven を使用してデプロイ パッケージを作成します。

    mvn clean package
    
  2. まず、Azure CLI コマンド az webapp upを使用して、アプリを Azure App Service にデプロイします。 このコマンドを実行すると、新しい Web アプリが作成され、コードがデプロイされます。

    az webapp up \
      --resource-group $RESOURCE_GROUP \
      --location $LOCATION \
      --name $APPSERVICE_NAME \
      --plan $APPSERVICE_NAME \
      --sku B1 \
      --runtime "JAVA:21" \
      --os-type Linux \
      --track-status false
    

    このコマンドは、完了するまで数分かかることがあります。 OpenAI リソースと同じリソース グループに新しい Web アプリが作成されます。

  3. アプリがデプロイされたら、マネージド ID を使用して、Web アプリと Azure OpenAI リソースの間にサービス接続を作成します。

    az webapp connection create cognitiveservices \
      --resource-group $RESOURCE_GROUP \
      --name $APPSERVICE_NAME \
      --target-resource-group $RESOURCE_GROUP \
      --account $OPENAI_SERVICE_NAME \
      --system-identity
    

    このコマンドは、次の方法で Web アプリと Azure OpenAI リソース間の接続を作成します。

    • Web アプリのシステム割り当てマネージド ID の生成。
    • Azure OpenAI リソースのマネージド ID に Cognitive Services OpenAI 共同作成者ロールを追加します。
    • AZURE_OPENAI_ENDPOINT アプリ設定を Web アプリに追加する。
  4. デプロイされた Web アプリをブラウザーで開きます。

    az webapp browse
    
  5. テキスト ボックスにメッセージを入力し、[送信] を選択し、アプリに数秒待って Azure OpenAI からのメッセージに返信します。

    Azure App Service で実行されているチャットボットを示すスクリーンショット。

これで、アプリがデプロイされ、マネージド ID を使用して Azure OpenAI に接続されました。 @ConfigurationAZURE_OPENAI_ENDPOINT使用して アプリ設定にアクセスすることに注意してください。

よく寄せられる質問

サンプルで OpenAI クライアントに @Configuration と Spring Bean を使用する理由

OpenAIAsyncClientに Spring Bean を使用すると、次のことが保証されます。

  • すべての構成プロパティ (エンドポイントなど) が Spring によって読み込まれ、挿入されます。
  • 資格情報とクライアントは、アプリケーション コンテキストが完全に初期化された後に作成されます。
  • 依存関係の挿入が使用されます。これは、Spring アプリケーションの標準的で最も堅牢なパターンです。

非同期クライアントは、特に Azure CLI 認証で DefaultAzureCredential を使用する場合に、より堅牢です。 同期 OpenAIClient では、一部のローカル開発シナリオでトークンの取得に関する問題が発生する可能性があります。 非同期クライアントを使用すると、これらの問題が回避され、推奨される方法です。


Azure OpenAI ではなく OpenAI に接続する場合はどうすればよいですか?

代わりに OpenAI に接続するには、次のコードを使用します。

OpenAIClient client = new OpenAIClientBuilder()
    .credential(new KeyCredential(<openai-api-key>))
    .buildClient();

詳細については、「 OpenAI API 認証」を参照してください。

App Service で接続シークレットを操作する場合は、コードベースにシークレットを直接格納するのではなく、 Key Vault 参照 を使用する必要があります。 これにより、機密情報は安全なままであり、一元的に管理されます。


代わりに API キーを使用して Azure OpenAI に接続できますか?

はい。マネージド ID ではなく API キーを使用して Azure OpenAI に接続できます。 このアプローチは、Azure OpenAI SDK とセマンティック カーネルでサポートされています。

App Service で接続シークレットを操作する場合は、コードベースにシークレットを直接格納するのではなく、 Key Vault 参照 を使用する必要があります。 これにより、機密情報は安全なままであり、一元的に管理されます。


このチュートリアルでは DefaultAzureCredential はどのように機能しますか?

DefaultAzureCredentialは、使用可能な最適な認証方法を自動的に選択することで認証を簡略化します。

  • ローカル開発中: az loginを実行すると、ローカルの Azure CLI 資格情報が使用されます。
  • Azure App Service にデプロイする場合: アプリのマネージド ID を使用して、セキュリティで保護されたパスワードレス認証を行います。

この方法により、ローカル環境とクラウド環境の両方でコードを変更することなく、安全かつシームレスに実行できます。

次のステップ