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


Начало работы с приложениями чата с многомодальным зрением с помощью Azure OpenAI

В этой статье показано, как использовать многомодальные модели Azure OpenAI для создания ответов на сообщения пользователей и отправки изображений в приложении чата. Этот пример приложения чата также включает всю инфраструктуру и конфигурацию, необходимую для подготовки ресурсов Azure OpenAI и развертывания приложения в приложениях контейнеров Azure с помощью Интерфейса командной строки разработчика Azure.

Следуя инструкциям в этой статье, вы получите следующее:

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

Завершив эту статью, вы можете начать изменение нового проекта с помощью пользовательского кода.

Примечание.

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

Обзор архитектуры

Простая архитектура приложения чата показана на следующей схеме: Схема, показывающая архитектуру от клиента к внутреннему приложению.

Приложение чата работает в качестве приложения контейнера Azure. Приложение использует управляемое удостоверение с помощью идентификатора Microsoft Entra для проверки подлинности с помощью Azure OpenAI в рабочей среде, а не ключа API. Во время разработки приложение поддерживает несколько методов проверки подлинности, включая учетные данные Azure Developer CLI, ключи API и модели GitHub для тестирования без ресурсов Azure.

Архитектура приложения зависит от следующих служб и компонентов:

  • Azure OpenAI представляет поставщик ИИ , в который мы отправляем запросы пользователя.
  • Приложения контейнеров Azure — это среда контейнера , в которой размещено приложение.
  • Управляемое удостоверение помогает нам обеспечить безопасность в классе и исключить требование, необходимое для разработчика для безопасного управления секретом.
  • Файлы Bicep для подготовки ресурсов Azure, включая Azure OpenAI, приложения контейнеров Azure, Реестр контейнеров Azure, Azure Log Analytics и роли управления доступом на основе ролей (RBAC).
  • Протокол чата Microsoft AI предоставляет стандартные контракты API на разных языках и решениях ИИ. Приложение чата соответствует протоколу Microsoft AI Chat.
  • Quart Python, использующий openai пакет для создания ответов на сообщения пользователей с отправленными файлами изображений.
  • Базовый интерфейс HTML/JavaScript, который передает ответы из серверной части с помощью строк JSON через readableStream.

Себестоимость

При попытке сохранить цены как можно ниже в этом примере, большинство ресурсов используют базовую или ценовую категорию потребления. Измените уровень уровня по мере необходимости на основе предполагаемого использования. Чтобы прекратить сборы, удалите ресурсы, когда вы закончите работу со статьей.

Дополнительные сведения о затратах в примере репозитория.

Необходимые компоненты

Среда контейнера разработки доступна со всеми зависимостями, необходимыми для выполнения этой статьи. Контейнер разработки можно запустить в GitHub Codespaces (в браузере) или локально с помощью Visual Studio Code.

Чтобы использовать эту статью, необходимо выполнить следующие предварительные требования:

Открытие среды разработки

Используйте следующие инструкции для развертывания предварительно настроенной среды разработки, содержащей все необходимые зависимости для выполнения этой статьи.

GitHub Codespaces запускает контейнер разработки, управляемый GitHub, с Помощью Visual Studio Code для Интернета в качестве пользовательского интерфейса. Для наиболее простой среды разработки используйте GitHub Codespaces, чтобы у вас были правильные средства разработчика и зависимости, предварительно установленные для выполнения этой статьи.

Внимание

Все учетные записи GitHub могут использовать Codespaces в течение до 60 часов бесплатно каждый месяц на двухядровых экземплярах. Дополнительные сведения см. в GitHub Codespaces ежемесячно включаемых в хранилище и основные часы.

