ChatGPT API利用方法の簡単解説

ChatGPTのAPIがついに公開されたので、どのように利用するのか簡単にまとめました。

OpenAIアカウントとAPI Key
-----
OpenAIのAPIを利用するためにはOpenAIのアカウントが必要です。

https://openai.com/

アカウント取得後API Keyを以下から払い出してください。

https://platform.openai.com/account/api-keys

なお、各種API呼び出しは有償ですが、アカウント取得後Free trialとして期限つきのクレジットが$18くらい貰えます。試したり遊んだりする分には十分な感じです。

基本的なAPI利用法
-------
公式ガイドの通り基本的な呼び出し方は以下のように行います。API Key取得後、まずは簡単にcurlで叩いてみるのがよいでしょう。（一回スクリプトとして保存しておくと後のステップも試しやすいです）

```sh:chat.sh
curl https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "user", "content": "よく使う英語のフレーズを教えて"}
  ]
}'
```

chat/completionsエンドポイントに対して、modelとmessagesから成るjsonをBodyとしてPOSTすればOKです。modelは現時点ではgpt-3.5-turboに、messagesには入力となる対話文を設定します。

これを実行すると以下のようなjsonレスポンスが帰ってきます
```json
{
  "id": "chatcmpl-6pY7sbIBUPMDiYyEZV3B7H1gnb9Qr",
  "object": "chat.completion",
  "created": 1677743928,
  "model": "gpt-3.5-turbo-0301",
  "usage": {
    "prompt_tokens": 24,
    "completion_tokens": 229,
    "total_tokens": 253
  },
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "\n\n1. Hello! - こんにちは！\n2. How are you? - お元気ですか？\n3. Nice to meet you - お会いできて嬉しいです\n4. Thank you - ありがとうございます\n5. You're welcome - どういたしまして\n6. Excuse me - すみません（失礼ですが）\n7. I'm sorry - ごめんなさい（申し訳ありません）\n8. Please - お願いします\n9. Goodbye - さようなら\n10. Have a nice day - いい一日を！\n11. How much is it? - いくらですか？\n12. Can you help me? - 手伝っていただけますか？\n13. What's your name? - お名前は？\n14. Where are you from? - 出身はどこですか？\n15. I don't understand - わかりません"
      },
      "finish_reason": "stop",
      "index": 0
    }
  ]
}
```

choices[0]["messages"]["content"]となっている部分が、入力した対話文に後続すると推論された出力になります。

ロール
------
messages内のroleは、各文章において誰が述べたものなのかを明示するもので、system, user, assistantの３種類があります。

* system
  * 主にmessagesの冒頭に配置し、アシスタントの振る舞いを設定します
* user
  * アシスタントに対しての指示や質問を設定します。基本的には、ここの部分をAPIユーザー側として指定していきます
* assinstant
  * アシスタントからの応答（過去の）を設定します

例えば以下のようなsystem文パラメータとして送ると、assinstantロールは、「役に立つアシスタント」として振る舞おうとします。

```json
[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
]
```
ちなみにsystem, user, assistant以外のロールは指定できません。エラーになります。


コンテキストと実際の会話の続け方
-----

上記の通りmessagesに会話文の履歴を設定することで、次のassistantの推論・返答を得ます。

例えばこのようなリクエストを送信した場合、次のようなレスポンスが返ってきます。
```json:(request.messages)
[
    {"role": "system", "content": "あなたは優秀なAIアシスタントです。できるだけ簡潔に回答してください。"},
    {"role": "user", "content": "Rust言語について教えてください"}
]
```

```json:(response.choices)
{
  "message": {
    "role": "assistant",
    "content": "Rustは、システムプログラミング向けのオープンソースのプログラミング言語です。C言語と同じような低レベルの制御を可能にする一方で、メモリ安全性が強化されています。また、スレッドセーフな並列処理や高速なコンパイルが特長的です。生産性を担保しながら高速なパフォーマンスを求める場合に最適な言語として知られています。"
  }
}
```

つまり次のリクエストでは、受け取ったmessageを送信時のmessagsにappendすれば、前の文脈を考慮した自然な会話が実現できます。（モデル側には過去の文の履歴などは保存されません）

```json
[
    {"role": "system", "content": "あなたは優秀なAIアシスタントです。できるだけ簡潔に回答してください。"},
    {"role": "user", "content": "Rust言語について教えてください"},
    {"role": "assistant", "content": "Rustは、システムプログラミング向けの....",
    {"role": "user", "content": "[次の質問]"},
  }
]
```

