Azure OpenAI ServiceをBicepで構築する

この記事は [セゾン情報システムズ Advent Calendar 2023](https://qiita.com/advent-calendar/2023/sisco) 1日目の記事です。

Azure OpenAI ServiceをBicepで構築するコードです。
今回最新のGPT-4 Turboモデルを使いたかったので、利用可能なリージョンの1つであるEast US2 リージョンでデプロイしています。
診断設定でAOAIのログをStorage Accountに飛ばしています。

# リポジトリ構成
* 以下のようにモジュール化、パラメータ化しています。

```リポジトリ構成
.
├── main.bicep
├── main.bicepparam
└── modules
    ├── openai.bicep
    └── storageaccount.bicep
```

# Bicepパラメータファイル
* モデルバージョンはパラメータとして渡しています。GPT-4 Turboが利用できる '1106-Preview' バージョンとしています。
* Azure OpenAI Serviceへのネットワークアクセス制限をしたいので、allowIpList配列に許可するIPアドレスを渡します。

```main.bicepparam
using 'main.bicep'

param location = 'eastus2'

// OpenAI Parameters
param openAiName = '[Your OpenAi Name]'
param openAiSku = 'S0'
param allowIpList = [
  'x.x.x.x'
  'y.y.y.y'
]

// OpenAI Model Parameters
param gpt4ModelCapacity = 10
param gpt4ModelVersion = '1106-Preview'
param gpt35ModelCapacity = 120
param gpt35ModelVersion = '0613'

// Storage Account Parameters
param storageAccountName = '[Your Storage Account Name]'
param storageSku = 'Standard_LRS'
```

# Bicepファイル
* mainからモジュールを呼び出すようにしています。

```main.bicep
param location string

// OpenAI Parameters
param openAiName string
param openAiSku string
param allowIpList array

// OpenAI Model Parameters
param gpt4ModelCapacity int
param gpt4ModelVersion string
param gpt35ModelCapacity int
param gpt35ModelVersion string

// Storage Account Parameters
param storageAccountName string
param storageSku string

module storageAccountModule 'modules/storageaccount.bicep' = {
  name: 'storageAccountModule'
  params: {
    location: location
    storageAccountName: storageAccountName
    storageSku: storageSku
  }
}

module openAiModule './modules/openai.bicep' = {
  name: 'openAiModule'
  params: {
    location: location
    openAiName: openAiName
    openAiSku: openAiSku
    gpt4ModelCapacity: gpt4ModelCapacity
    gpt4ModelVersion: gpt4ModelVersion
    gpt35ModelCapacity: gpt35ModelCapacity
    gpt35ModelVersion: gpt35ModelVersion
    storageAccountId: storageAccountModule.outputs.storageAccountId
    allowIpList: allowIpList
  }
}
```

* 診断設定用のストレージアカウントを作ります。

```storageaccount.bicep
param location string
param storageAccountName string
param storageSku string

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  location: location
  name: storageAccountName
  kind: 'StorageV2'
  sku: {
    name: storageSku
  }
  properties: {
    minimumTlsVersion: 'TLS1_2'
  }
}

resource storageAccountBlob 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = {
  parent: storageAccount
  name: 'default'
  properties: {
    deleteRetentionPolicy: {
      enabled: true
      days: 7
    }
    containerDeleteRetentionPolicy: {
      enabled: true
      days: 7
    }
  }
}

output storageAccountId string = storageAccount.id
```

* Azure OpenAI Serviceをデプロイします。モデルはGPT-4、GPT-3.5の2つをデプロイします。

```openai.bicep
param location string
param openAiName string
param openAiSku string
param gpt4ModelCapacity int
param gpt4ModelVersion string
param gpt35ModelCapacity int
param gpt35ModelVersion string
param storageAccountId string
param allowIpList array

resource openAi 'Microsoft.CognitiveServices/accounts@2023-05-01' = {
  name: openAiName
  location: location
  kind: 'OpenAI'
  sku: {
    name: openAiSku
  }
  properties: {
    customSubDomainName: openAiName
    networkAcls: {
      defaultAction: 'Deny'
      virtualNetworkRules: []
      ipRules: [for item in allowIpList: {
        value: item
      }]
    }
    publicNetworkAccess: 'Enabled'
  }
}

resource gpt4Model 'Microsoft.CognitiveServices/accounts/deployments@2023-10-01-preview' = {
  parent: openAi
  name: 'gpt-4'
  sku: {
    name: 'Standard'
    capacity: gpt4ModelCapacity
  }
  properties: {
    model: {
      format: 'OpenAI'
      name: 'gpt-4'
      version: gpt4ModelVersion
    }
    versionUpgradeOption: 'OnceNewDefaultVersionAvailable'
    raiPolicyName: 'Microsoft.Default'
  }
}

resource gpt35Model 'Microsoft.CognitiveServices/accounts/deployments@2023-10-01-preview' = {
  parent: openAi
  name: 'gpt-35-turbo'
  sku: {
    name: 'Standard'
    capacity: gpt35ModelCapacity
  }
  properties: {
    model: {
      format: 'OpenAI'
      name: 'gpt-35-turbo'
      version: gpt35ModelVersion
    }
    versionUpgradeOption: 'OnceNewDefaultVersionAvailable'
    raiPolicyName: 'Microsoft.Default'
  }
  dependsOn: [
    gpt4Model
  ]
}

resource diagnosticLogs 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
  name: openAi.name
  scope: openAi
  properties: {
    storageAccountId: storageAccountId
    logs: [
      {
        category: 'Audit'
        enabled: true
      }
      {
        category: 'RequestResponse'
        enabled: true
      }
    ]
  }
}
```

* 今回GPT-3.5、GPT-4の2つをデプロイしようとしていますが、複数モデルをデプロイしようとすると以下のエラーとなりました。

```json
{
  "code": "RequestConflict",
  "message": "Another operation is being performed on the parent resource 'xxx'. Please try again later."
}
```

* dependsOnを加えて、複数モデルが同時にデプロイされないように変更することで解消しています。

# 実行
* パラメータを指定してデプロイし、Azure OpenAI Serviceがデプロイされたことを確認します。

```
az deployment group create --resource-group [Your Resource Group Name] --template-file main.bicep --parameters main.bicepparam
```

以上です