Выполните следующие действия, чтобы создать новое пространство кода GitHub в main ветви Azure-Samples/openai-chat-vision-quickstart репозитория GitHub.

  1. Щелкните правой кнопкой мыши следующую кнопку и нажмите кнопку "Открыть ссылку" в новом окне. Это действие позволяет иметь среду разработки и документацию, доступную для проверки.

    Открытие в GitHub Codespaces

  2. На странице "Создание пространства кода" просмотрите и выберите "Создать новое пространство кода"

  3. Дождитесь запуска пространства кода. Этот процесс запуска может занять несколько минут.

  4. Войдите в Azure с помощью интерфейса командной строки разработчика Azure в терминале в нижней части экрана.

    azd auth login
    
  5. Скопируйте код из терминала и вставьте его в браузер. Следуйте инструкциям по проверке подлинности с помощью учетной записи Azure.

Остальные задачи в этой статье выполняются в контексте этого контейнера разработки.

Развертывание и запуск

Пример репозитория содержит все файлы кода и конфигурации для развертывания приложения чата Azure. Ниже описаны примеры процесса развертывания приложения чата Azure.

Развертывание приложения чата в Azure

Внимание

Чтобы снизить затраты, в этом примере используются базовые или ценовые категории потребления для большинства ресурсов. Настройте уровень по мере необходимости и удалите ресурсы, чтобы избежать расходов.

  1. Выполните следующую команду Azure Developer CLI для подготовки ресурсов Azure и развертывания исходного кода:

    azd up
    
  2. Используйте следующую таблицу, чтобы ответить на запросы:

    Prompt Ответ
    Имя среды Сохраните его коротким и строчным регистром. Добавьте имя или псевдоним. Например, chat-vision. Он используется в качестве части имени группы ресурсов.
    Отток подписок Выберите подписку, чтобы создать ресурсы.
    Расположение (для размещения) Выберите расположение рядом с вами из списка.
    Расположение для модели Azure OpenAI Выберите расположение рядом с вами из списка. Если то же расположение доступно в качестве первого расположения, выберите это.
  3. Дождитесь развертывания приложения. Развертывание обычно занимает от 5 до 10 минут.

Использование приложения чата для получения вопросов о модели большого языка

  1. Терминал отображает URL-адрес после успешного развертывания приложения.

  2. Выберите этот URL-адрес, чтобы Deploying service web открыть приложение чата в браузере.

    Снимок экрана: отправленное изображение, вопрос об изображении, ответе ИИ и текстовом поле.

  3. В браузере отправьте изображение, щелкнув " Выбрать файл " и выбрав изображение.

  4. Задайте вопрос о отправленном изображении, например "Что такое изображение?".

  5. Ответ поступает из Azure OpenAI и отображается результат.

Изучение примера кода

Хотя служба OpenAI и Azure OpenAI используют общую клиентную библиотеку Python, при использовании конечных точек Azure OpenAI необходимы небольшие изменения кода. В этом примере используется мультимодальная модель Azure OpenAI для создания ответов на сообщения пользователей и отправленных изображений.

Кодировка Base64 отправленного изображения в интерфейсном интерфейсе

Отправленное изображение должно быть закодировано в Кодировке Base64, чтобы его можно было использовать непосредственно в качестве URI данных в рамках сообщения.

В примере следующий фрагмент кода внешнего интерфейса в scriptтеге src/quartapp/templates/index.html файла обрабатывает эту функцию. Функция toBase64 со стрелками использует readAsDataURL методFileReader асинхронного чтения в отправленном файле изображения в виде строки в кодировке Base64.

    const toBase64 = file => new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => resolve(reader.result);
        reader.onerror = reject;
    });

Функция toBase64 вызывается прослушивателем события формы submit .

