【自分でも動かせた！】Azure OpenAI REST APIの挙動を見てみた

# INDEX
- 概要
- 目的
- 準備
- 雑なリソース構成
- Azure OpenAI REST APIの挙動を見てみた
- あとがき
- 参考


# 1. 概要

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/a80d34b7-c808-1a42-dbd0-9a3fab17efef.png)
注意: この記事は↑スクショのアプリ[^overview]を作る訳ではありません。


こんにちは。今回はとりあえずGPT関連に触ってみようという事で社内で試行錯誤していた記録です。
この記事は、**Azure OpenAI Serviceに興味はあるけど触った事ない人（どっから始めればいいんや…と悩んでいる人）** あたりを想定しています。
つまり、**俺でもアプリにAzure OpenAIを組み込んで何か出来そう！** と思ってもらえたら、**私的にもオールオッケー**[^hotlimit]です。

MS Learnやリファレンスが難解と感じる**企業ユーザー向け**[^corp-users]なので、既に使い始めている人には無用の長物どころか知識を捻じ曲げる毒物になりそうなので見ない方がいいです。

[^overview]: このスクショはOpenAI Studioで`Playground > Chat`を開き、画面右上にある`Deploy to > A new web app...`を選択すると構築できるアプリを改造したものです。ソースコードはGitHub上のMITで公開されています。https://github.com/microsoft/sample-app-aoai-chatGPT

[^hotlimit]: 元ネタはTMRの[Hotlimit](https://www.youtube.com/watch?v=vBmU5v2EyxM)の一節。`ダイスケ的にもオールオッケー`。`ダイスケ`とは多分`浅田大介`の事。もう10年以上前なんですね。

[^corp-users]: 後述する利用申請ページにて、メールアドレス等を入力しないとダメですが、これを企業ユーザーに限定している。個人ユーザーはダメっぽい。悲しいω


## 2. 目的
本記事では、VSCode拡張のREST Clientを用いて、Azure OpenAI APIの呼び出しをする手順を記載します。
REST APIの呼び出し方さえ分かってしまえば、他のアプリに組み込むのは何とかなるのではないかと思ったからです。


## 3. 準備
- Azureのサブスクを持ってる事
    - Azureを選ぼうとしているサラリーマンエンジニアなら既に持ってると思うのでスキップ！
- OpenAIの利用申請をする事
    - 申請ページ
        - https://aka.ms/oai/access
    - 申請時の注意点
        - 問5: 申請ページの途中でメールアドレスを求められるが、これが企業ユーザーに限定されている
        - 問17: OpenAIを使いたいのが自社ではない場合、**使いたい企業（顧客企業等）自身**に申請させて下さい（代理不可）
        - 問18: 通常は`Text and code models`だけでよい。画像生成もしたいなら`DALL-E 2 models`[^dall-e]も選択して良いです。2023年9月現在は、East USリージョンのみの提供になっています
    - メモ
        - GPT-4のモデルを使いたい人は、こちらの利用申請も追加で必要です
            - https://aka.ms/oai/get-gpt4


[^dall-e]: 読みは「ダリー」。テキストの説明を元に画像を生成するモデルの一つです。`Stable Diffution`や`Novel AI`のサービスの中にいるモデルもこういう特徴を持ったものかもしれませんね。知らんけど。


# 4. 雑なリソース構成
本家ChatGPTと違い、Azure OpenAIを使うためにはAzure的な考えが必要です。
ここでは、実際にリソースを作成し、RESTリクエストを投げる所までを書きます。

## 4.1. OpenAI Serviceリソースを作る
- Azureポータルにアクセスし、リソース作成画面を開きます
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/f28aabaf-5830-f5de-2c59-8a387e5d6f4a.png)
- 適宜設定します
    - 基本
        - 名前はREST APIのエンドポイントのサブドメイン部分になります。あんま変な名前にしないでね！[^endpoint]
        - リージョンについて2023/9時点では、DALL-Eを使う場合は`East US`にしないとダメです！[^openai-region]
        - 価格について2023/9時点では、`Standard S0`しか確認できていません
            ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/edfe3e54-222f-e1eb-fde5-e133a78bc433.png)
    - ネットワーク
        - 種類について、一旦さっくり使いたいだけなので、無効にします。
        - それ以外はそのままで
            ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/14284e39-2470-329a-f06c-e70d3bc66e45.png)
    - タグ
        - お好きなように！
    - レビューおよび送信
        - 問題がなければ`作成`ボタンを押下します。
            ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/3a0daa18-dbd3-70b5-331f-727a67c3ad64.png)
