🙆‍♀️

[概要編]OpenAI GPTsのAPI版、AssistantsAPIの仕様を読んでいく

2023/12/16に公開

はじめに

ChatGPTの新機能GPTsが出て1か月ほど経ちました。
GPTsによって個別事案にカスタマイズされたGPTが様々な方が公開されています。
実はGPTsの発表と同時にGPTsを作るAPIも公開されていました。

それが今回仕様を確認するAssistants APIです。
※思いのほか長くなってしまったので今回は概要ページで区切ります。

Assistants APIとは?

前述のとおり、GPTsを作るAPIです。
GPTsを作るだけでなく、変更や削除もできます。
作成したGPTsを用いて会話も可能なので、GPTsでできることは一通り出来ると思います。
※APIではGPTsの事をAssistantと呼ぶため、以降はAssistant(またはアシスタント)と表記します。

Assistants APIはOpenAIが提供している公式のAPIです。
まだベータ版の扱いですので、今後APIの仕様が大きく変わる可能性があります。

Assistants APIの概要

https://platform.openai.com/docs/assistants/overview

Assistants APIを使用すると、自身のアプリケーション内にAIアシスタントを構築することができます。
アシスタントはユーザからの指示(instructions)に従い、モデル(models)、ツール(tools)、知識(knowledge)を活用してユーザ(user)の問い合わせに応答します。

APIは現在、コードインタープリター、検索、関数呼び出しの3種類のツールをサポートしています。将来的には、OpenAIが構築したツールをリリースする予定のようなので、もっと使いやすくなりそうです。

Assistants APIの機能を知るには、以下の方法があります。

  • Assistantsプレイグラウンドを使用して試してみる
  • APIガイドに沿って段階的な統合を構築する

アシスタントAPI の一般的な統合には大まかな流れです。

  1. API でアシスタントを作成するには、カスタム命令を定義し、モデルを選択します。役立つ場合は、コードインタープリター、取得、関数呼び出しなどのツールを有効にします。
  2. ユーザーが会話を開始するときにスレッドを作成します。
  3. ユーザーが質問するときにスレッドにメッセージを追加します。
  4. スレッド上でアシスタントを実行して、応答をトリガーします。これにより、関連するツールが自動的に呼び出されます。

用語を整理すると以下の通りです。

  • カスタム命令:Instructionsで指示を与えるテキスト
  • モデル:言語モデル(gpt-3.5やgpt-4.0など)
  • コードインタープリター:そのままCode interpreterでPythonによるコードで色々できます。
  • 検索:英語だとRetrievalですが、要はWebブラウジング機能です。
  • 関数呼び出し:Functionsを用いた独自関数の埋め込み
  • スレッド:ChatGPTでいうところの1つのチャット欄です。
  • メッセージ:チャット欄に送信する質問や指示などのテキストです。
  • 応答をトリガー:

検索Retrievalについては、分かりづらいので、以降はRetrievalか「Webブラウジング」と呼んでいきます。

Assistantsプレイグラウンド

Assistants APIの機能を試せる実験場です。
サインインしないと使えません。

https://platform.openai.com/playground?mode=assistant

軽く触ってみるとGPTsとの違いがいくつか見えてきます。

  • 言語モデルを選べます。
  • 言語モデルによって検索が使える場合と使えない場合があります。
    gpt-4は使えませんが、gpt-4-1106-previewでは使用可など
  • DALL·Eとの連携はできなそう。GPTsオリジナルの統合なのかもしれません。
    DALL·EにはDALL·EのAPIがあるので、APIで考えれば当然といえば当然ですね。

Assistants APIの構築

ガイドに沿って実際に構築してみます。

1. アシスタントの作成

アシスタントは、次のようないくつかのパラメータを使用してユーザーのメッセージに応答するように構成できるエンティティを表します。

指示Instructions: アシスタントとモデルがどのように動作または応答するかを与えます。役割であったり、ユーザからのメッセージをどう解釈してどのように出力するかなど、肝になる部分です。
モデルModel: 微調整されたモデルを含む、任意の GPT-3.5 または GPT-4 モデルを指定できます。
Webブラウジング機能を使用するにはgpt-3.5-turbo-1106gpt-4-1106-previewのモデルを指定する必要があります。
ツールTools: コードインタープリターとWebブラウジングが使えます。
関数Functions: API を使用すると、関数呼び出し機能[1]と同様の動作を持つカスタム関数シグネチャを定義できます。

以下の例では、コードインタープリターツールを有効にして、数学の個人教師であるアシスタントを作成しています。
以降の実行はcurlコマンドで実施していますが、概要ページでは、pythonとnode.jsのサンプルもあるので、そちらの言語が得意な方は切り替えて確認するのが良いでしょう。

アシスタント作成API実行