Прослушиватель submit событий обрабатывает полный поток взаимодействия чата. Когда пользователь отправляет сообщение, происходит следующий поток:

  1. Скрывает элемент "заголовка отсутствия сообщений", чтобы показать, что беседа началась.
  2. Возвращает и base64 кодирует отправленный файл изображения (если он присутствует)
  3. Создает и отображает сообщение пользователя в чате, включая отправленное изображение
  4. Подготавливает контейнер сообщений помощника с индикатором "Печатает..."
  5. Добавляет сообщение пользователя в массив журнала сообщений
  6. Вызывает метод клиента getStreamedCompletion() протокола AI Chat с журналом сообщений и контекстом (включая закодированное изображение и имя файла в кодировке Base64).
  7. Обрабатывает блоки потокового ответа и преобразует Markdown в HTML с помощью Showdown.js
  8. Обрабатывает любые ошибки во время потоковой передачи
  9. Добавляет кнопку вывода речи после получения полного ответа, чтобы пользователи могли услышать ответ
  10. Очищает поле ввода и возвращает фокус для следующего сообщения.
form.addEventListener("submit", async function(e) {
    e.preventDefault();

    // Hide the no-messages-heading when a message is added
    document.getElementById("no-messages-heading").style.display = "none";

    const file = document.getElementById("file").files[0];
    const fileData = file ? await toBase64(file) : null;

    const message = messageInput.value;

    const userTemplateClone = userTemplate.content.cloneNode(true);
    userTemplateClone.querySelector(".message-content").innerText = message;
    if (file) {
        const img = document.createElement("img");
        img.src = fileData;
        userTemplateClone.querySelector(".message-file").appendChild(img);
    }
    targetContainer.appendChild(userTemplateClone);

    const assistantTemplateClone = assistantTemplate.content.cloneNode(true);
    let messageDiv = assistantTemplateClone.querySelector(".message-content");
    targetContainer.appendChild(assistantTemplateClone);

    messages.push({
        "role": "user",
        "content": message
    });

    try {
        messageDiv.scrollIntoView();
        const result = await client.getStreamedCompletion(messages, {
            context: {
                file: fileData,
                file_name: file ? file.name : null
            }
        });

        let answer = "";
        for await (const response of result) {
            if (!response.delta) {
                continue;
            }
            if (response.delta.content) {
                // Clear out the DIV if its the first answer chunk we've received
                if (answer == "") {
                    messageDiv.innerHTML = "";
                }
                answer += response.delta.content;
                messageDiv.innerHTML = converter.makeHtml(answer);
                messageDiv.scrollIntoView();
            }
            if (response.error) {
                messageDiv.innerHTML = "Error: " + response.error;
            }
        }
        messages.push({
            "role": "assistant",
            "content": answer
        });

        messageInput.value = "";

        const speechOutput = document.createElement("speech-output-button");
        speechOutput.setAttribute("text", answer);
        messageDiv.appendChild(speechOutput);
        messageInput.focus();
    } catch (error) {
        messageDiv.innerHTML = "Error: " + error;
    }
});

Обработка изображения с помощью серверной части

src\quartapp\chat.py В файле серверный код для обработки изображений начинается после настройки проверки подлинности без ключей.

Примечание.

Дополнительные сведения об использовании бессерверных подключений для проверки подлинности и авторизации в Azure OpenAI см . в статье "Начало работы со стандартным блоком безопасности Azure OpenAI" Microsoft Learn.

Конфигурация проверки подлинности

Функция configure_openai() настраивает клиент OpenAI, прежде чем приложение начнет обслуживать запросы. Он использует декоратор Quart @bp.before_app_serving для настройки проверки подлинности на основе переменных среды. Эта гибкая система позволяет разработчикам работать в разных контекстах без изменения кода.

