5分で学ぶOpenAI APIハンズオン
はじめに
はじめまして。新卒エンジニアのwinnieです。
この度めでたく、社内初のLT大会を主催できることになりました!
自分もLTをするのでせっかくなら、という訳で話す内容を記事にしてみます。ちなみに当初は発表10分を想定していたのですが、参加者の希望により5分になりました。
倍速で喋らないと… 😱
OpenAIとは?
OpenAIは、ChatGPTを提供する企業です[2]。
GPTをはじめとした、さまざまなモデル(GPT-4 / DALL•E 2 / Whisper など)を開発しています。これらのモデルには、API経由でアクセスできます。
はじめてのOpenAI API
Playgroundを試す
OpenAIのサイトでは、簡単にAPIを試すためのプラットフォームが提供されています[3]。まずは、こちらのページを開いてください。ページを開いたら、早速APIを試してみましょう!
シンプルなやりとり
まずは、シンプルなやりとりをしてみましょう。
-
USER
に下記を入力して送信する。 - 文章の続きが
ASSISTANT
に出力される。
今日は晴れています。空の色は // 青いです。
このように、 USER
にプロンプトを入力することで、 ASSISTANT
から文章の続きを出力させることができます。
モデルに「設定」を与える
次に、第三者視点である SYSTEM
を使ってみましょう。
-
ASSISTANT
のメッセージを削除する。 -
SYSTEM
に下記を入力して再度送信する。
一文で答えてください。今は夕暮れ時です。 // オレンジ色に染まっています。
このように、 SYSTEM
には状況設定などを伝えることができます。
会話を続ける
では、ChatGPTのような対話的な生成をしてみましょう。
-
USER
に下記を入力して送信する。
後ろの空は // 徐々に暗くなっています。
以前に対話した情報を残しておくことで、対話的な文章生成をすることができました。
コードを眺める
続いて、今までの対話をコードで見てみます。
- 右上の “View Code” をクリックする。
- “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にリクエストしてみましょう。
-
messages
配列の最後の要素を削除する。 - リクエストを送信する。
{
"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
}'
{
"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とは、モデルから関数を呼び出せる機能のことです。
最新の情報を出力してみる
まずは、明日の最高気温を出力してみましょう。
- 以下のプロンプトをメッセージとして渡す。
- リクエストを送信する。
今日の最高気温は // 申し訳ありませんが…
リクエスト
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にリクエストしてみます。
{
"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
が生成されました。なお、このときの content
は null
になっています。
"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
としてメッセージに組み込みます。
get_max_temperature(35.6895, 139.6917) # 30.3
{
"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)
返り値に続く文章が生成されました。
{
"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分で喋るの無理じゃん 😇
Discussion