OpenAI Assistants APIを試す
昨日OpenAI DevDayで発表されたAssistants APIにフォーカスを当てて実際に試してみる。
発表された内容は下記にまとめたので、こちらも参考にして欲しい。
Playgroundでの基本的な使い方
まずはOpenAI PlatformのAssistantsにアクセスしてログインしてみる。
視覚的に理解できるのはPlaygroundのありがたいところだ。
アクセスすると下記のような画面がある。
作れと言わんばかりに+Createのボタンがある。
ボタンを押すとアシスタント作成用のダイアログが開く。
まずはプレーンなアシスタントを作ってみる。
下記のように設定してSaveで保存する。
Assistantsの一覧にNameに入力した「Helpful Assistant」が表示されれば作成できたことになる。
表示されたHelpful Assistantを選択すると、作成したAssistantを編集できるとともに、右上にTestのリンクが表示されている。こちらをクリックするとこのアシスタントをPlaygroundでテストできる。もちろん、左上のナビゲーションメニューのPlaygroundからも行ける。
画面はこんな感じ。
アシスタントを編集しながら試せるのはさすがPlaygroundといったところ。
右下の'Enter your message…'から作成したアシスタントと話すことができる。
試しに何ができるか聞いてみる。
期待通りの回答が返ってくる。
続けてFunctions, Code Interpreter, Retrievalも試してみよう。
Functions (Playground)
左下のToolsにあるFunctions横の+AddからExamplesに登録されているFunctionを2つとも登録してみる。
これで何ができるか聞いてみると天気予報の取得や株価の確認ができると返ってきた!これだけで何ができるか判断できるのか!Instructionsには天気や株価については書いてないので、関数から判断されているようだ。
試しに東京の天気を聞いてみる。
…ん?
関数の下の ↪ Submit output e.g. {success: "true"} に入力カーソルが求められている。出力結果をJSONで送信しろと?
あ、関数を定義してないから結果を自分で入力する必要があるのね。。。
これはFunction Callingを実装したことある人じゃないと気づけないやつだ。。。
試しに{success: "true"}を送信してみたところ、成功したけど天気の情報は取得できなかったとの説明が返ってきた。そらそうだわな、天気の情報が入った無いんだから。。。
今度は{success: "true", location: "Tokyo", weather: "晴れ", min_temperture: 10, max_temperture: 20}を出力結果として入力してみた。(日本語が変だがこれが正しい。。。)
なるほど、いい感じに解釈してくれた。
次はCode Interpreterいってみよう。
Code Interpreter (Playground)
設定はこんな感じ。Code Interpreterのみ有効にしている。
何ができるか聞いてみる。Pythonで分析ができると答えてくれる。
一応確認してみるが、インターネットには接続できない。
とりあえずネット接続不要なものを実装させてみる。
光が1秒で地球を何周できるか計算するプログラムを実装して。
……速い!
あ、光がじゃなくてCode Interpreterの処理の話です。
code_interpreterの横のカッコ内をクリックすると……
下記のようにプログラムが表示できる。
素晴らしい。感動できる!
これでCode Interpreterが実装できるということか!
画面を広げると、右上にLogsが表示される。
ここをクリックすると、どんな挙動になっているか確認できる。
開いたログにはめっちゃThreads APIを呼んでいるログがある。これのおかげでトークンを気にせず無限に会話ができるということらしい。意識しないでできるのは素晴らしい。
無論、Threads APIのRequestとResponseを確認できる。まあ、トラブル対応くらいしか見ない気がするけど。
そういえば、昨日ナビゲーションメニューにあったThreadsの項目がなくなっていた。URLに直接アクセスしても見れなかったので、なんか不具合でもあって閉じたのだろう。
Retrieval (Playground)
今度はRetrieval。日本語に訳すと検索とか回収とかなんだけど、しっくりこないのでRetrievalと呼ぶのが良さそう。
できることはアップロードしたファイルを使用して情報を検索したりドキュメントを開いたり、要約したり翻訳したり質問に答えてくれる。この半年で似たようなサービスを作ってた会社がたくさんあったことを思い出す。。。
予めOpenAIの公式ドキュメントの、Assistants APIの内容をアップロードしておいた。これについて聞いてみる。
……英語かいな。。
日本語とサンプルコードの出力をお願いしてみる。
うーん、ちょっと違うんだよなー。。。
今回はそれぞれ別々に試してみたけど、すべてを有効にしてまとめて実行することもできる。
最新版のChatGPTとほとんど同じ機能が実装できるじゃないか。。。
Pythonで実装する
実際にAssistants APIを組み込むには公式ドキュメントが非常に役に立つ。
先程PDFにして読み込ませてたやつだ。
完成形のPythonコード
公式ドキュメントを元に作成したpythonファイルが下記のapp.pyだ。
無論、本番これで運用ができるわけではない。
# app.py
import os
import json
import codecs
import time
from openai import OpenAI
from dotenv import load_dotenv
# .envファイルから環境変数を読み込む
load_dotenv()
# 環境設定に値がない場合はデフォルト値を設定
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4-1106-preview")
client = OpenAI()
# ステップ 1: アシスタントを作成する
assistant = client.beta.assistants.create(
name="数学教師",
instructions="あなたは個人の数学の先生です。数学の質問に答えるためにコードを書いて実行してください。",
tools=[{"type": "code_interpreter"}],
model=OPENAI_MODEL
)
# ステップ 2: スレッドを作成する
thread = client.beta.threads.create()
# ステップ 3: スレッドにメッセージを追加する
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content="`3x + 11 = 14`の方程式を解きたいです。助けてください。"
)
message_str = json.dumps(message.dict(), indent=2)
print("### Step 2: Create a Thread ###")
print(codecs.decode(message_str, 'unicode-escape'))
# ステップ 4: アシスタントを実行する
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id,
instructions="ユーザーを山田花子として呼んでください。ユーザーはプレミアムアカウントを持っています。",
)
# ステップ 5: アシスタントの応答を表示する
for i in range(3):
time.sleep(1)
run = client.beta.threads.runs.retrieve(
thread_id=thread.id,
run_id=run.id
)
messages = client.beta.threads.messages.list(
thread_id=thread.id
)
messages_str = json.dumps(messages.dict(), indent=2)
print(f"### Step 5: Display the Assistant's Response ( {i + 1} ) ###")
print(codecs.decode(messages_str, 'unicode-escape'))
とりあえず動くようになったのが上記のとおり。
OPENAI_API_KEYを.envか環境変数に設定してから実行してください。
実行方法は下記の通り。
$ python app.py
実行すると下記が出力される。
### Step 2: Create a Thread ###
{
"id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"assistant_id": null,
"content": [
{
"text": {
"annotations": [],
"value": "`3x + 11 = 14`の方程式を解きたいです。助けてください。"
},
"type": "text"
}
],
"created_at": 1699436237,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "user",
"run_id": null,
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
}
### Step 5: Display the Assistant's Response ( 1 ) ###
{
"data": [
{
"id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"assistant_id": "asst_raNPQqifFleSrGrqos2kCLey",
"content": [
{
"text": {
"annotations": [],
"value": "もちろんですね。この方程式を解くために、まずは変数xについて整理を行います。それでは、計算して解を見つけましょう。"
},
"type": "text"
}
],
"created_at": 1699436238,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "assistant",
"run_id": "run_HZgA4eF3rXq5ocONuKkEwvUf",
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
},
{
"id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"assistant_id": null,
"content": [
{
"text": {
"annotations": [],
"value": "`3x + 11 = 14`の方程式を解きたいです。助けてください。"
},
"type": "text"
}
],
"created_at": 1699436237,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "user",
"run_id": null,
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
}
],
"object": "list",
"first_id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"last_id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"has_more": false
}
### Step 5: Display the Assistant's Response ( 2 ) ###
{
"data": [
{
"id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"assistant_id": "asst_raNPQqifFleSrGrqos2kCLey",
"content": [
{
"text": {
"annotations": [],
"value": "もちろんですね。この方程式を解くために、まずは変数xについて整理を行います。それでは、計算して解を見つけましょう。"
},
"type": "text"
}
],
"created_at": 1699436238,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "assistant",
"run_id": "run_HZgA4eF3rXq5ocONuKkEwvUf",
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
},
{
"id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"assistant_id": null,
"content": [
{
"text": {
"annotations": [],
"value": "`3x + 11 = 14`の方程式を解きたいです。助けてください。"
},
"type": "text"
}
],
"created_at": 1699436237,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "user",
"run_id": null,
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
}
],
"object": "list",
"first_id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"last_id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"has_more": false
}
### Step 5: Display the Assistant's Response ( 3 ) ###
{
"data": [
{
"id": "msg_HujM5BKzdUYgXT0hiOshXpfi",
"assistant_id": "asst_raNPQqifFleSrGrqos2kCLey",
"content": [
{
"text": {
"annotations": [],
"value": "方程式`3x + 11 = 14`の解は、x = 1 ですね。"
},
"type": "text"
}
],
"created_at": 1699436241,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "assistant",
"run_id": "run_HZgA4eF3rXq5ocONuKkEwvUf",
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
},
{
"id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"assistant_id": "asst_raNPQqifFleSrGrqos2kCLey",
"content": [
{
"text": {
"annotations": [],
"value": "もちろんですね。この方程式を解くために、まずは変数xについて整理を行います。それでは、計算して解を見つけましょう。"
},
"type": "text"
}
],
"created_at": 1699436238,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "assistant",
"run_id": "run_HZgA4eF3rXq5ocONuKkEwvUf",
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
},
{
"id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"assistant_id": null,
"content": [
{
"text": {
"annotations": [],
"value": "`3x + 11 = 14`の方程式を解きたいです。助けてください。"
},
"type": "text"
}
],
"created_at": 1699436237,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "user",
"run_id": null,
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
}
],
"object": "list",
"first_id": "msg_HujM5BKzdUYgXT0hiOshXpfi",
"last_id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"has_more": false
}
順を追って説明しよう。
まず下記は事前準備と考えて欲しい。
説明は割愛する。
import os
import json
import codecs
import time
from openai import OpenAI
from dotenv import load_dotenv
# .envファイルから環境変数を読み込む
load_dotenv()
# 環境設定に値がない場合はデフォルト値を設定
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4-1106-preview")
client = OpenAI()
ステップ 1: アシスタントを作成する
# ステップ 1: アシスタントを作成する
assistant = client.beta.assistants.create(
name="数学教師",
instructions="あなたは個人の数学の先生です。数学の質問に答えるためにコードを書いて実行してください。",
tools=[{"type": "code_interpreter"}],
model=OPENAI_MODEL
)
ちなみにここを何度も実行すると、Playground上で確認できる通り、たくさんアシスタントを作ってしまう。同じアシスタントは大量に作る必要はないので必要に応じて削除しておこう。
ステップ 2: スレッドを作成する
スレッドの作成。これは1ユーザのひとつの会話という単位で見ておいたほうが良さそうだ。
# ステップ 2: スレッドを作成する
thread = client.beta.threads.create()
ステップ 3: スレッドにメッセージを追加する
スレッドを追加しただけだと会話をしていないので会話を追加する。
しかしまだアシスタントからの返事は来てない。
# ステップ 3: スレッドにメッセージを追加する
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content="`3x + 11 = 14`の方程式を解きたいです。助けてください。"
)
message_str = json.dumps(message.dict(), indent=2)
print("### Step 2: Create a Thread ###")
print(codecs.decode(message_str, 'unicode-escape'))
「Step 2: Create a Thread」ってログ出力しているけど、ステップ3が正しいじゃないか。。。いま気づいた。とりあえずさっさと公開して、修正は気が向いたら後日。
レスポンスはこんな感じ。
### Step 2: Create a Thread ###
{
"id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"assistant_id": null,
"content": [
{
"text": {
"annotations": [],
"value": "`3x + 11 = 14`の方程式を解きたいです。助けてください。"
},
"type": "text"
}
],
"created_at": 1699436237,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "user",
"run_id": null,
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
}
ステップ 4: アシスタントを実行する
ここでアシスタントのリクエストを投げているようだ。
この時点で返信はまだ返ってきていない模様。
# ステップ 4: アシスタントを実行する
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id,
instructions="ユーザーを山田花子として呼んでください。ユーザーはプレミアムアカウントを持っています。",
)
ステップ 5: アシスタントの応答を表示する
応答の表示処理でうまくいかず四苦八苦したのだが、Playgroundの挙動を思い出して、sleepで処理を止めながら何度か表示していたらうまくいった。
そういえば何度か返信を分けていたし、Threads APIを何度も呼んでいた。
# ステップ 5: アシスタントの応答を表示する
for i in range(3):
time.sleep(1)
run = client.beta.threads.runs.retrieve(
thread_id=thread.id,
run_id=run.id
)
messages = client.beta.threads.messages.list(
thread_id=thread.id
)
messages_str = json.dumps(messages.dict(), indent=2)
print(f"### Step 5: Display the Assistant's Response ( {i + 1} ) ###")
print(codecs.decode(messages_str, 'unicode-escape'))
レスポンスを見ると1回目は"もちろんですね。この方程式を解くために、まずは変数xについて整理を行います。それでは、計算して解を見つけましょう。"と返事をしている。
2回目は変化がなく、 3回目は"方程式`3x + 11 = 14`の解は、x = 1 ですね。"と返信をくれた。
これらのメッセージが返ってくるタイミングはその時々によって違うので何かしらステータスを確認しながら出力することになると思うんだが、そこまで理解することができなかった。
### Step 5: Display the Assistant's Response ( 1 ) ###
{
"data": [
{
"id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"assistant_id": "asst_raNPQqifFleSrGrqos2kCLey",
"content": [
{
"text": {
"annotations": [],
"value": "もちろんですね。この方程式を解くために、まずは変数xについて整理を行います。それでは、計算して解を見つけましょう。"
},
"type": "text"
}
],
"created_at": 1699436238,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "assistant",
"run_id": "run_HZgA4eF3rXq5ocONuKkEwvUf",
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
},
{
"id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"assistant_id": null,
"content": [
{
"text": {
"annotations": [],
"value": "`3x + 11 = 14`の方程式を解きたいです。助けてください。"
},
"type": "text"
}
],
"created_at": 1699436237,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "user",
"run_id": null,
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
}
],
"object": "list",
"first_id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"last_id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"has_more": false
}
### Step 5: Display the Assistant's Response ( 2 ) ###
{
"data": [
{
"id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"assistant_id": "asst_raNPQqifFleSrGrqos2kCLey",
"content": [
{
"text": {
"annotations": [],
"value": "もちろんですね。この方程式を解くために、まずは変数xについて整理を行います。それでは、計算して解を見つけましょう。"
},
"type": "text"
}
],
"created_at": 1699436238,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "assistant",
"run_id": "run_HZgA4eF3rXq5ocONuKkEwvUf",
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
},
{
"id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"assistant_id": null,
"content": [
{
"text": {
"annotations": [],
"value": "`3x + 11 = 14`の方程式を解きたいです。助けてください。"
},
"type": "text"
}
],
"created_at": 1699436237,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "user",
"run_id": null,
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
}
],
"object": "list",
"first_id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"last_id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"has_more": false
}
### Step 5: Display the Assistant's Response ( 3 ) ###
{
"data": [
{
"id": "msg_HujM5BKzdUYgXT0hiOshXpfi",
"assistant_id": "asst_raNPQqifFleSrGrqos2kCLey",
"content": [
{
"text": {
"annotations": [],
"value": "方程式`3x + 11 = 14`の解は、x = 1 ですね。"
},
"type": "text"
}
],
"created_at": 1699436241,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "assistant",
"run_id": "run_HZgA4eF3rXq5ocONuKkEwvUf",
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
},
{
"id": "msg_gkxwl27PvcrbVOCYBRPmy01b",
"assistant_id": "asst_raNPQqifFleSrGrqos2kCLey",
"content": [
{
"text": {
"annotations": [],
"value": "もちろんですね。この方程式を解くために、まずは変数xについて整理を行います。それでは、計算して解を見つけましょう。"
},
"type": "text"
}
],
"created_at": 1699436238,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "assistant",
"run_id": "run_HZgA4eF3rXq5ocONuKkEwvUf",
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
},
{
"id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"assistant_id": null,
"content": [
{
"text": {
"annotations": [],
"value": "`3x + 11 = 14`の方程式を解きたいです。助けてください。"
},
"type": "text"
}
],
"created_at": 1699436237,
"file_ids": [],
"metadata": {},
"object": "thread.message",
"role": "user",
"run_id": null,
"thread_id": "thread_rWhxXHlvGUAusirWmMi5hvXH"
}
],
"object": "list",
"first_id": "msg_HujM5BKzdUYgXT0hiOshXpfi",
"last_id": "msg_yi2N0T5mYLuXQu2lVb5XrbK9",
"has_more": false
}
まとめ
ChatGPTですごいと感じていたいくつもの機能がこのAssistants APIで実装されていることがわかった。そしてそれを自身で開発ができる。
ソースコードでFunction Calling, Code Interpreter, Retrievalのそれぞれも実装してみたかったが、ちょっと時間がかかりそうだったので今回は見送った。
OpenAIはきっと、この凄さを真っ先に伝えたかったような気もするけど、ニュースとして伝えても伝わりきらないと思ったんだろう。GPT-4 Turboの方が分かりやすいもんな。
私もニュースを見ただけだと「ん?すごそうだけどどういうことだ?」となってしまったので、英断だと思う。
しかし、Assistants APIは開発者にとっては本当に素晴らしい機能だ。
LangChainなどのオープンソースとの棲み分けも気になるところだが、公式が開発しやすい形で提供してくれるのはありがたいことだ。
今後の動向も期待したい。
ちなみにGPTsとAll Toolsはまだですか?
早く使いたい。。。
改めてこちらもよろしく。
この記事が気に入ったらサポートをしてみませんか?