Описаны режимы проверки подлинности
  • Локальная разработка (OPENAI_HOST=local): подключается к локальной службе API, совместимой с OpenAI (например, Ollama или LocalAI) без проверки подлинности. Используйте этот режим для тестирования без затрат на Интернет или API.
  • Модели GitHub (OPENAI_HOST=github): использует торговую площадку GitHub для моделей искусственного интеллекта с GITHUB_TOKEN аутентификацией. При использовании моделей GitHub добавляйте префикс к имени модели openai/ (например, openai/gpt-4o). Этот режим позволяет разработчикам попробовать модели перед подготовкой ресурсов Azure.
  • Azure OpenAI с ключом API (AZURE_OPENAI_KEY_FOR_CHATVISION переменная среды): использует ключ API для проверки подлинности. Избегайте этого режима в рабочей среде, так как ключи API требуют смены вручную и представляют угрозу безопасности при наличии. Используйте его для локального тестирования в контейнере Docker без учетных данных Azure CLI.
  • Производственная среда с управляемым удостоверением (RUNNING_IN_PRODUCTION=true): Использует ManagedIdentityCredential для аутентификации с Azure OpenAI через управляемое удостоверение контейнерного приложения. Этот метод рекомендуется для рабочей среды, так как он удаляет необходимость управления секретами. Контейнерные приложения Azure автоматически обеспечивают управляемое удостоверение и создают разрешения во время развертывания с помощью Bicep.
  • Разработка с помощью Azure CLI (режим по умолчанию): применяется AzureDeveloperCliCredential для аутентификации через Azure OpenAI, используя локально авторизованные учетные данные Azure CLI. Этот режим упрощает локальную разработку без управления ключами API.
Основные детали реализации
  • Функция get_bearer_token_provider() обновляет учетные данные Azure и использует их в качестве токенов носителя.
  • Путь конечной точки Azure OpenAI включает /openai/v1/, чтобы соответствовать требованиям клиентской библиотеки OpenAI.
  • Ведение журнала показывает, какой режим проверки подлинности активен.
  • Эта функция является асинхронной для поддержки операций с учетными данными Azure.

Ниже приведен полный код настройки проверки подлинности из chat.py:

@bp.before_app_serving
async def configure_openai():
    bp.model_name = os.getenv("OPENAI_MODEL", "gpt-4o")
    openai_host = os.getenv("OPENAI_HOST", "github")

    if openai_host == "local":
        bp.openai_client = AsyncOpenAI(api_key="no-key-required", base_url=os.getenv("LOCAL_OPENAI_ENDPOINT"))
        current_app.logger.info("Using local OpenAI-compatible API service with no key")
    elif openai_host == "github":
        bp.model_name = f"openai/{bp.model_name}"
        bp.openai_client = AsyncOpenAI(
            api_key=os.environ["GITHUB_TOKEN"],
            base_url="https://models.github.ai/inference",
        )
        current_app.logger.info("Using GitHub models with GITHUB_TOKEN as key")
    elif os.getenv("AZURE_OPENAI_KEY_FOR_CHATVISION"):
        bp.openai_client = AsyncOpenAI(
            base_url=os.environ["AZURE_OPENAI_ENDPOINT"],
            api_key=os.getenv("AZURE_OPENAI_KEY_FOR_CHATVISION"),
        )
        current_app.logger.info("Using Azure OpenAI with key")
    elif os.getenv("RUNNING_IN_PRODUCTION"):
        client_id = os.environ["AZURE_CLIENT_ID"]
        azure_credential = ManagedIdentityCredential(client_id=client_id)
        token_provider = get_bearer_token_provider(azure_credential, "https://cognitiveservices.azure.com/.default")
        bp.openai_client = AsyncOpenAI(
            base_url=os.environ["AZURE_OPENAI_ENDPOINT"] + "/openai/v1/",
            api_key=token_provider,
        )
        current_app.logger.info("Using Azure OpenAI with managed identity credential for client ID %s", client_id)
    else:
        tenant_id = os.environ["AZURE_TENANT_ID"]
        azure_credential = AzureDeveloperCliCredential(tenant_id=tenant_id)
        token_provider = get_bearer_token_provider(azure_credential, "https://cognitiveservices.azure.com/.default")
        bp.openai_client = AsyncOpenAI(
            base_url=os.environ["AZURE_OPENAI_ENDPOINT"] + "/openai/v1/",
            api_key=token_provider,
        )
        current_app.logger.info("Using Azure OpenAI with az CLI credential for tenant ID: %s", tenant_id)

