🍩

5分で学ぶOpenAI APIハンズオン

2023/10/02に公開

はじめに

はじめまして。新卒エンジニアのwinnieです。
この度めでたく、社内初のLT大会を主催できることになりました!

https://speakerdeck.com/yjn279/5fen-dexue-buopenai-api-hanzuon

自分もLTをするのでせっかくなら、という訳で話す内容を記事にしてみます。ちなみに当初は発表10分を想定していたのですが、参加者の希望により5分になりました。

倍速で喋らないと… 😱

https://note.com/libproc/n/nc777ee0b3bf0

OpenAIとは?

OpenAIは、ChatGPTを提供する企業です[2]

GPTをはじめとした、さまざまなモデル(GPT-4 / DALL•E 2 / Whisper など)を開発しています。これらのモデルには、API経由でアクセスできます。

はじめてのOpenAI API

Playgroundを試す

OpenAIのサイトでは、簡単にAPIを試すためのプラットフォームが提供されています[3]。まずは、こちらのページを開いてください。ページを開いたら、早速APIを試してみましょう!

https://platform.openai.com/playground

シンプルなやりとり

まずは、シンプルなやりとりをしてみましょう。

  1. USER に下記を入力して送信する。
  2. 文章の続きが ASSISTANT に出力される。
今日は晴れています。空の色は  // 青いです。

このように、 USER にプロンプトを入力することで、 ASSISTANT から文章の続きを出力させることができます。

モデルに「設定」を与える

次に、第三者視点である SYSTEM を使ってみましょう。

  1. ASSISTANT のメッセージを削除する。
  2. SYSTEM に下記を入力して再度送信する。
一文で答えてください。今は夕暮れ時です。  // オレンジ色に染まっています。

このように、 SYSTEM には状況設定などを伝えることができます。

会話を続ける

では、ChatGPTのような対話的な生成をしてみましょう。

  1. USER に下記を入力して送信する。
後ろの空は  // 徐々に暗くなっています。

以前に対話した情報を残しておくことで、対話的な文章生成をすることができました。

コードを眺める

続いて、今までの対話をコードで見てみます。

  1. 右上の “View Code” をクリックする。
  2. “curl” を選択する。

messages の配列に注目してください。ここでは、先ほどの対話を配列として渡しているだけです。このように、メッセージの配列(とモデル名)をJSONとして送信するだけで、APIにリクエストを飛ばすことができます。

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {
      "role": "system",
      "content": "一文で答えてください。今は夕暮れ時です。"
    },
    {
      "role": "user",
      "content": "今日は晴れています。空の色は"
    },
    {
      "role": "assistant",
      "content": "オレンジ色に染まっています。"
    },
    {
      "role": "user",
      "content": "後ろの空は"
    },
    {
      "role": "assistant",
      "content": "徐々に暗くなっています。"
    }
  ]
}
コード
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
  "model": "gpt-3.5-turbo",
  "messages": [
    {
      "role": "system",
      "content": "一文で答えてください。今は夕暮れ時です。"
    },
    {
      "role": "user",
      "content": "今日は晴れています。空の色は"
    },
    {
      "role": "assistant",
      "content": "オレンジ色に染まっています。"
    },
    {
      "role": "user",
      "content": "後ろの空は"
    },
    {
      "role": "assistant",
      "content": "徐々に暗くなっています。"
    }
  ],
  "temperature": 0,
  "max_tokens": 256,
  "top_p": 1,
  "frequency_penalty": 0,
  "presence_penalty": 0
}'

APIにリクエストする

では実際に、APIにリクエストしてみましょう。

  1. messages 配列の最後の要素を削除する。
  2. リクエストを送信する。