curl "https://api.openai.com/v1/assistants" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
    "instructions": "You are a personal math tutor. Write and run code to answer math questions.",
    "name": "Math Tutor",
    "tools": [{"type": "code_interpreter"}],
    "model": "gpt-4"
  }'

レスポンス

{
  "id": "asst_qSAtIoQ1iaq5JeWYF7ifcWCk",
  "object": "assistant",
  "created_at": 1702189369,
  "name": "Math Tutor",
  "description": null,
  "model": "gpt-4",
  "instructions": "You are a personal math tutor. Write and run code to answer math questions.",
  "tools": [
    {
      "type": "code_interpreter"
    }
  ],
  "file_ids": [],
  "metadata": {}
}

無事作成されました。作成したAPIはプレイグランドからも見ることができます。

2. スレッドの作成

スレッドは会話を表します。ユーザーが会話を開始したらすぐに、ユーザーごとに1つのスレッドを作成することをお勧めします。
Messagesを作成して、このスレッドにユーザー固有のコンテキストとファイルを渡します。

curl https://api.openai.com/v1/threads \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d ''

レスポンス

{
  "id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
  "object": "thread",
  "created_at": 1702211522,
  "metadata": {}
}

スレッドにはサイズ制限がありません。メッセージは必要なだけスレッドに追加できます。
アシスタントは、ChatGPT で徹底的にテストした切り捨てなどの関連する最適化手法を使用して、モデルへのリクエストが最大コンテキスト ウィンドウ内に収まるようにします。アシスタント API を使用すると、特定の実行でモデルに渡される入力トークンの数の制御を委任することになります。これは、場合によってはアシスタントの実行コストをあまり制御できなくなりますが、複雑さに対処する必要がないことを意味します。コンテキスト ウィンドウを自分で管理する必要があります。

3. スレッドにメッセージを追加

アシスタントではメッセージは特定の Thread に追加する必要があります。
メッセージにはテキストが含まれ、オプションでユーザーにアップロードを許可するファイルも含まれます。
アップロードしたファイルはアシスタントが持つKnowledgeとして扱われ、ファイルの内容からユーザへの応答メッセージに活用されます。
画像をアップロードし、Retrieval機能を用いて処理させることもできるようです。

  • アップロード可能なファイル:[2]

GPT-4 Vision(画像を添付してチャットする機能)は現在サポートされていませんが、今後数か月以内にサポートを追加する予定です。

curl https://api.openai.com/v1/threads/{スレッドID}/messages \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
      "role": "user",
      "content": "I need to solve the equation `3x + 11 = 14`. Can you help me?"
    }'

スレッドIDは前項のスレッド作成時に発行されたthread_で始まるidを指定します。

レスポンス

{
  "id": "msg_88TKiCIfQsNrLRfUzp36hTEn",
  "object": "thread.message",
  "created_at": 1702211890,
  "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": {
        "value": "I need to solve the equation `3x + 11 = 14`. Can you help me?",
        "annotations": []
      }
    }
  ],
  "file_ids": [],
  "assistant_id": null,
  "run_id": null,
  "metadata": {}
}

ここで、Thread 内のメッセージをリストすると、このメッセージが追加されたことがわかります。

curl https://api.openai.com/v1/threads/{スレッドID}/messages \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1"

レスポンス

{
  "object": "list",
  "data": [
    {
      "id": "msg_88TKiCIfQsNrLRfUzp36hTEn",
      "object": "thread.message",
      "created_at": 1702211890,
      "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": {
            "value": "I need to solve the equation `3x + 11 = 14`. Can you help me?",
            "annotations": []
          }
        }
      ],
      "file_ids": [],
      "assistant_id": null,
      "run_id": null,
      "metadata": {}
    }
  ],
  "first_id": "msg_88TKiCIfQsNrLRfUzp36hTEn",
  "last_id": "msg_88TKiCIfQsNrLRfUzp36hTEn",
  "has_more": false
}

4. アシスタントの実行

アシスタントがユーザーのメッセージに応答するには、Run を作成する必要があります。
これにより、アシスタントはスレッドを読み取り、ツール (有効な場合) を呼び出すか、単純にモデルを使用してクエリに最適な回答をするかを決定します。
実行が進行するにつれて、アシスタントは role="assistant" を使用してメッセージをスレッドに追加します。
また、アシスタントは、モデルのコンテキスト ウィンドウにどの以前のメッセージを含めるかを自動的に決定します。これは、価格とモデルのパフォーマンスの両方に影響します。
現在のアプローチは、ChatGPT の構築で学んだことに基づいて最適化されており、時間の経過とともに進化する可能性があります。

オプションで、Run の作成中に新しい命令をアシスタントに渡すことができますが、これらの命令はアシスタントのデフォルトの命令をオーバーライドすることに注意してください。