Функция обработчика чата

Функция chat_handler() обрабатывает запросы чата, отправленные в конечную точку /chat/stream . Он получает POST-запрос с JSON-пейлоадом, который соответствует протоколу Microsoft AI Chat.

JSON-содержимое включает:

  • сообщения: список журнала бесед. Каждое сообщение имеет role ("пользователь" или "помощник") и content (текст сообщения).
  • контекст: дополнительные данные для обработки, в том числе:
    • файл: данные изображения в кодировке Base64 (например, data:image/png;base64,...).
    • file_name: исходное имя файла отправленного образа (полезно для ведения журнала или идентификации типа изображения).
  • температура (необязательно): плавающая, которая управляет случайностью отклика (по умолчанию — 0,5).

Обработчик извлекает данные журнала сообщений и изображений. Если изображение не отправлено, значение изображения равно null, а код обрабатывает этот случай.

@bp.post("/chat/stream")
async def chat_handler():
    request_json = await request.get_json()
    request_messages = request_json["messages"]
    # Get the base64 encoded image from the request context
    # This will be None if no image was uploaded
    image = request_json["context"]["file"]
    # The context also includes the filename for reference
    # file_name = request_json["context"]["file_name"]

Создание массива сообщений для запросов на визуальное зрение

Функция response_stream() подготавливает массив сообщений, отправляемый в API OpenAI Azure. Декоратор @stream_with_context сохраняет контекст запроса во время потоковой передачи ответа.

Логика подготовки сообщений

  1. Начните с журнала бесед: функция начинается с all_messages, которая включает системное сообщение и все предыдущие сообщения, кроме последних (request_messages[0:-1]).
  2. Обработка текущего сообщения пользователя на основе присутствия изображения:
    • С изображением: оформите сообщение пользователя в виде многокомпонентного массива содержимого с текстовыми и image_url объектами. Объект image_url содержит данные изображения в кодировке Base64 и detail параметр.
    • Без изображения: добавление сообщения пользователя в виде обычного текста.
  3. Параметрdetail: установите значение «auto», чтобы модель могла выбирать между уровнями детализации «низкий» или «высокий» в зависимости от размера изображения. Низкая детализация быстрее и дешевле, а высокая детализация обеспечивает более точный анализ сложных изображений.
    @stream_with_context
    async def response_stream():
        # This sends all messages, so API request may exceed token limits
        all_messages = [
            {"role": "system", "content": "You are a helpful assistant."},
        ] + request_messages[0:-1]
        all_messages = request_messages[0:-1]
        if image:
            user_content = []
            user_content.append({"text": request_messages[-1]["content"], "type": "text"})
            user_content.append({"image_url": {"url": image, "detail": "auto"}, "type": "image_url"})
            all_messages.append({"role": "user", "content": user_content})
        else:
            all_messages.append(request_messages[-1])

Примечание.

Дополнительные сведения о параметре изображения detail и связанных настройках см. в разделе "Настройки параметров сведений" статьи Microsoft Learn "Модели чата с визуальной поддержкой".

bp.openai_client.chat.completions Затем получает завершение чата через вызов API Azure OpenAI и передает ответ.

        chat_coroutine = bp.openai_client.chat.completions.create(
            # Azure OpenAI takes the deployment name as the model name
            model=bp.model_name,
            messages=all_messages,
            stream=True,
            temperature=request_json.get("temperature", 0.5),
        )

Наконец, ответ передается клиенту обратно с обработкой ошибок для любых исключений.

        try:
            async for event in await chat_coroutine:
                event_dict = event.model_dump()
                if event_dict["choices"]:
                    yield json.dumps(event_dict["choices"][0], ensure_ascii=False) + "\n"
        except Exception as e:
            current_app.logger.error(e)
            yield json.dumps({"error": str(e)}, ensure_ascii=False) + "\n"

    return Response(response_stream())

Интерфейсные библиотеки и компоненты

