Azure OpenAI APIをPythonで利用する

# はじめに
本記事ではPythonを使ってAzure OpenAI APIを利用する方法を記載しています。

Azure OpenAI APIは「EntraID認証」と「キー認証」を使って利用する方法がありますが、本記事では「キー認証」を用いて利用します。

## 前提
Azure OpenAI Serviceに任意のモデルをデプロイしておいてください。

Pythonバージョンは「3.13.1」で動作確認しています。

また、ライブラリとして「openai」と「python-dotenv」を利用しています。

```shell:ライブラリのインストール
pip install openai python-dotenv
```

# サンプルコード
「とりあえず動くコードが見たい」という方向けのコードはこちらです。

「これはテストメッセージです」と送信し、AIの回答と「利用トークン数」「プロンプトトークン数」を表示しています。
```python:main.py
import os
from openai import AzureOpenAI
from dotenv import load_dotenv

# .env ファイルから環境変数をロードする
load_dotenv()

# 環境変数を取得する
endpoint = os.getenv("ENDPOINT_URL")
deployment = os.getenv("DEPLOYMENT_NAME")
subscription_key = os.getenv("AZURE_OPENAI_API_KEY")
api_version = os.getenv("API_VERSION")

# キーベースの認証を使用して Azure OpenAI クライアントを初期化する
client = AzureOpenAI(
    azure_endpoint=endpoint,
    api_key=subscription_key,
    api_version=api_version,
)

# モデルへの指示とコンテキストを定義する。
model_context = "情報を見つけるのに役立つ AI アシスタントです。"

# ユーザー クエリを定義する。
user_query = "これはテストメッセージです。"

# チャット プロンプトを準備する
chat_prompt = [{
    "role": "system",
    "content": [
        {
            "type": "text",
            "text": model_context
        },
    ],
}, {
    "role": "user",
    "content": [
        {
            "type": "text",
            "text": user_query,
        },
    ],
}]

# パラメーターを設定する
parameters = {
    "model": deployment,
    "max_tokens": 800,
    "temperature": 1.0,
    "top_p": 0.7,
    "frequency_penalty": 0,
    "presence_penalty": 0,
    "stop": None,
    "stream": False,
}

# チャット プロンプトを送信する
completion = client.chat.completions.create(messages=chat_prompt, **parameters)

# チャット プロンプトを表示する
print(completion.choices[0].message.content)

# 使用したトークンを表示する
print(f"- 完了トークン: {completion.usage.completion_tokens}")
print(f"- プロンプトトークン: {completion.usage.prompt_tokens}")

```

```.env:.env
ENDPOINT_URL=https://<your-endpoint>.openai.azure.com/
AZURE_OPENAI_API_KEY=<your_api_key>
DEPLOYMENT_NAME=<your_deployment_name>
API_VERSION=<your_api_version>
```

## 実行結果
実行すると下記のような出力となります。
```bash:実行結果
C:\xxx> python .\main.py
はい、問題ありません！何かお手伝いできることがあればお気軽にお知らせください。😊
- 完了トークン: 25
- プロンプトトークン: 38
```


# サンプルコードの解説
## .envファイル
Azure OpenAI Serivceのページから必要な情報を取得し、`.env`ファイルに記載します。
```.env:.env
ENDPOINT_URL=https://<your-endpoint>.openai.azure.com/
AZURE_OPENAI_API_KEY=<your_api_key>
DEPLOYMENT_NAME=<your_deployment_name>
API_VERSION=<your_api_version>
```
Azure PortalからAzure OpenAI Studioを開き、Azure OpenAI APIで呼び出すAIモデルの詳細画面を開きます。
![Azure_AI_Studio_ModelDeploy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402149/85f7308e-6dde-f582-c73e-24c927cc5fa0.png)

詳細画面から情報を取得し、.envファイルに記載してください。
![Azure_AI_Studio_ModelDetail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402149/e27fdf71-dbbd-0b26-34fc-5a2956ae6bf0.png)

## モデルへの指示とユーザークエリ
`model_context`にはAIがどのように動作する必要があるかについて記載します。

`user_query`にはAIに対する入力文を記載します。
```python
# モデルへの指示とコンテキストを定義する。
model_context = "情報を見つけるのに役立つ AI アシスタントです。"

# ユーザー クエリを定義する。
user_query = "これはテストメッセージです。"
```

## チャットプロンプトの準備
先に定義したモデルへの指示とユーザークエリを設定します。
```python
# チャット プロンプトを準備する
chat_prompt = [{
    "role": "system",
    "content": [
        {
            "type": "text",
            "text": model_context
        },
    ],
}, {
    "role": "user",
    "content": [
        {
            "type": "text",
            "text": user_query,
        },
    ],
}]
```

