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


Разработка приложений для рассуждений с использованием моделей DeepSeek на платформе Microsoft Foundry и пакета SDK OpenAI.

Узнайте, как использовать модели рассуждений, такие как DeepSeek в Azure OpenAI, с помощью пакета SDK OpenAI для Python.

В этой статье показано несколько рекомендаций по интеграции моделей причин:

  • Аутентификация без ключей: используйте управляемые удостоверения или учетные данные разработчика вместо ключей API.
  • Асинхронные операции: используйте асинхронные функции для повышения производительности.
  • Ответы потоковой передачи: предоставляют немедленную обратную связь пользователям.
  • Разделение рассуждений: Отделите шаги рассуждений от окончательных результатов.
  • Управление ресурсами: очистка ресурсов после использования.

Базовый блок DeepSeek

Изучите пример базового блока DeepSeek. В нем показано, как использовать клиентская библиотека OpenAI для вызова модели DeepSeek-R1 и создания ответов на сообщения пользователей.

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

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

Приложение чата запускается как приложение контейнера Azure. Приложение использует управляемое удостоверение с Microsoft Entra ID для проверки подлинности с помощью Azure OpenAI вместо ключа API. Приложение использует Azure OpenAI для создания ответов на сообщения пользователей.

Приложение использует следующие службы и компоненты:

  • Приложение Python Quart, использующее пакет клиентской библиотеки OpenAI для создания ответов на сообщения пользователей
  • Базовый интерфейс HTML/JS, который передает ответы из серверной части с помощью строк JSON через readableStream
  • Файлы Bicep для предоставления ресурсов Azure, включая средства Foundry, Azure Container Apps, Azure Container Registry, Azure Log Analytics и роли RBAC.

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

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

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

Предпосылки

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

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

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

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

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

Это важно

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

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

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

    Открыть в GitHub Codespaces

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

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

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

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

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

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

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

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

Это важно

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

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

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

    Подсказка Ответ
    Имя среды Сохраните его коротким и в нижнем регистре. Добавьте имя или псевдоним. Например: chat-app. Он используется в качестве части имени группы ресурсов.
    Подписка Выберите подписку, в которой вы хотите создать ресурсы.
    Расположение (для размещения) Выберите место рядом с вами из списка.
    Расположение модели DeepSeek Выберите место рядом с вами из списка. Если то же местоположение доступно в качестве вашего первого выбора, выберите его.
  3. Дождитесь развертывания приложения. Развертывание обычно занимает от 5 до 10 минут.

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

  1. После развертывания терминал отображает URL-адрес.

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

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

  3. В браузере задайте вопрос о отправленном изображении, например "Кто нарисовал Мону Лизу?"

  4. Azure OpenAI предоставляет ответ через вывод модели, а результат отображается в приложении.

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

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

Настройка и проверка подлинности

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

Настройка инфраструктуры

Сценарий использует Quart, асинхронный веб-фреймворк, чтобы создать Blueprint под названием chat. Это Blueprint определяет маршруты приложения и управляет его хуками жизненного цикла.

bp = Blueprint("chat", __name__, template_folder="templates", static_folder="static")

Blueprint определяет маршруты / и /chat/stream, а также перехватчики жизненного цикла @bp.before_app_serving и @bp.after_app_serving.

Инициализация с помощью проверки подлинности без ключа

Следующий фрагмент кода обрабатывает проверку подлинности.

Замечание

Хук @bp.before_app_serving инициализирует клиент OpenAI и обрабатывает проверку подлинности. Этот подход крайне важен для безопасного доступа к Azure размещенным DeepSeek-R1 моделям.

Стратегия проверки подлинности адаптируется к среде:

  • In production: использовать Управляемое удостоверение с идентификатором клиента Azure, чтобы избежать хранения конфиденциальных ключей. Этот метод является безопасным и масштабируемым для облачных приложений.
  • На стадии разработки: использует учетные данные Azure Developer CLI с идентификатором клиента Azure для упрощения локального тестирования, используя сеанс входа разработчика в Azure CLI.