Интерфейс использует современные API и библиотеки браузера для создания интерактивного интерфейса чата. Разработчики могут настроить интерфейс или добавить функции, понимая эти компоненты:

  1. Вход/выход речи: пользовательские веб-компоненты используют браузерные Speech API:

    • <speech-input-button>: преобразует речь в текст с помощью API веб-распознавания речи SpeechRecognition. Она предоставляет кнопку микрофона, которая прослушивает голосовой ввод и выдает событие с транскрибированным текстом.

    • <speech-output-button>: зачитывает текст вслух с помощью SpeechSynthesis API. Он отображается после каждого ответа помощника с значком говорящего, позволяя пользователям слышать ответ.

    Зачем использовать API браузера вместо служб Azure Speech?

    • Без затрат — выполняется полностью в браузере
    • Мгновенный ответ — задержка в сети отсутствует
    • Конфиденциальность — голосовые данные остаются на устройстве пользователя
    • Нет необходимости в дополнительных ресурсах Azure

    Эти компоненты находятся в src/quartapp/static/speech-input.js и speech-output.js.

  2. Предварительный просмотр изображения: отображает отправленное изображение в чате перед отправкой анализа для подтверждения. Предварительный просмотр обновляется автоматически при выборе файла.

    fileInput.addEventListener("change", async function() {
        const file = fileInput.files[0];
        if (file) {
            const fileData = await toBase64(file);
            imagePreview.src = fileData;
            imagePreview.style.display = "block";
        }
    });
    
  3. Bootstrap 5 и Bootstrap Icons: предоставляет адаптивные компоненты и значки из библиотеки Bootstrap Icons для пользовательского интерфейса. Приложение использует тему Cosmo из Bootswatch для современного внешнего вида.

  4. Отрисовка сообщений на основе шаблона: использует HTML-элементы <template> для повторно используемых макетов сообщений, обеспечивая согласованность стилей и структуры.

Другие примеры ресурсов для изучения

Помимо примера приложения чата, в репозитории есть другие ресурсы для дальнейшего обучения. Ознакомьтесь со следующими записными книжками в каталоге notebooks :

Записная книжка Description
chat_pdf_images.ipynb В этой записной книжке показано, как преобразовать PDF-страницы в изображения и отправить их в модель визуального зрения для вывода.
chat_vision.ipynb Эта записная книжка предоставляется для ручного экспериментирования с моделью зрения, используемой в приложении.

Локализованное содержимое: испанские версии записных книжек находятся в notebooks/Spanish/ каталоге, предлагая одно и то же практическое обучение для разработчиков, говорящих на испанском языке. Отображаются как английские, так и испанские записные книжки:

  • Как вызывать модели визуального зрения непосредственно для экспериментирования
  • Преобразование PDF-страниц в изображения для анализа
  • Как настроить параметры и тестовые запросы

Очистка ресурсов

Очистка ресурсов Azure

Ресурсы Azure, созданные в этой статье, выставляются в подписку Azure. Если вы не ожидаете, что эти ресурсы потребуются в будущем, удалите их, чтобы избежать дополнительных расходов.

Чтобы удалить ресурсы Azure и удалить исходный код, выполните следующую команду Azure Developer CLI:

azd down --purge

Очистка GitHub Codespaces

Удаление среды GitHub Codespaces гарантирует, что вы можете максимально увеличить объем бесплатных прав на базовые часы, которые вы получаете для вашей учетной записи.

Внимание

Дополнительные сведения о правах учетной записи GitHub см . в GitHub Codespaces ежемесячно включено в хранилище и основные часы.

  1. Войдите на панель мониторинга GitHub Codespaces.

  2. Найдите текущие запущенные пространства Codespaces, полученные из Azure-Samples//openai-chat-vision-quickstart репозитория GitHub.

  3. Откройте контекстное меню для пространства кода и нажмите кнопку "Удалить".

Получить помощь

Зайдите в журнал проблемы репозитория.

Следующие шаги