APIを利用するアプリケーション・クライアント側でmessagesの配列を管理しておけば簡単にChatGPTのようなものが作れます。

ただし、ChatGPTのチャットのような動作にこだわる必要はなく、userやassistantの文を事前に指定したりなどの利用方法は自由です。

systemロールへの振る舞いの指定
-------

systemロールへの振る舞いの指定を工夫すればいろいろなことができます。

```json:(request.messages)
[
    {"role": "system", "content": "あなたは語尾に「にゃ」をつける猫キャラクターです。いつも丁寧に明るく説明してくれます"},
    {"role": "user", "content": "ラーメンの起源についておしえて"}
]
```

```json:(response.choices)
{
    "message": {
        "role": "assistant",
        "content": "にゃ、ラーメンの起源についてにゃ！\n\n実はラーメンの起源ははっきりとはわかっていないのにゃ。一説では中国から伝わった麺料理が、日本で発展し、今のラーメンになったと言われていますにゃ。\n\nところで、日本で最初にラーメンが登場したのは、横浜中華街だとされていますにゃ。当時は中国人労働者向けに作られたもので、塩味のスープに細い麺が入っていたそうですにゃ。\n\nまた、戦後になり、濃い目の豚骨スープが流行するようになり、その後も様々なスタイルのラーメンが次々と生まれてきましたにゃ。\n\nちなみに、全国的にもっとも有名なラーメンと言えば、とんこつラーメンが有名ですにゃ。行列ができるラーメン屋さんも多く、人気の高さがうかがえますにゃ。"
      }
}
```

ただし、systemに配置する振る舞いの指示は、モデルとしてはあまり注意を払わないため、重要な指示はuserメッセージに配置した方が良いとのことです。（もともと本家のChatGPTはそのようなやり方でロールプレイなど、いろいろなことができていますね。）

例えば、以下のような感じです。想定通りの会話ができない場合はこのようなアプローチも良いかもしれません。

```json:(request.messages)
[
    {"role": "system", "content": "チャットの会話文をシミュレーションした文章です"},
    {"role": "user", "content": "あなたは私の親友として振る舞ってください。これから2人でラフな会話をします。でははじめます。"},
    {"role": "user", "content": "次の週末旅行に行かない？"}
]
```

前のAPIと利用料金
-------
実はchat/completionsが公開される前に、text-davinci-003というモデルを利用できるAPIで同様なことは一応できていました。

https://platform.openai.com/docs/api-reference/completions

こちらは、純粋に文章の補完を推論するものでした。例えば、以下のようなテキストを丸々送って、「友達:」の先の文章として何が来るかを推定してもらうという感じです。

```
以下は友達との会話文です。
あなた: 最近どうしてたの？
友達: 古い映画を見ていたよ。
あなた: 何か面白いものを見たの？
友達:
```
このような「あなた」や「友達」のようなラベルを自分で作れば、あたかもチャットや会話文もシミュレーションできるという感じです。

今回公開されたchat/completionsAPIはmessagesやroleなど構造化されたデータを扱う点でチャットアプリの利用に特化しています。また、料金も10分の1ということです($0.002 per 1k tokens)。

その他のリクエストパラメータ
-------
APIのリファレンスは以下です。

https://platform.openai.com/docs/api-reference/chat


基本、modelとmessagesが指定されていれば動作しますが、その他のパラメータも指定できます。例えばtemperature（0-2の値）は動作の決定性を決めるパラメータで、同じ入力に対しても値が高ければ高いほど毎回異なる回答を、反対に値が低いと全く同じ回答を返します。

各種パラメータは以下のようにjsonとして指定すればOKです。
```json
{
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "user", "content": "xxxxxxx"}
  ],
  "temperature": 0.2
}
````

補足：各言語のライブラリ
----
chat/completionsのAPIはシンプルなapiを叩けばすぐ利用可能ですが、各言語でより使いやすくしたライブラリもあります。ちゃんと調べられてないですが、各々昨日あたりリリースされているみたいです。

- python
  - https://github.com/openai/openai-python/releases/tag/v0.27.0
- node.js
  - https://github.com/openai/openai-node/releases/tag/v3.2.0
 
実際のアプリケーションを開発するときはこのようなライブラリを使うとより良いかもしれません。

参考
-----
- 公式ブログ
  - https://openai.com/blog/introducing-chatgpt-and-whisper-apis
- 利用ガイド
  - https://platform.openai.com/docs/guides/chat
- API Reference
  - https://platform.openai.com/docs/api-reference/chat