curl https://api.openai.com/v1/threads/{スレッドID}/runs \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
    "assistant_id": "{アシスタントID}",
    "instructions": "Please address the user as Jane Doe. The user has a premium account."
  }'

アシスタントIDは最初にアシスタントを作成した際に発行されたasst_で始まるIDです。

レスポンス

{
  "id": "run_83zBBU1PN5cHEmddLOE1Jo0u",
  "object": "thread.run",
  "created_at": 1702213339,
  "assistant_id": "asst_qSAtIoQ1iaq5JeWYF7ifcWCk",
  "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
  "status": "queued",
  "started_at": null,
  "expires_at": 1702213939,
  "cancelled_at": null,
  "failed_at": null,
  "completed_at": null,
  "last_error": null,
  "model": "gpt-4",
  "instructions": "Please address the user as Jane Doe. The user has a premium account.",
  "tools": [
    {
      "type": "code_interpreter"
    }
  ],
  "file_ids": [],
  "metadata": {}
}

5. 実行状態を確認

デフォルトでは、Run は queued状態になります。
Run を定期的に取得してステータスをチェックし、completedに移動したかどうかを確認できます。

curl https://api.openai.com/v1/threads/{スレッドID}/runs/{実行ID} \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1"

実行IDは前項でアシスタントを実行した際に発行されたrun_で始まるIDです。

レスポンス

{
  "id": "run_83zBBU1PN5cHEmddLOE1Jo0u",
  "object": "thread.run",
  "created_at": 1702213339,
  "assistant_id": "asst_qSAtIoQ1iaq5JeWYF7ifcWCk",
  "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
  "status": "completed",
  "started_at": 1702213339,
  "expires_at": null,
  "cancelled_at": null,
  "failed_at": null,
  "completed_at": 1702213353,
  "last_error": null,
  "model": "gpt-4",
  "instructions": "Please address the user as Jane Doe. The user has a premium account.",
  "tools": [
    {
      "type": "code_interpreter"
    }
  ],
  "file_ids": [],
  "metadata": {}
}

6. アシスタントの応答を表示

実行が完了すると、アシスタントによってスレッドに追加されたメッセージを一覧表示できます。

curl https://api.openai.com/v1/threads/thread_abc123/messages \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1"
{
  "object": "list",
  "data": [
    {
      "id": "msg_T1ivBnpwwvlf9tRJebGdkkIM",
      "object": "thread.message",
      "created_at": 1702213352,
      "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
      "role": "assistant",
      "content": [
        {
          "type": "text",
          "text": {
            "value": "The solution to the equation `3x + 11 = 14` is `x = 1`, Jane Doe.",
            "annotations": []
          }
        }
      ],
      "file_ids": [],
      "assistant_id": "asst_qSAtIoQ1iaq5JeWYF7ifcWCk",
      "run_id": "run_83zBBU1PN5cHEmddLOE1Jo0u",
      "metadata": {}
    },
    {
      "id": "msg_E3FR56WJBCLIOg2muMFPZHpK",
      "object": "thread.message",
      "created_at": 1702213341,
      "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
      "role": "assistant",
      "content": [
        {
          "type": "text",
          "text": {
            "value": "Of course, Jane Doe! To solve the equation `3x + 11 = 14`, we need to find the value of `x` that makes the equation true. \n\nWe can do this by following these steps:\n1. Subtract 11 from both sides of the equation.\n2. Then divide by 3 on both sides.\n\nLet's calculate.",
            "annotations": []
          }
        }
      ],
      "file_ids": [],
      "assistant_id": "asst_qSAtIoQ1iaq5JeWYF7ifcWCk",
      "run_id": "run_83zBBU1PN5cHEmddLOE1Jo0u",
      "metadata": {}
    },
    {
      "id": "msg_88TKiCIfQsNrLRfUzp36hTEn",
      "object": "thread.message",
      "created_at": 1702211890,
      "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": {
            "value": "I need to solve the equation `3x + 11 = 14`. Can you help me?",
            "annotations": []
          }
        }
      ],
      "file_ids": [],
      "assistant_id": null,
      "run_id": null,
      "metadata": {}
    }
  ],
  "first_id": "msg_T1ivBnpwwvlf9tRJebGdkkIM",
  "last_id": "msg_88TKiCIfQsNrLRfUzp36hTEn",
  "has_more": false
}

取得したレスポンスから応答したメッセージをユーザに表示して完了です。
今回の実行でが、アシスタントは 2 つの新しいメッセージをスレッドに追加しました。
以下抜粋です。

役割 コンテンツ
user I need to solve the equation 3x + 11 = 14. Can you help me?
assistant Of course, Jane Doe! To solve the equation 3x + 11 = 14, we need to find the value of x that makes the equation true.

