Azure AI FoundryのプロンプトフローをCLIでデプロイする

# はじめに
~~Azure AI Studio~~ Azure AI Foundry のプロンプトフローは多くの場合、GUIでポチポチとデプロイしてエンドポイントが出来上がるという使い方をされるかと思います。
しかしながらGUI上のプロンプトフローは、基本的に作成者しか編集やデプロイができません。誰かのプロンプトフローを編集したい場合は、元のフローをクローンしてくる必要があります。

こうした仕様のため、チームで開発する際にはプロンプトフローをCLIでデプロイしたい！
CD環境を構築したい！というモチベーションが生まれるかと思います。ここではそれらをどのように実現できるかをまとめます。

プロンプトフローからデプロイを行った場合、「モデル＋エンドポイント」画面にエンドポイントとデプロイメントが作成されます。以下の画像が例です。エンドポイントの下にクリック可能なリンクができるのですが、これがデプロイメントです。画像では1つしかありませんが、1つのエンドポイントに対して複数のデプロイメントを持たせることも可能です。そのようにしてデプロイメントAにはトラフィックの70%を、デプロイメントBには30%をといったことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3942439/ee8c14cf-0430-f8c8-2174-9931a486108a.png)


# Azure AI Foundry～実態はAzure Machine Learning～
Azure AI Foundryで用いられる機能が実態はMachine Learningで動いている。これは AI Studio時代からの特徴です。例えば、プロンプトフローをデプロイをすると作成されたエンドポイントとデプロイメントがAI Foundry画面で確認できるようになります。これは実際にはMachine Learningによって管理されているリソースになり、Machine Learning Studioの画面でも確認可能なのです。
（Azure AI Foundryのプロジェクトは実質的にMachine Learningのワークスペースなのです。実際、Machine Learning Studioを起動すると作った覚えはないのに、Azure AI Foundryのプロジェクトと同名のワークスペースが作られていることに気づきます。）

そのため、プロンプトフローをデプロイする際もAzure Machine Learningにアプローチするということが必要になります。具体的には、デプロイには`azure ml ~`コマンドを使います。
大きく分けて、CLIでのデプロイには３段階に分けて行われます。すなわち、モデルの作成・エンドポイントの作成・デプロイメントの作成です。

※AI Foundryの画面からデプロイメントを削除する場合、以下のようなポップアップが出ます。
ここでデプロイメントとエンドポイントを削除した場合、AI Foundryの画面から消え、きれいに掃除できたかに見えますが実際には「モデル」は削除されておらず、残り続けています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3942439/43a7e953-8160-4617-aaf8-dccfe6a8f21c.png)


モデルそれ自体はMachine Learning Studioの画面（あるいはcliの実行）でしか確認できないのです。
以下がMachine Learning Studioのモデル画面です。ここからモデル自体の削除が可能です。
こういった仕様のためにAI Foundryの画面のみでデプロイメントやエンドポイントの作業をしていた場合知らず知らずのうちにモデルの残骸がたまり続けていることに気が付かないという事態になります...
下の画像はMachine Learning Studioの「モデル」画面です。モデルはAI Foundryの画面からは確認できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3942439/485335a0-a851-4249-aa78-8a28be292f36.png)

# 事前準備
### Azure CLIのインストール

お使いの環境にAzure CLIがない場合、インストールする必要があります。下記のリンクからインストールが可能です。
例として、curlコマンドを用いてインストールする場合のコマンドは以下です。
`curl -L https://aka.ms/InstallAzureCli | bash`

https://learn.microsoft.com/ja-jp/cli/azure/install-azure-cli

次に、以下のコマンドを実行して`ml` の拡張が入っているかを確認します。なければ`add`で拡張を導入します。
- `az extension list`
- `az extension add --name ml`

### プロンプトフローの準備
今回はAzure AI Foundryで作成したプロンプトフローをローカルにダウンロードして用いようと思います。
画面上の「ファイル」にあるダウンロードボタンを押すことで現在のプロンプトフローの構成物一式をダウンロードすることができます。
ここから先のモデルの作成、エンドポイントの作成、デプロイメントの作成はダウンロードした構成物を展開したルートフォルダで作業をしています。

