ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

Azure Functions の Azure OpenAI Extension で 404 エラーが発生する場合の確認事項

Azure Functions では、Azure OpenAI 向けの拡張機能(Preview)が提供されていますが、関数を呼び出した際の 404 エラーに遭遇したので顛末をまとめておきます。
learn.microsoft.com

現象

Text completion input binding などの関数を呼び出した際に、下記のように 404 エラーが発生しました。


[2025-01-17T06:48:58.834Z] Executed 'Functions.GenerateText' (Failed, Id=88d16bb1-2c58-4db4-a173-98208885ae76, Duration=1065ms)
[2025-01-17T06:48:58.838Z] System.Private.CoreLib: Exception while executing function: Functions.GenerateText. Azure.AI.OpenAI: The API deployment for this resource does not exist. If you created the deployment within the last 5 minutes, please wait a moment and try again.
[2025-01-17T06:48:58.849Z] Status: 404 (DeploymentNotFound)
[2025-01-17T06:48:58.852Z] ErrorCode: DeploymentNotFound
[2025-01-17T06:48:58.856Z]
[2025-01-17T06:48:58.861Z] Content:
[2025-01-17T06:48:58.864Z] {"error":{"code":"DeploymentNotFound","message":"The API deployment for this resource does not exist. If you created the deployment within the last 5 minutes, please wait a moment and try again."}}
[2025-01-17T06:48:58.867Z]
[2025-01-17T06:48:58.870Z] Headers:
[2025-01-17T06:48:58.877Z] x-ms-client-request-id: d6ccf64a-504c-471c-b100-d8ff659824d9
[2025-01-17T06:48:58.880Z] apim-request-id: REDACTED
[2025-01-17T06:48:58.883Z] Strict-Transport-Security: REDACTED
[2025-01-17T06:48:58.886Z] X-Content-Type-Options: REDACTED
[2025-01-17T06:48:58.889Z] x-ms-region: REDACTED
[2025-01-17T06:48:58.895Z] Date: Fri, 17 Jan 2025 06:48:57 GMT
[2025-01-17T06:48:58.897Z] Content-Length: 197
[2025-01-17T06:48:58.899Z] Content-Type: application/json
[2025-01-17T06:48:58.901Z] .

原因

以前は正常に動作していたコードなので1時間くらい悩んだのですが、原因はシンプルでエンドポイントが間違っていました。

Azure Portal ではなく、

AI Foundry のモデルのエンドポイントを使うのが正解です。URL の openai/deployments/gpt-4o/chat/completions?api-version=2024-08-01-preview を除いた https://xxx-xxx-eastus2.cognitiveservices.azure.com/ までを使ってください。

ちなみに、以前は Azure Portal のエンドポイントで正常に動作していました。正確には Azure Functions の問題ではなく、AOAI 側のエンドポイントの違いです。

対応

local.settings.json において、正しいエンドポイントとキーを定義します。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "AZURE_OPENAI_ENDPOINT": "https://xxx-xxx-eastus2.cognitiveservices.azure.com/",
    "AZURE_OPENAI_KEY": "xxx",
    "CHAT_MODEL_DEPLOYMENT_NAME": "gpt-4o"
}

Azure Functions のビルドが NuGet エラーで失敗する件

Azure Functions のビルドで NuGet エラーに遭遇したので顛末をまとめておきます。

現象

Azure Functions は、Isolated Worker Process モデルの Durable Functions(.NET9)です。 In-Process モデルでも通常の Functions でも同様のエラーでビルドが失敗します。


error NU1102: バージョン (>= 4.3.1) のパッケージ System.Text.RegularExpressions が見つかりません
error NU1102:   - 2 バージョンが Microsoft Visual Studio Offline Packages に見つかりました。 [ 最も近いバージョン: 4.1.0 ]
error NU1102:   - nuget.org からのバージョンは考慮されませんでした。
error NU1100: 'net6.0' に対する 'Grpc.Core (>= 2.46.6)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。
error NU1100: 'net6.0' に対する 'ncrontab.signed (>= 3.3.0)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。
error NU1100: 'net6.0' に対する 'runtime.native.System (>= 4.3.0)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。
error NU1100: 'net6.0' に対する 'runtime.native.System.Net.Http (>= 4.3.0)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。
error NU1100: 'net6.0' に対する 'runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。
error NU1100: 'net6.0' に対する 'Azure.Data.Tables (>= 12.8.0)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。
error NU1100: 'net6.0' に対する 'WindowsAzure.Storage (>= 9.3.1)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。
error NU1100: 'net6.0' に対する 'Newtonsoft.Json.Bson (>= 1.0.1)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。
error NU1100: 'net6.0' に対する 'runtime.native.System.Security.Cryptography.Apple (>= 4.3.0)' を解決できません。 PackageSourceMapping が有効になっています。次のソースは考慮されませんでした: Microsoft Visual Studio Offline Packages, nuget.org。

Visual Studio から NuGet のキャッシュをクリアしても、エラーは解決しませんでした。


原因

数日前まではビルドが成功していたので、正直何もしていないのに壊れた状態です。

learn.microsoft.com
learn.microsoft.com

エラーコードの説明を読むと、NuGet.Config が怪しそうなので、パッケージソースのマッピングを追加したところ、そのパッケージのエラーは解消するものの、また別のパッケージでエラーが発生してしまいます。


対応

結論としては、パッケージソースのマッピングをすべて削除することで、エラーが解決しました。念のため、すべて削除した後にキャッシュもクリアしました。