We can do this by following these steps:
1. Subtract 11 from both sides of the equation.
2. Then divide by 3 on both sides.

Let's calculate.
assistant The solution to the equation 3x + 11 = 14 is x = 1, Jane Doe.

和訳

役割 コンテンツ
user 方程式「3x + 11 = 14」を解く必要があります。手伝ってもらえますか?
assistant もちろん、ジェーン・ドゥ!方程式 3x + 11 = 14 を解くには、方程式を真にする x の値を見つける必要があります。

次の手順に従ってこれを行うことができます。
1.方程式の両辺から 11 を引きます。
2.次に、両辺を 3 で割ります。

計算してみましょう。
assistant 方程式「3x + 11 = 14」の解は「x = 1」です、ジェーン・ドウ。

アシスタントとそのツールの内部動作を調査または表示したい場合は、下記のように実行ステップを取得することもできます。

実行ステップを取得

curl https://api.openai.com/v1/threads/thread_abc123/runs/run_abc123/steps \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "OpenAI-Beta: assistants=v1"

レスポンス

{
  "object": "list",
  "data": [
    {
      "id": "step_IoCGpMG16vsUBHov5AouKvQI",
      "object": "thread.run.step",
      "created_at": 1702213352,
      "run_id": "run_83zBBU1PN5cHEmddLOE1Jo0u",
      "assistant_id": "asst_qSAtIoQ1iaq5JeWYF7ifcWCk",
      "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
      "type": "message_creation",
      "status": "completed",
      "cancelled_at": null,
      "completed_at": 1702213353,
      "expires_at": null,
      "failed_at": null,
      "last_error": null,
      "step_details": {
        "type": "message_creation",
        "message_creation": {
          "message_id": "msg_T1ivBnpwwvlf9tRJebGdkkIM"
        }
      }
    },
    {
      "id": "step_H1RyirtzQv2Dld2XquyXcFVn",
      "object": "thread.run.step",
      "created_at": 1702213346,
      "run_id": "run_83zBBU1PN5cHEmddLOE1Jo0u",
      "assistant_id": "asst_qSAtIoQ1iaq5JeWYF7ifcWCk",
      "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
      "type": "tool_calls",
      "status": "completed",
      "cancelled_at": null,
      "completed_at": 1702213352,
      "expires_at": null,
      "failed_at": null,
      "last_error": null,
      "step_details": {
        "type": "tool_calls",
        "tool_calls": [
          {
            "id": "call_B92gIAl3tOUvxslUjuiZedkF",
            "type": "code_interpreter",
            "code_interpreter": {
              "input": "# required libraries\nfrom sympy import symbols, Eq, solve\n\n# symbol declaration\nx = symbols('x')\n\n# equation\nequation = Eq(3*x + 11, 14)\n\n# solve for x\nsolution = solve(equation, x)\nsolution",
              "outputs": [
                {
                  "type": "logs",
                  "logs": "[1]"
                }
              ]
            }
          }
        ]
      }
    },
    {
      "id": "step_pfkZoCDhsGbHYutA8O9L7nus",
      "object": "thread.run.step",
      "created_at": 1702213341,
      "run_id": "run_83zBBU1PN5cHEmddLOE1Jo0u",
      "assistant_id": "asst_qSAtIoQ1iaq5JeWYF7ifcWCk",
      "thread_id": "thread_HJdWoVoVSv0a5f23bo93Em1b",
      "type": "message_creation",
      "status": "completed",
      "cancelled_at": null,
      "completed_at": 1702213346,
      "expires_at": null,
      "failed_at": null,
      "last_error": null,
      "step_details": {
        "type": "message_creation",
        "message_creation": {
          "message_id": "msg_E3FR56WJBCLIOg2muMFPZHpK"
        }
      }
    }
  ],
  "first_id": "step_IoCGpMG16vsUBHov5AouKvQI",
  "last_id": "step_pfkZoCDhsGbHYutA8O9L7nus",
  "has_more": false
}

自サービスに組み込む際に、このステップ情報は重宝しそうです。
ステップで見ると計算結果をコードインスペクター使っているのが分かりますね。

今回はここまでです。

さいごに

概要ページではありますが、概要だけでアシスタントAPIの使用感がさくっとわかる情報が詰まっていました。途中リンクされているページに飛んだりしていると終わらなくなりそうなので、後の自分に任せようと思います。

小ネタ

OpenAIのドキュメントページでコンソールを開くとmain.jsから以下のようなOpenAIのロゴを模した文字列が出力されています。
ロゴの下にSolve Impossible Problemsと書いてあるのがまたいいですね。

脚注
  1. https://platform.openai.com/docs/guides/function-calling ↩︎

  2. https://platform.openai.com/docs/assistants/tools/supported-files ↩︎

Discussion