## パラメーターの設定
AIに対する各種パラメーターを設定します。
```python
# パラメーターを設定する
parameters = {
    "model": deployment,
    "max_tokens": 800,
    "temperature": 0.7,
    "top_p": 0.95,
    "frequency_penalty": 0,
    "presence_penalty": 0,
    "stop": None,
    "stream": False,
}
```
それぞれの項目は下記となります。

詳細な説明やその他のパラメーターは[Azure OpenAI Service の REST API リファレンス](https://learn.microsoft.com/ja-jp/azure/ai-services/openai/reference)を参照してください。
- `model`
    - AIモデル名を指定します。
- `max_tokens`
    - モデル応答あたりのトークン数に制限を設定します。
- `tempreature`
    - ランダム性を制御します。
    - 0.0に近いとモデルがより反復的および決定論的な応答を生成することを意味します。
    - 1.0に近いと予期しない応答や創造的な応答が増えます。
    - `tempreature`か`top_p`のいずれかを調整することが推奨されています。
- `top_p`
    - ランダム性を制御します。
    - 0.0に近いとモデルのトークンの選択がより可能性が高いトークンに絞り込まれます。
    - 1.0に近いと確率が高いトークンと低いトークンの両方からモデルが選択できるようになります。
    - `tempreature`か`top_p`のいずれかを調整することが推奨されています。
- `frequency_penalty`
    - これまでにテキストに出現した頻度に基づいて、トークンが繰り返される可能性を比例的に減らします。
    - これにより、応答でまったく同じテキストが繰り返される可能性が低くなります。
- `presence_penalty`
    - これまでにテキストに表示されているトークンを繰り返す可能性を減らします。
    - これにより、応答で新しいトピックを紹介する可能性が高まります。
- `stop`
    - モデルの応答を目的のポイントで終了します。
- `stream`
    - 部分的な進行状況をストリーム バックするかどうかを設定します。

## プロンプトの送信と応答の表示
先に設定したチャットプロンプトをパラメーターとともに送信し、応答を表示します。
```python
# チャット プロンプトを送信する
completion = client.chat.completions.create(messages=chat_prompt, **parameters)

# チャット プロンプトを表示する
print(completion.choices[0].message.content)
```

応答 (`completion`)のデータ構造のサンプルは下記の通りです。
```json
{
    "id": "chatcmpl-XXX...",
    "choices": [
        {
            "finish_reason": "stop",
            "index": 0,
            "logprobs": null,
            "message": {
                "content": "はい、問題ありません！何かお手伝いできることがあればお気軽にお知らせください。😊",
                "refusal": null,
                "role": "assistant",
                "audio": null,
                "function_call": null,
                "tool_calls": null
            },
            "content_filter_results": {
                "hate": {
                    "filtered": false,
                    "severity": "safe"
                },
                "self_harm": {
                    "filtered": false,
                    "severity": "safe"
                },
                "sexual": {
                    "filtered": false,
                    "severity": "safe"
                },
                "violence": {
                    "filtered": false,
                    "severity": "safe"
                }
            }
        }
    ],
    "created": 12345678901,
    "model": "xxxxxxxx",
    "object": "chat.completion",
    "service_tier": null,
    "system_fingerprint": "fp_xxxx",
    "usage": {
        "completion_tokens": 27,
        "prompt_tokens": 38,
        "total_tokens": 65,
        "completion_tokens_details": {
            "accepted_prediction_tokens": 0,
            "audio_tokens": 0,
            "reasoning_tokens": 0,
            "rejected_prediction_tokens": 0
        },
        "prompt_tokens_details": {
            "audio_tokens": 0,
            "cached_tokens": 0
        }
    },
    "prompt_filter_results": [
        {
            "prompt_index": 0,
            "content_filter_results": {
                "hate": {
                    "filtered": false,
                    "severity": "safe"
                },
                "self_harm": {
                    "filtered": false,
                    "severity": "safe"
                },
                "sexual": {
                    "filtered": false,
                    "severity": "safe"
                },
                "violence": {
                    "filtered": false,
                    "severity": "safe"
                }
            }
        }
    ]
}
```

## 使用トークンの表示
参考までに`completion`から取得して表示しています。
```python
# 使用したトークンを表示する
print(f"- 完了トークン: {completion.usage.completion_tokens}")
print(f"- プロンプトトークン: {completion.usage.prompt_tokens}")
```

## おわりに

本記事では、Pythonを使ってAzure OpenAI APIへ接続し、実際にチャットプロンプトを送信する方法を記載しました。

誰かのお役に立てれば幸いです。