# モデルの作成
初めに、モデルの作成を行います。モデルはプロンプトフローのフローを定義したファイル（flow.dag.yamlなど）を含むフローの核となる成果物です。モデルは以下のようなスキーマで定義されています。

生成AIでよく使われるチャットとして登録するには次のようなプロパティを記述する必要があります。公式ドキュメントからの引用です。これを`model.yml`などの名前で保存します。


```yaml
$schema: https://azuremlschemas.azureedge.net/latest/model.schema.json
name: basic-chat-model
path: ../../../../examples/flows/chat/basic-chat
description: register basic chat flow folder as a custom model
properties:
  # In AuzreML studio UI, endpoint detail UI Test tab needs this property to know it's from prompt flow
  azureml.promptflow.source_flow_id: basic-chat
  
  # Following are properties only for chat flow 
  # endpoint detail UI Test tab needs this property to know it's a chat flow
  azureml.promptflow.mode: chat
  # endpoint detail UI Test tab needs this property to know which is the input column for chat flow
  azureml.promptflow.chat_input: question
  # endpoint detail UI Test tab needs this property to know which is the output column for chat flow
  azureml.promptflow.chat_output: answer
```
`path`でモデルが参照するパスを指定します。これはflow.dag.yamlを含むフォルダです。

`azureml.promptflow.source_flow_id: basic-chat`、`azureml.promptflow.mode: chat`でこのモデルが「チャット」のモデルであることを明示しています。
また、入力と出力をしている箇所があります。ここはプロンプトフローにおけるチャットの入力とチャットの出力に対応する部分です。プロンプトフローの定義ファイル（flow.dag.yaml）で`is_chat_input: true`と`is_chat_output: true`になっている部分を指します。下の定義を例にするとそれぞれ`chat_input`と`content`です。
```yaml
id: bring_your_own_data_chat_qna
name: Bring Your Own Data Chat QnA
inputs:
  chat_history:
    type: list
    default: []
    is_chat_input: false
  chat_input:
    type: string
    default: こんにちは、お元気ですか？
    is_chat_input: true
outputs:
  content:
    type: string
    reference: ${chat_with_context.output}
    is_chat_output: true
```

`model.yml`が作成できたら、モデルの登録を行います。以下のコマンドを実行します。
- `az ml model create --file model.yml -w <workspace> -g <resource group>`

workspaceにはご自身のAI Foundryプロジェクト名、リソースグループにはAI Foundryが属するリソースグループの名前をご指定ください。


# エンドポイントの作成

モデルが登録されたら、エンドポイントを作成します。コードは公式ドキュメントからの引用です。
エンドポイントの名前は必須で必要で、API Keyでの認証を行うために`auth_mode`を`key`にしています。また、`enforce_access_to_default_secret_stores : true`の設定によりこれを実行するユーザーがシークレットを読み取るようにしています。
```yaml
$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineEndpoint.schema.json
name: basic-chat-endpoint
auth_mode: key
properties:
# this property only works for system-assigned identity.
# if the deploy user has access to connection secrets, 
# the endpoint system-assigned identity will be auto-assigned connection secrets reader role as well
  enforce_access_to_default_secret_stores: enabled
```

こちらの定義を`endpoint.yml`などの名前で保存し、以下のコマンドを実行します。
- `az ml online-endpoint create --file endpoint.yml -w <workspace> -g <resource group>`

成功すると、エンドポイントが作成されます。

# デプロイメントの作成
エンドポイントまで作成が成功したら、最後にデプロイメントの作成を行います。先ほど作成したエンドポイントに対してデプロイメントを作成するかたちになります。
`environment: image:`でデプロイするプロンプトフローが動作するランタイムイメージを指定します。
例で指定している`mcr.microsoft.com/azureml/promptflow/promptflow-runtime:latest`はAzureが公式で提供しているプロンプトフロー用ランタイムの最新版を意味します。

`instance_type`でインスタンスの種類を選択します。予算に合わせて選択してください。
また、`instance_count`で数も指定できます。