自分ではパッケージソースのマッピングを追加していないのに、かなりの数のマッピングが追加されていました。そもそも個別に追加する必要はないはずなので、何かの拍子に追加されたマッピング同士の依存関係が悪さをしていたのかもしれません。

Azure App Service に Streamlit で作成したチャットアプリをデプロイする

今更感ありますが、Azure App Service に Streamlit で作成したアプリケーションをデプロイする手順をまとめておきます。

Streamlit とは

Streamlit は、Python で簡単に Web アプリケーションを構築できるため、AI や機械学習などのデータサイエンティストに人気があるフレームワークです。
streamlit.io

チャットアプリを作成する

今回は、Streamlit でチャットボットのアプリケーションを作成し、バックエンドの LLM には Azure OpenAI Service を利用しました。

まずは、必要となる Python のパッケージをインストールします。

PM> pip install streamlit openai python-dotenv

次に、接続先となる Azure OpenAI Service の情報を環境変数(.env)に定義します。

AZURE_OPENAI_API_KEY="xxx"
AZURE_OPENAI_ENDPOINT="https://xxx.openai.azure.com/"
AZURE_OPENAI_API_VERSION="yyyy-mm-dd-preview"
AZURE_OPENAI_MODEL_NAME="gpt-4o"

app.py にチャットボットを実装します。OpenAI Client を生成し、Chat Completions API を呼び出しています。チャットメッセージの入力と表示、セッション管理など含めて、数行の Python のコードで実装できます。

import streamlit as st

import os
from openai import AzureOpenAI
from dotenv import load_dotenv
load_dotenv()

api_key = os.getenv("AZURE_OPENAI_API_KEY")
azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
api_version = os.getenv("AZURE_OPENAI_API_VERSION")
model = os.getenv("AZURE_OPENAI_MODEL_NAME")

st.title("AOAI Chat App")

client = AzureOpenAI(
    api_key = api_key,
    azure_endpoint = azure_endpoint,
    api_version = api_version
)

if "openai_model" not in st.session_state:
    st.session_state["openai_model"] = model

if "messages" not in st.session_state:
    st.session_state.messages = []

for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

if prompt := st.chat_input("What is up?"):
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)

    with st.chat_message("assistant"):
        stream = client.chat.completions.create(
            model = model,
            messages=[
                {"role": m["role"], "content": m["content"]}
                for m in st.session_state.messages
            ],
            max_tokens = 1024,
            temperature = 0.95,
            stream=True
        )
        response = st.write_stream(stream)
    st.session_state.messages.append({"role": "assistant", "content": response})

ローカル開発環境において、アプリケーションを実行して動作確認しておきます。

PM> streamlit run app.py

デプロイ準備

Azure App Service にデプロイする準備として、下記の2つを追加しておきます。

Azure App Service に Python のパッケージをインストールするための requirements.txt を追加します。

streamlit
openai
python-dotenv

Azure App Service 上で Streamlit のアプリケーションを実行するためのスクリプト(startup.sh)を追加します。

python -m streamlit run app.py --server.port 8000 --server.address 0.0.0.0

ここまで準備できたら、GitHub のリポジトリにコードをプッシュしておきます。

Azure App Service を作成する

Azure Portal から App Service を作成します。Python 3.12 を指定し、Startup Command に startup.sh を設定します。

App settings に SCM_DO_BUILD_DURING_DEPLOYMENT を追加して、値に「1」を設定します。これは App Service 上に Python のパッケージをインストールさせるための構成なので、必ず設定しておく必要があります。
合わせて、.env に定義した Azure OpenAI Service の情報も設定しておきます。

ここまで設定できたら、Deployment Center から App Service と GitHub のリポジトリをリンクして GitHub Actions を設定します。

name: Build and deploy

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python version
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Create and start virtual environment
        run: |
          python -m venv venv
          source venv/bin/activate
      
      - name: Install dependencies
        run: pip install -r requirements.txt
        
      # Optional: Add step to run tests here (PyTest, Django test suites, etc.)

      - name: Zip artifact for deployment
        run: zip release.zip ./* -r

      - name: Upload artifact for deployment jobs
        uses: actions/upload-artifact@v4
        with:
          name: python-app
          path: |
            release.zip
            !venv/

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'Production'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
    permissions:
      id-token: write #This is required for requesting the JWT

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v4
        with:
          name: python-app

      - name: Unzip artifact for deployment
        run: unzip release.zip

      
      - name: Login to Azure
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_2466F700CA8843CA9B069A29E3450DFA }}
          tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_190A7EF7651C4E9B8B92AB9EE837B7F8 }}
          subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_C91DA824A9CC46778EC83041EBFC699E }}

      - name: 'Deploy to Azure Web App'
        uses: azure/webapps-deploy@v3
        id: deploy-to-webapp
        with:
          app-name: 'gooner-chat'
          slot-name: 'Production'

動作確認

デプロイが完了したら、チャットアプリを動作確認してみます。

App Service の Easy Auth で Microsoft Account 認証を設定しました。認証周りもアプリケーションに手を加えずに実現できるのは、App Service のメリットの1つです。


まとめ

Azure App Service に Streamlit で作成したチャットアプリをデプロイしてみました。
HTML や CSS を書かずに Python の数行のコードで Web アプリケーションを構築できるのは便利ですし、Azure App Service にもサクッと公開できるのでお勧めです。

今回のソースコードは、こちらのリポジトリで公開しています。
github.com