Поделиться через


Руководство. Создание чат-бота с помощью Службы приложений Azure и Azure OpenAI (Spring Boot)

В этом руководстве вы создадите интеллектуальное приложение ИИ, интегрируя Azure OpenAI с приложением Java Spring Boot и развертывая его в Службе приложений Azure. Вы создадите контроллер Spring Boot, который отправляет запрос в Azure OpenAI и отправляет ответ в браузер.

Подсказка

Хотя в этом руководстве используется Spring Boot, основные понятия создания приложения чата с помощью Azure OpenAI применяются к любому веб-приложению Java. Если вы используете другой вариант размещения в службе приложений, например Tomcat или JBoss EAP, вы можете адаптировать шаблоны проверки подлинности и использование пакета SDK Azure, показанные здесь, в предпочитаемой платформе.

Снимок экрана: чат-бот, работающий в Службе приложений Azure.

В этом руководстве вы узнаете, как:

  • Создайте ресурс Azure OpenAI и разверните языковую модель.
  • Создайте приложение Spring Boot, которое подключается к Azure OpenAI.
  • Используйте внедрение зависимостей для настройки клиента Azure OpenAI.
  • Разверните приложение в Службе приложений Azure.
  • Реализуйте безопасную проверку подлинности без пароля как в среде разработки, так и в Azure.

Предпосылки

1. Создание ресурса Azure OpenAI

В этом разделе вы будете использовать GitHub Codespaces для создания ресурса Azure OpenAI с помощью Azure CLI.

  1. Перейдите в GitHub Codespaces и войдите с помощью учетной записи GitHub.

  2. Найдите пустой шаблон GitHub и выберите "Использовать этот шаблон ", чтобы создать пустое пространство кода.

  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"
    

    Это важно

    Регион имеет решающее значение, так как он привязан к региональной доступности выбранной модели. Доступность модели и доступность типов развертывания зависят от региона к региону. В этом руководстве используется 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, вы создадите веб-приложение для взаимодействия с ним.

2. Создание и настройка веб-приложения Spring Boot

  1. В терминале Codespace клонируйте пример REST Spring Boot в рабочую область и попробуйте запустить его в первый раз.

    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), добавьте файл Java с именем ChatController.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 классы в одном файле. В рабочей среде обычно можно разделить конфигурацию и бизнес-логику для обеспечения удобства обслуживания.

  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. Запустите приложение еще раз, добавив AZURE_OPENAI_ENDPOINT со значением из вывода командной строки (CLI):

    AZURE_OPENAI_ENDPOINT=<output-from-previous-cli-command> mvn spring-boot:run
    
  8. Нажмите кнопку "Открыть в браузере ", чтобы запустить приложение на новой вкладке браузера.

  9. Введите сообщение в текстовое поле и нажмите кнопку "Отправить и дать приложению несколько секунд ответить с сообщением из Azure OpenAI.

Приложение использует DefaultAzureCredential, которое автоматически использует azure CLI, выполнившего вход пользователя для проверки подлинности маркера. Далее в этом руководстве вы развернете веб-приложение в Службе приложений Azure и настройте его для безопасного подключения к ресурсу Azure OpenAI с помощью управляемого удостоверения. То же самое DefaultAzureCredential в вашем коде может обнаружить управляемое удостоверение и использовать его для аутентификации. Дополнительный код не требуется.

3. Развертывание в Службе приложений Azure и настройка подключения OpenAI

Теперь, когда приложение работает локально, давайте развернем его в Службе приложений Azure и настроим подключение службы к Azure OpenAI с помощью управляемого удостоверения.

  1. Создайте пакет развертывания с помощью Maven.

    mvn clean package
    
  2. Сначала разверните приложение в Службе приложений Azure с помощью команды az webapp upAzure CLI. Эта команда создает веб-приложение и развертывает код в нем:

    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.

  3. После развертывания приложения создайте подключение службы между веб-приложением и ресурсом 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
    

    Эта команда создает подключение между веб-приложением и ресурсом Azure OpenAI, выполнив следующие действия.

    • Создание системного управляемого удостоверения для веб-приложения.
    • Добавление роли участника Cognitive Services OpenAI для управляемого удостоверения ресурса Azure OpenAI.
    • Добавление настройки приложения AZURE_OPENAI_ENDPOINT в ваше веб-приложение.
  4. Откройте развернутое веб-приложение в браузере.

    az webapp browse
    
  5. Введите сообщение в текстовое поле и нажмите кнопку "Отправить и дать приложению несколько секунд ответить с сообщением из Azure OpenAI.

    Снимок экрана: чат-бот, работающий в Службе приложений Azure.

Ваше приложение теперь развернуто и подключено к Azure OpenAI с использованием управляемой идентификации. Обратите внимание, что он получает доступ к параметру AZURE_OPENAI_ENDPOINT приложения через внедрение @Configuration.

Часто задаваемые вопросы

Почему пример использует @Configuration и Spring Beans для клиента OpenAI?

Использование Spring bean для OpenAIAsyncClient обеспечивает, что:

  • Все свойства конфигурации (например, конечная точка) загружаются и внедряются Spring.
  • Учетные данные и клиент создаются после полного инициализации контекста приложения.
  • Используется внедрение зависимостей, которое является стандартным и наиболее надежным шаблоном в приложениях Spring.

Асинхронный клиент является более надежным, особенно при использовании вместе с DefaultAzureCredential аутентификацией Azure CLI. Синхронный OpenAIClient может столкнуться с проблемами с получением маркеров в некоторых сценариях локальной разработки. Использование асинхронного клиента избегает этих проблем и рекомендуется.


Что делать, если я хочу подключиться к OpenAI вместо Azure OpenAI?

Чтобы подключиться к OpenAI, используйте следующий код:

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

Дополнительные сведения см. в разделе "Проверка подлинности API OpenAI".

При работе с секретами подключения в службе приложений следует использовать ссылки Key Vault вместо хранения секретов непосредственно в базе кода. Это гарантирует, что конфиденциальная информация остается безопасной и управляется централизованно.


Можно ли подключиться к Azure OpenAI с помощью ключа API?

Да, вы можете подключиться к Azure OpenAI с помощью ключа API вместо управляемого удостоверения. Этот подход поддерживается SDK для Azure OpenAI и Semantic Kernel.

При работе с секретами подключения в службе приложений следует использовать ссылки Key Vault вместо хранения секретов непосредственно в базе кода. Это гарантирует, что конфиденциальная информация остается безопасной и управляется централизованно.


Как работает DefaultAzureCredential в этой инструкции?

DefaultAzureCredential упрощает аутентификацию, автоматически выбирая лучший доступный метод аутентификации:

  • Во время локальной разработки: после запуска az login используются ваши локальные учетные данные Azure CLI.
  • При развертывании в Службе приложений Azure используется управляемое удостоверение приложения для безопасной проверки подлинности без пароля.

Такой подход позволяет безопасно и эффективно выполнять код как в локальных, так и в облачных средах без изменений.

Дальнейшие шаги