- 追加のネットワーク設定をします
    - 作成したリソースを開き、`リソース管理 > ネットワーク（Networking）`を開きます
    - スクショのように設定し、自分のPCからOpenAIリソースに触れるようにします。[^caution1]
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/794e1b10-d306-e639-8bdd-b7aa72e896f3.png)


[^endpoint]: もしかしたら自前のドメインを買っているブルジョアな所は重複を気にしなくて良いかもね。買ってないので知らんけど。

[^openai-region]: Japan Eastで使えるのは `gpt-35-turbo系`、`gpt-4系`、`text-embedding-ada-002` の3系統。不正確な説明だが、初心者レベルなら`gpt-35`と`gpt-4`はチャットAPIに特化しているおり、`ada`は埋め込みAPIに特化…くらいに知っていればOK。

[^caution1]: お試しで触りたいだけなのでこういう構成にしています。この構成でアプリを公開するのは推奨しません。仮想ネットワーク等を作り、特定のアプリからのみアクセスするようにさせる等を検討して下さい。


## 4.2. 使用するモデルをデプロイする
- OpenAI Serviceリソースは、GPTモデルを格納する為の箱です。なので、箱にモデルを入れていきます。
- 作成した`Azure OpenAI Service`リソースを開き、`Azure OpenAI Studio`を起動します。  
    上の方にある`Go to Azure OpenAI Studio`でも開きますが、同じウインドウで開いてしまうのでスクショのように`Explore`ボタンがオススメです。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/21a6d740-6160-0f1a-1156-7e9af8574a4b.png)
- Studioが起動したら、`Management > Deployments > + Create new deployment`を開きます
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/2516b5af-1d1f-d628-956b-c4da6c32886f.png)
- 画面がポップしたら、任意のモデルとデプロイ名を指定します。  
    スクショは`gpt-35-turbo-16k`を指定[^flag]していますが、`gpt-35-turbo`で問題ありません。  
    `Tokens per Minute Rate Limit`に関してはお試しで触るだけなので初期値で問題ありません。高負荷または低負荷アプリ組み込み時等は調整が必要です。  
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/be37c766-c34d-e11e-dc05-6a8fb8afd35b.png)

[^flag]: このスクショはフラグです…orz


### 余談: デプロイできるモデルの一覧を確認する
`+ Create new deployment`で選べるモデルは、`Management > Models`から確認できます。
ちなみに、OpenAIの利用申請がまだ適用されていなかったりすると空っぽになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/76f64dda-5bb9-8cbc-2d72-1481c7fd2870.png)


# 5. Azure OpenAI REST APIの挙動を見てみた
REST APIの呼び出しは、VSCodeの[`REST Client`](https://marketplace.visualstudio.com/items?itemName=humao.rest-client)という拡張機能を使いました。

## 5.1. とりあえずチャットAPIでHello, World
最初なので、細かく書いてみます。

### 5.1.1. RESTの投げ方を見る
- Studioの`Playground > Chat`を開きます
- `Chat session`のテキストボックスに任意の文字を入れて送信します
- `Chat session > View code`を開きます
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/5fceb6fa-7bb2-1777-adf3-49766bcc9e83.png)
- 右上のドロップダウンボックスで言語が選べます。今回はRESTの投げ方を知りたいので`curl`を選びます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/5fc8055b-78e3-2f4f-d083-07771020d6bc.png)
- リクエストヘッダも含めて、チャットを送った時のコマンドが分かりますね！ポイントはこの辺ですかね。
    - エンドポイント（URL）とメソッド（GETとかPOSTとか）
    - APIキー
    - リクエストBODY