request.json
{
  "messages": [
    {
      "role": "system",
      "content": "一文で答えてください。今は夕暮れ時です。"
    },
    {
      "role": "user",
      "content": "今日は晴れです。空の色は"
    },
    {
      "role": "assistant",
      "content": "オレンジ色に染まっています。"
    },
    {
      "role": "user",
      "content": "後ろの空は"
    }
  ]
}
リクエスト
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
  "model": "gpt-3.5-turbo",
  "messages": [
    {
      "role": "system",
      "content": "一文で答えてください。今は夕暮れ時です。"
    },
    {
      "role": "user",
      "content": "今日は晴れです。空の色は"
    },
    {
      "role": "assistant",
      "content": "オレンジ色に染まっています。"
    },
    {
      "role": "user",
      "content": "後ろの空は"
    }
  ],
  "temperature": 1,
  "max_tokens": 256,
  "top_p": 1,
  "frequency_penalty": 0,
  "presence_penalty": 0
}'
response.json
{
  "message": {
    "role": "assistant",
    "content": "徐々に暗くなりつつあります。"
  }
}
レスポンス
{
  "id": "chatcmpl-80hTiakDk7iP3oKfowmFeUf7R1PXe",
  "object": "chat.completion",
  "created": 1695177822,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "徐々に暗くなりつつあります。"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 67,
    "completion_tokens": 15,
    "total_tokens": 82
  }
}

Playgroundと同様に、文章の続きを生成することができました!

Function Calling

Function Callingとは、モデルから関数を呼び出せる機能のことです。

最新の情報を出力してみる

まずは、明日の最高気温を出力してみましょう。

  1. 以下のプロンプトをメッセージとして渡す。
  2. リクエストを送信する。
今日の最高気温は  // 申し訳ありませんが…
リクエスト
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
  "model": "gpt-3.5-turbo",
  "messages": [
    {
      "role": "user",
      "content": "今日の最高気温は"
    }
  ],
  "temperature": 0,
  "max_tokens": 256,
  "top_p": 1,
  "frequency_penalty": 0,
  "presence_penalty": 0
}'
レスポンス
{
  "id": "chatcmpl-80lbbV7Rw5N11YRsJjmpC31VO05SO",
  "object": "chat.completion",
  "created": 1695193687,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "申し訳ありませんが、私は情報を提供することができません。最高気温は地域や時期によって異なるため、具体的な場所や日付を教えていただければ、お手伝いできるかもしれません。"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 16,
    "completion_tokens": 86,
    "total_tokens": 102
  }
}

できません。モデルは最新の情報を学習していないからです。

自作関数を渡す

これは、Function Callingの機能で実現できます。気温をインターネットから取得する関数を実装し[4]、Function Callingで呼び出せば良いのです。

# 実装した関数
get_max_temperature(35.6895, 139.6917)  # 30.3
コード
import json
import urllib

def get_max_temperature(latitude, longitude):
    """緯度と経度を受け取り、その地点の最高気温を返す。"""
    
    # パラメータ
    URL = "https://api.open-meteo.com/v1/forecast?"
    query = urllib.parse.urlencode({
        "latitude": latitude,
        "longitude": longitude,
        "hourly": "temperature_2m",
    })
    
    # リクエスト
    req = urllib.request.Request(URL + query)
    with urllib.request.urlopen(req) as res:
        body = json.load(res)
        temperature_list = body["hourly"]["temperature_2m"]
    
    return max(temperature_list)

functions パラメータに自作した関数を渡し、再度APIにリクエストしてみます。

request.json
{
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "user", "content": "今日の最高気温は"},
  ],
  // 実装した関数を渡す
  "functions": [
    {
      "name": "get_max_temperature",
      "description": "緯度と経度を受け取り、その地点の最高気温を返す。",
      "parameters": {
        "type": "object",
        "properties": {
          "latitude": {
            "type": "number",
            "description": "最高気温を取得する地点の緯度"
          },
          "longitude": {
            "type": "number",
            "description": "最高気温を取得する地点の経度"
          }
        },
        "required": ["latitude", "longitude"]
      }
    }
  ]
}
リクエスト
import json
import urllib

# パラメータ
URL = "https://api.openai.com/v1/chat/completions"

headers = {
    "content-type": "application/json",
    "Authorization": f"Bearer {OPENAI_API_KEY}",
}