@bp.before_app_serving
async def configure_openai():
    if os.getenv("RUNNING_IN_PRODUCTION"):
        client_id = os.environ["AZURE_CLIENT_ID"]
        bp.azure_credential = ManagedIdentityCredential(client_id=client_id)
    else:
        tenant_id = os.environ["AZURE_TENANT_ID"]
        bp.azure_credential = AzureDeveloperCliCredential(tenant_id=tenant_id)

Этот подход к проверке подлинности без ключей обеспечивает следующее:

  • Улучшена безопасность: ключи API не хранятся в переменных кода или среды.
  • Упрощение управления. Нет необходимости сменить ключи или управлять секретами.
  • Плавные переходы: один и тот же код работает как в среде разработки, так и в производственной среде.

Настройка поставщика токенов

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

bp.openai_token_provider = get_bearer_token_provider(
    bp.azure_credential, "https://cognitiveservices.azure.com/.default"
)

Конфигурация клиента Azure OpenAI

Есть два возможных клиента: AzureOpenAI и AsyncAzureOpenAI. Следующий фрагмент кода использует AsyncAzureOpenAI вместе с асинхронным Quart фреймворком для улучшения производительности в условиях конкурентного использования.

bp.openai_client = AsyncAzureOpenAI(
    azure_endpoint=os.environ["AZURE_INFERENCE_ENDPOINT"],
    azure_ad_token_provider=openai_token_provider,
    api_version="2024-10-21",
  • base_url: указывает на конечную точку инференса DeepSeek с Azure
  • api_key. Использует динамически созданный ключ API от поставщика токенов.
  • API-версия: указывает версию API, поддерживающую модели DeepSeek

Конфигурация имени развертывания модели

Следующий фрагмент кода задает версию модели DeepSeek, получив имя развертывания из конфигурации среды. Он назначает имя переменной bp.model_deployment_name , что делает его доступным во всем приложении. Такой подход позволяет изменить развертывание модели без обновления кода.

bp.model_deployment_name = os.getenv("AZURE_DEEPSEEK_DEPLOYMENT")

Замечание

В OpenAI Azure имена моделей напрямую не используются, например gpt-4o или deepseek-r1. Вместо этого вы создаете deployments, которые называются экземплярами моделей в ресурсе OpenAI Azure. Этот подход обеспечивает следующие преимущества:

  • Абстракция: Сохраняет имена развертываний вне кода, используя переменные среды.
  • Гибкость. Позволяет переключаться между различными развертываниями DeepSeek, не изменяя код.
  • Конфигурация для конкретной среды: позволяет использовать различные развертывания для разработки, тестирования и рабочей среды.
  • Управление ресурсами: Каждое развертывание Azure имеет собственные квоты, ограничения и мониторинг.

Управление жизненным циклом

Следующий фрагмент кода предотвращает утечку ресурсов, закрывая асинхронный Azure клиент OpenAI при завершении работы приложения. Хук @bp.after_app_serving обеспечивает правильную очистку ресурсов.

@bp.after_app_serving
async def shutdown_openai():
    await bp.openai_client.close()

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

Функция chat_handler() управляет взаимодействием с моделью DeepSeek-R1 через маршрут chat/stream. Он передает ответы клиенту в режиме реального времени и обрабатывает их. Функция извлекает сообщения из полезных данных JSON.

Реализация потоковой передачи

  1. Функция response_stream начинается с приема сообщений от клиента.

    • request_messages: маршрут ожидает нагрузку JSON, содержащую сообщения пользователя.
    @bp.post("/chat/stream")
    async def chat_handler():
       request_messages = (await request.get_json())["messages"]
    
  2. Затем функция передает ответы из API OpenAI. Он объединяет системные сообщения, такие как "Вы полезный помощник" с предоставленными пользователем сообщениями.

    @stream_with_context
    async def response_stream():
        all_messages = [
            {"role": "system", "content": "You are a helpful assistant."},
        ] + request_messages
    
  3. Затем функция создает запрос завершения потокового чата.

    Метод chat.completions.create отправляет сообщения в DeepSeek-R1 модель. Параметр stream=True включает потоковую передачу ответов в режиме реального времени.

      chat_coroutine = bp.openai_client.chat.completions.create(
          model=bp.openai_model,
          messages=all_messages,
          stream=True,
      )
    
  4. Следующий фрагмент кода обрабатывает ответы потоковой передачи из DeepSeek-R1 модели и обрабатывает ошибки. Он выполняет итерацию по обновлениям, проверяет допустимые варианты и отправляет каждый фрагмент ответа в виде строк JSON. Если возникает ошибка, он регистрирует ошибку и отправляет клиенту сообщение об ошибке JSON при продолжении потока.

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

Обработка содержимого на основе рассуждений

В то время как традиционные языковые модели предоставляют только окончательные выходные данные, модели рассуждений, такие как DeepSeek-R1, показывают свои промежуточные этапы рассуждений. Эти шаги делают их полезными для:

  • Решение сложных проблем
  • Выполнение математических вычислений
  • Обработка многошагового логического рассуждения
  • Принятие прозрачных решений

Обработчик событий submit, расположенный в index.html, обрабатывает потоковый ответ на стороне интерфейса. Этот подход позволяет получать доступ к инструкциям модели и отображать их наряду с окончательными выходными данными.

Фронтенд использует ReadableStream для обработки потоковых ответов из бэкенда. Он отделяет содержимое рассуждений от обычного содержимого, показывая рассуждение в расширяемом разделе, а окончательный ответ — в основной области чата.

Пошаговый разбор

  1. Запуск потокового запроса

    Этот фрагмент кода создает соединение между интерфейсом JavaScript и серверной частью Python, что позволяет интегрировать DeepSeek-R1 Azure OpenAI с проверкой подлинности без ключей.

    const response = await fetch("/chat/stream", {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify({messages: messages})
    });
    
  2. Инициализация переменных

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

    let answer = "";
    let thoughts = "";    
    
  3. Обработка каждого обновления

    Следующий фрагмент кода асинхронно итерирует фрагменты ответа модели.

    for await (const event of readNDJSONStream(response.body)) {
    
  4. Определение и маршрутизация типа контента

    Скрипт проверяет, содержит delta ли событие поле. Если это так, он обрабатывает содержимое в зависимости от того, является ли оно обоснованным или обычным.

    if (!event.delta) {
         continue;
    }
    if (event.delta.reasoning_content) {
         thoughts += event.delta.reasoning_content;
         if (thoughts.trim().length > 0) {
             // Only show thoughts if they are more than just whitespace
             messageDiv.querySelector(".loading-bar").style.display = "none";
             messageDiv.querySelector(".thoughts").style.display = "block";
             messageDiv.querySelector(".thoughts-content").innerHTML = converter.makeHtml(thoughts);
         }
     } else if (event.delta.content) {
         messageDiv.querySelector(".loading-bar").style.display = "none";
         answer += event.delta.content;
         messageDiv.querySelector(".answer-content").innerHTML = converter.makeHtml(answer);
     }
    
    • Если тип контента имеет значение reasoning_content, содержимое добавляется thoughts и отображается в .thoughts-content разделе.
    • Если тип контента имеет значение content, содержимое добавляется answer и отображается в .answer-content разделе.
    • Элемент .loading-bar скрывается, как только начинается потоковая передача содержимого, и раздел .thoughts отображается, если есть какие-либо мысли.
  5. Обработка ошибок:

    Ошибки регистрируются в серверной части и возвращаются клиенту в формате JSON.

    except Exception as e:
        current_app.logger.error(e)
        yield json.dumps({"error": str(e)}, ensure_ascii=False) + "\n"
    

    Этот фрагмент кода внешнего интерфейса отображает сообщение об ошибке в интерфейсе чата.

    messageDiv.scrollIntoView();
    if (event.error) {
        messageDiv.innerHTML = "Error: " + event.error;
    }
    

Очистка GitHub пространства кода

Удалите среду GitHub Codespaces, чтобы максимально увеличить бесплатные часы на ядро.

Это важно

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

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

  2. Найдите свои активные Кодспейсы, созданные из репозитория Azure-Samples//deepseek-python GitHub.

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

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

Зарегистрируйте вашу проблему в Issues репозитория.

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