Azure OpenAI ServiceでJSONモード

# Azure OpenAI ServiceでJSONモードを使用する方法

### はじめに

:::note info
間違っている情報を記載している可能性もあります。見つけた際は優しく教えていただけますと幸いです。
:::


本記事は以下の公式ドキュメントを参考にしています。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/how-to/json-mode?tabs=python

JSONモードの使用方法についてのみ記載しているので、基本的なAzure OpenAI Serviceの使用方法がわからない方は以下の公式ドキュメントを御覧ください。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/quickstart?tabs=command-line%2Cpython&pivots=programming-language-python

## JSONモードを使用可能なモデル
 - **gpt-4-1106-preview**
     - [利用可能なリージョン](https://learn.microsoft.com/ja-jp/azure/ai-services/openai/concepts/models#gpt-4-and-gpt-4-turbo-preview-model-availability)
     - 記事投稿時）オーストラリア東部、カナダ東部、米国東部 2、フランス中部、ノルウェー東部、インド南部、スウェーデン中部、英国南部、米国西部
 - **gpt-35-turbo-1106**
     - [利用可能なリージョン](https://learn.microsoft.com/ja-jp/azure/ai-services/openai/concepts/models#gpt-35-turbo-model-availability)
     - 記事投稿時）オーストラリア東部、カナダ東部、フランス中部、インド南部、スウェーデン中部、英国南部、米国西部

GPT4は確かに精度は高いですが、ロードにかなり時間がかかるので、時と場合で使い分ける必要がありそうです。

画像の赤枠の部分。使いたいモデルを利用可能なリージョンを選んでください。

![リージョン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704771/14ee7852-e223-b881-3d06-cba3b8da87e2.png)


## APIのバージョン
 - **2023-12-01-preview**
（APIのバージョンは この後、コード上に記載します。）

## コードの例

```python
import os
from openai import AzureOpenAI

client = AzureOpenAI(
  # Azureポータルで確認できます。 
  azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"), 
  # Azureポータルで確認できます。 
  api_key=os.getenv("AZURE_OPENAI_KEY"),  
  # 先ほど記載した、APIのバージョン。
  api_version="2023-12-01-preview"
)

response = client.chat.completions.create(
  # Azure OpenAI Studioでデプロイした名前
  model="deployment_name",
  # これを指定することで、JSONモードになります。
  response_format={ "type": "json_object" },
  # JSONモードを使用するにはメッセージに、「JSON」を含める必要があります。
  messages=[
    {"role": "system", "content": "You are a helpful assistant designed to output JSON."},
    {"role": "user", "content": "Who won the world series in 2020?"}
  ]
)
print(response.choices[0].message.content)
```

:::note warn
メッセージ会話の一部として JSON を生成する必要があるというガイダンスをモデルに含めることが必要です。 命令は、システム メッセージの一部として追加することをお勧めします。 OpenAI によると、この命令の追加の失敗により、モデルによって "空白の無制限のストリームが生成され、要求がトークンの制限に達するまで継続的に実行される" 可能性があります。

メッセージ内に "JSON" を含めないと、以下が返されます。
```
BadRequestError: Error code: 400 - {'error': {'message': "'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'.", 'type': 'invalid_request_error', 'param': 'messages', 'code': None}}
```
:::

## 出力の例
```JSON
{
  "winner": "Los Angeles Dodgers",
  "event": "World Series",
  "year": 2020
}
```
<details><summary>Pythonの辞書型に変換</summary>

PythonでAPIから返ってきたJSON形式のデータをPythonの辞書に変換する方法。
jsonモジュールのloads関数を使用することで、辞書に変換することができます。

例）
```python
import os
import json
from openai import AzureOpenAI

（省略）

response_content = response.choices[0].message.content
data = json.loads(response_content)
res = {
    "winner": data["winner"],
    "event": data["event"],
    "year": data["year"]
}

print res
```
</details>


## その他の考慮事項

応答を解析する前に、値 length があるか finish_reason を確認する必要があります。 このモデルから部分的な JSON が生成されることがあります。 つまり、モデルからの出力が、要求の一部として設定された使用可能な max_tokens よりも大きかったか、会話自体がトークンの制限を超えています。

JSON モードにより、有効な JSON が生成され、エラーなしで解析されます。 ただし、プロンプトで要求された場合でも、出力が特定のスキーマと一致する保証はありません。

### おわりに
Azure OpenAI ServiceでもJSONモードが安定して使用出来るようになりました！とても便利ですね！
後は、[Vercel AI SDK](https://sdk.vercel.ai/docs)にAzureも対応して欲しいと思っている所存です。