### 5.1.2. 実際にREST Clientで投げてみる
色々と思考錯誤して最小に近い形にしたのがこちら。
カッコ書きした箇所は適宜置き換えて使ってみて下さい。

```:test1.http
# 基本設定
@api_key = （APIキー）
@endpoint = https://（リソース名）.openai.azure.com
@api_version = 2023-05-15
@deployment_name = （モデルデプロイ時につけた`Deployment Name`）

### チャットAPI（Chat） - "/chat/completions"
POST {{endpoint}}/openai/deployments/{{deployment_name}}/chat/completions?api-version={{api_version}}
api-key: {{api_key}}
Content-Type: application/json

{
    "model": "（モデル名「gpt-35-turbo」等）",
    "messages": [
        { "role": "user", "content": "こんにちは、世界" }
    ]
}
```

#### 実際に投げてみた所
- 送信方法。VSCode上に上記コードをテキストファイル（拡張子はhttp）で作成すると、メソッド（GETやPOST）の直上に`Send Request`という文字が出るので、これをクリックする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/e323bced-3d10-18c4-a73a-6bf71daf2025.png)
- 送信
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/5e4125e9-db86-caed-de0d-876a367f639b.png)
- 受信
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/de86b9de-b7c5-6ebc-6b20-4d1b26bbe902.png)
    

## 5.2. 入力候補APIはどうよ？！
投げ方の雰囲気はチャットAPIを同じだけど、モデルがチャット系特化（`gpt-35-turbo`ではなく`gpt-35-turbo-16k`等）だと失敗する。

```:test2.http
# 基本設定
@api_key = （APIキー）
@endpoint = https://（リソース名）.openai.azure.com
@api_version = 2023-05-15
@deployment_name = （モデルデプロイ時につけた`Deployment Name`）

### 入力候補API（Completions） - "/chat/completions"
POST {{endpoint}}/openai/deployments/{{deployment_name}}/completions?api-version={{api_version}}
api-key: {{api_key}}
Content-Type: application/json

{
    "prompt": "赤い果物を3つ、名詞のみで答えなさい",
    "max_tokens": 100,
    "stop": null
}
```

#### 実際に投げてみた所
- 送信
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/a9ca4042-26ea-a643-d4b9-7a39803d3a40.png)
- 受信
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/c1c69a15-cbe8-1a56-6eaa-2ce3a6b58aaf.png)

**エラーやんけ！** どうやら入力候補APIに対応していないモデル（`gpt-35-turbo-16k`）を使ったせいみたいです。

#### モデルを`gpt-35-turbo`に変更して実際に投げてみた所（リトライ）
- OpenAI Serviceリソースに`gpt-35-turbo`を追加してからリトライします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/e7343631-d9a3-3a8e-cf55-d4fe39420805.png)
- 送信
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/21d584a7-0c36-27c0-95ea-655d5dc8d2f8.png)
- 受信
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/71a20cbd-2f46-4eba-42b1-975372f9b107.png)

200 OKが返ってきました。
でも、文章にもなってしまいましたね。この辺は別のモデルを使うと良いのだろうか。（davinci等）


## 5.3. それ以外のAPI。そや！モデルAPIって使えそうじゃね？
```:test3.http
# 基本設定
@api_key = （APIキー）
@endpoint = https://（リソース名）.openai.azure.com
@api_version = 2023-05-15
@deployment_name = （モデルデプロイ時につけた`Deployment Name`）

### モデル一覧取得
GET {{endpoint}}/openai/models?api-version={{api_version}}
api-key: {{api_key}}

### モデル取得
@model-id = gpt-35-turbo-16k
GET {{endpoint}}/openai/models/{{model-id}}?api-version={{api_version}}
api-key: {{api_key}}

```

- 送信（モデルデプロイ名をURLに含めると単数取得になる）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/774cb563-e0ec-e30d-7a59-08a1cc723d2f.png)
- 受信（モデルデプロイ名を含めなかった時の応答）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/6a2ed620-796a-52df-9b34-0a3a77a9fa27.png)