`environment_variables: PRT_CONFIG_OVERRIDE`は、プロンプトフローをCLIからデプロイする場合は必須の値になります。「サブスクリプション名」「リソースグループ名」「ワークスペース名」「エンドポイント名」「デプロイメント名」をそれぞれ指定する必要があります。


```yaml
$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineDeployment.schema.json
name: <デプロイメント名>
endpoint_name: <エンドポイント名>
model: azureml:<モデル名>:<バージョン名>
  # You can also specify model files path inline
  # path: examples/flows/chat/basic-chat
environment:
  # recommend to use latest version of promptflow-runtime image
  image: mcr.microsoft.com/azureml/promptflow/promptflow-runtime:latest
  # inference config is used to build a serving container for online deployments
  inference_config:
    liveness_route:
      path: /health
      port: 8080
    readiness_route:
      path: /health
      port: 8080
    scoring_route:
      path: /score
      port: 8080
instance_type: Standard_DS3_v2
instance_count: 1
environment_variables:
  PROMPTFLOW_RUN_MODE: "serving"
  # for pulling connections from workspace
  PRT_CONFIG_OVERRIDE: deployment.subscription_id=<サブスクリプションid>,deployment.resource_group=<リソースグループ名>,deployment.workspace_name=<ワークスペース名>,deployment.endpoint_name=<エンドポイント名>,deployment.deployment_name=<デプロイメント名>

  # (Optional) When there are multiple fields in the response, using this env variable will filter the fields to expose in the response.
  # For example, if there are 2 flow outputs: "answer", "context", and I only want to have "answer" in the endpoint response, I can set this env variable to '["answer"]'.
  # If you don't set this environment, by default all flow outputs will be included in the endpoint response.
  # PROMPTFLOW_RESPONSE_INCLUDED_FIELDS: '["category", "evidence"]'
data_collector:
  collections:
    model_inputs:
      enabled: "true"
    model_outputs:
      enabled: "true"
egress_public_network_access: "enabled"
request_settings:
  request_timeout_ms: 300000
  max_concurrent_requests_per_instance: 10

```

このように修正したファイルを`deployment.yml`などのファイル名で保存します。
その後、以下のようにコマンドを実行することでデプロイメントを作成します。
- `az ml online-deployment create --file deployment.yml -w <workspace> -g <resource group> --all-traffic `

`--all traffic`オプションを付けると、このデプロイメントに割り当てられるトラフィックが100になります。
デプロイメントの作成に成功すると、このエンドポイントが実際に使えるようになります。

# まとめ
今回の内容をまとめると以下のようになります。
- プロンプトフローはCLIを用いてデプロイができる
- デプロイまでには次の3ステップに分けられる
  - モデルの作成
  - エンドポイントの作成
  - デプロイメントの作成
- 一部 Machine Learning Studioか`azure ml` コマンドを用いないと確認できない内容がある

以上になります。お読みいただきありがとうございました！

## 補足
デプロイメントを作成する場合、様々な設定が可能であり、どうするのがベストなのか判断だ難しいということがあり得ると思います。
その場合、リバース的にすでに存在するデプロイメント（GUIからデプロイしたフローのデプロイメントなど）の設定を参考するという手も考えられます。
その際には以下のようなコマンドでデプロイメントの詳細な設定を取得できます
- `az ml online-deployment show -n <deployment_name> -e <endpoint_name> -w <workspace> -g <resource group>`

# 参考

https://learn.microsoft.com/en-us/azure/machine-learning/prompt-flow/how-to-deploy-to-code?view=azureml-api-2&tabs=managed

https://learn.microsoft.com/ja-jp/cli/azure/install-azure-cli

https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-configure-cli?view=azureml-api-2&tabs=public


https://learn.microsoft.com/ja-jp/azure/machine-learning/reference-yaml-model?view=azureml-api-2

https://learn.microsoft.com/ja-jp/azure/machine-learning/reference-yaml-endpoint-online?view=azureml-api-2

https://learn.microsoft.com/ja-jp/azure/machine-learning/reference-yaml-deployment-managed-online?view=azureml-api-2