data = json.dumps({
    "model": "gpt-3.5-turbo",
    "messages": [
        {"role": "user", "content": "今日の最高気温は"},
    ],
    "functions": [
        {
            # 実装した関数を渡す
            "name": "get_max_temperature",
            "description": "緯度と経度を受け取り、その地点の最高気温を返す。",
            "parameters": {
                "type": "object",
                "properties": {
                    "latitude": {
                        "type": "number",
                        "description": "最高気温を取得する地点の緯度",
                    },
                    "longitude": {
                        "type": "number",
                        "description": "最高気温を取得する地点の経度",
                    },
                },
                "required": ["latitude", "longitude"],
            },
        },
    ],
    "temperature": 0,
    "max_tokens": 256,
    "top_p": 1,
    "frequency_penalty": 0,
    "presence_penalty": 0,
}).encode()

# リクエスト
req = urllib.request.Request(URL, data, headers)
with urllib.request.urlopen(req) as res:
    body = json.load(res)
    pprint(body)

関数を呼び出すための引数 arguments が生成されました。なお、このときの contentnull になっています。

response.json
"message": {
  "content": null,
  "function_call": {
    "arguments": {
      "latitude": 35.6895,
      "longitude": 139.6917
    },
    "name": "get_max_temperature"
  },
  "role": "assistant"
}
レスポンス
{
  "choices": [
    {
      "finish_reason": "function_call",
      "index": 0,
      "message": {
        "content": null,
        "function_call": {
          "arguments": {
            "latitude": 35.6895,
            "longitude": 139.6917
          },
          "name": "get_max_temperature"
        },
        "role": "assistant"
      }
    }
  ],
  "created": 1695204618,
  "id": "chatcmpl-80oRugzV0CMDStAzjYVwbAaXaiIf1",
  "model": "gpt-3.5-turbo-0613",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 29,
    "prompt_tokens": 117,
    "total_tokens": 146
  }
}

もう一度試す

この引数を使い、再度気温を出力してみましょう。まずは引数を関数に渡し、その返り値を FUNCTION としてメッセージに組み込みます。

request.py
get_max_temperature(35.6895, 139.6917)  # 30.3
request.json
{
  "messages": [
    {
      "role": "user",
      "content": "今日の最高気温は"
    },
    {
      "role": "function",
      "name": "get_max_temperature",
      "content": 30.3  // 関数の返り値
    }
  ]
}
リクエスト
# パラメータ
URL = "https://api.openai.com/v1/chat/completions"

headers = {
    "content-type": "application/json",
    "Authorization": f"Bearer {OPENAI_API_KEY}",
}

data = json.dumps({
    "model": "gpt-3.5-turbo",
    "messages": [
        {
            "role": "user",
            "content": "今日の最高気温は",
        },
        {
            "role": "function",
            "name": "get_max_temperature",
            "content": f"{get_max_temperature(35.6895, 139.6917)}",  # 実装した関数
        },
    ],
    "temperature": 0,
    "max_tokens": 256,
    "top_p": 1,
    "frequency_penalty": 0,
    "presence_penalty": 0,
}).encode()

# リクエスト
req = urllib.request.Request(URL, data, headers)
with urllib.request.urlopen(req) as res:
    body = json.load(res)
    print(body)

返り値に続く文章が生成されました。

response.json
{
  "message": {
    "content": "度です。",
    "role": "assistant"
  }
}
レスポンス
{
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "度です。",
        "role": "assistant"
      }
    }
  ],
 "created": 1695214394,
 "id": "chatcmpl-80qzaPCDwtHlt6lDOrodBKj2bCVbi",
 "model": "gpt-3.5-turbo-0613",
 "object": "chat.completion",
 "usage": {
    "completion_tokens": 3,
    "prompt_tokens": 25,
    "total_tokens": 28
  }
}

ここまでの対話を繋げて文章にすると、以下のようになります。

今日の最高気温は30.3度です。

無事、最高気温を出力することができましたね!

おわりに

今回は基本的なChat APIに加えて、Function Callingの機能にも触れたハンズオンを記事にしました。Function Callingは少しだけややこしいですが、使いこなせればかなり実現できることが広がります。ぜひ理解してみてください。

てか5分で喋るの無理じゃん 😇

脚注
  1. [超初心者向け] ChatGPT(OpenAI)のAPI key取得手順|TodoONada株式会社 ↩︎

  2. OpenAI ↩︎

  3. Playground - OpenAI API ↩︎

  4. 🌤️ Free Open-Source Weather API | Open-Meteo.com ↩︎

GitHubで編集を提案
株式会社アクティブコア

Discussion