これは作ったアプリ上で動的にモデルを切り替えたい時に良さそうですね。
`capabilities`をよく見ると対応APIが分かりそうなパラメータを持っていそうな感じがします。（未確認）


## 5.4. …という事で雑なAPI説明
- APIは大まかに9個ほどある様子
    1. チャット（Chat）
        - 連続した会話をする
    2. 入力候補（Completions）
        - 一問一答
        - 文章の要約や翻訳
        - ユーザー入力の予測
        - 等々…
    3. 画像生成（DALL-E、preview）
        - 2023/9時点では、East US限定
        - テキストから画像を生成する。Stable DiffusionやNovelAIっぽい？
    4. ファイル（Files、一部preview）
    5. 微調整（Fine Tunes、一部preview）
    6. モデル（Models、一部preview）
        - モデルの情報を取得する
    7. 画像（Images、一部preview）
    8. 操作イメージ（Operations Images、一部preview）
    9. 埋め込み（Embeddings、未調査）[^embeddings]
- 初心者は`チャット（Chat）`と`入力候補（Completions）`を抑えておけば良いと思います
    - この2つのAPIは、Azure OpenAI Studioでも確認できるので、こちらを活用するのがオススメです
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/3673c871-0556-2528-d1ed-d65559e42fe1.png)
    - 一応リファレンスは存在しますが、翻訳精度的[^trans]な障壁もあって私にはキツイものでしたω
        - Azure OpenAI Service の REST API リファレンス
            - https://learn.microsoft.com/ja-jp/azure/ai-services/openai/reference
                ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/a298ffae-70e1-b318-b087-3803e37f1f3c.png)
        - Azure Cognitive Services の REST API リファレンス
            - https://learn.microsoft.com/ja-jp/rest/api/cognitiveservices/
                ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/7cbd30f0-96ca-e584-a67e-5135f7fa1cf1.png)


[^trans]: `Completions`を`完了`と翻訳されたりするので、最初は「何のこっちゃ？」と思ったものです。これは訳さない方が理解できる。

[^embeddings]: 埋め込みAPI。なんだけどいまいち分かっていません…。別記事で書くか…？！本家OpenAIの方に役割っぽい情報はあるけど、一緒なのかな？！⇒ https://platform.openai.com/docs/guides/embeddings/embeddings


# 6. あとがき
すっかり長文が読めなくなり、寄る年波にはなんとやらを痛感してきた弊社のバカ野郎担当の人です。

元々興味はあったのですが、初めの一歩の障壁がものすごく高く感じたので、同じような悩みを持っている人に向けて、**スクショ大盛り**！

さらに、何らかのアプリを作りたい人に取っては、RESTリクエストの投げ方が分かればアプリへの組み込みはどうとでもなるかなと思い、**REST APIに注目**した記事になりました。

皆様のはじめの一歩に貢献できたのなら幸いです。


（2023/9/22追記）
`俺ですら`というキーワードに物言いがついたので修正しました。えっ、わざわざ修正履歴を残さなくてもいい…だと？！


# 7. 参考
- Azure OpenAI Serviceを使ってみた〜申請・利用方法〜｜クラウドテクノロジーブログ｜ソフトバンク
    - https://www.softbank.jp/biz/blog/cloud-technology/articles/202305/azure-openai-setup/
- クイック スタート - Azure OpenAI Service で GPT-35-Turbo と GPT-4 の使用を開始する
    - https://learn.microsoft.com/ja-jp/azure/ai-services/openai/chatgpt-quickstart?tabs=command-line&pivots=rest-api
- Azure OpenAI Service の REST API リファレンス
    - https://learn.microsoft.com/ja-jp/azure/ai-services/openai/reference
- Azure Cognitive Services の REST API リファレンス
    - https://learn.microsoft.com/ja-jp/rest/api/cognitiveservices/
- Embeddings - OpenAI API
    - https://platform.openai.com/docs/guides/embeddings/embeddings