Open2

Azure OpenAI ServiceのAssistants APIをPythonから触ってみる

Yuki YamadaYuki Yamada

Assistants APIとは?

Assistants APIは独自のAIアシスタントを定義し、利用可能にするOpenAIのAPIです。
Azure OpenAI Serviceでは先日からプレビュー版として提供が開始されました。

https://techcommunity.microsoft.com/t5/ai-azure-ai-services-blog/azure-openai-service-announces-assistants-api-new-models-for/ba-p/4049940

Assistants APIが利用可能なリージョンでAzure OpenAI Serviceリソースを作成する

現在、Azure OpenAI ServiceでAssistants APIが利用可能なリージョンは限られており、以下のいずれかのリージョンでAzure OpenAI Servieのリソースを作成する必要があります。

  • 米国東部2
  • オーストラリア東部
  • スウェーデン中部

以降の検証ではオーストラリア東部で作成したAzure OpenAI Serviceのリソースを利用しています。

また作成したリソースにはデプロイを作成しておく必要があります。
ひとまずgpt-35-turboモデルとgpt-4モデルのデプロイを作成しておきます。

Pythonのプロジェクトのセットアップ

Poetryで適当にプロジェクトを作成し、openaiパッケージを追加します。

poetry add openai

Azure OpenAI Serviceへ接続

作成したAzure OpenAI ServiceリソースのAPIキーとエンドポイントの情報を以下の環境変数にセットし、AzureOpenAIのクライアントを生成します。

  • AZURE_OPENAI_KEY
  • AZURE_OPENAI_ENDPOINT
import os
from openai import AzureOpenAI

api_key = os.getenv("AZURE_OPENAI_KEY", "")
azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT", "")

client = AzureOpenAI(
    api_key=api_key,
    api_version="2024-02-15-preview",
    azure_endpoint=azure_endpoint,
)

assistantの作成

早速、アシスタントを作成してみます。
作成するアシスタントにはCode Interpreterをtoolに指定しています。

deployment_name = "gpt-35-turbo"

assistant = client.beta.assistants.create(
    instructions="You are an AI assistant that can write code to help answer math questions",
    model=deployment_name,
    tools=[{"type": "code_interpreter"}],
)

生成したアシスタントは以下のような構造で、str型のidフィールドを持っています。
なお型情報はopenai.types.beta.assistant.Assistantでした。

Assistant(
  id='asst_****',
  created_at=1707401931,
  description=None, file_ids=[],
  instructions='You are an AI assistant that can write code to help answer math questions',
  metadata={},
  model='gpt-35-turbo',
  name=None,
  object='assistant',
  tools=[ToolCodeInterpreter(type='code_interpreter')]
)
Yuki YamadaYuki Yamada

スレッドの作成

アシスタントを使って会話をする際はスレッドを作成し実行する必要があります。
早速、スレッドを作成してみます。

# スレッドの作成
thread = client.beta.threads.create()

作成したスレッドは以下のような構造で、こちらもstr型のidフィールドを持っています。
なお型情報はopenai.types.beta.thread.Threadでした。

Thread(
  id='thread_*****',
  created_at=1707402867,
  metadata={},
  object='thread'
)

このスレッドにメッセージを追加します。

message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="日本の首都はどこですか?",
)

追加後、スレッドのメッセージ一覧を取得すると、メッセージが追加されていることがわかります。

thread_messages = client.beta.threads.messages.list(thread.id)
{
  "data": [
    {
      "id": "msg_AHBYC9jm1sWO4oUPUEJqsUev",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "日本の首都はどこですか?"
          },
          "type": "text"
        }
      ],
      "created_at": 1707403410,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_*****"
    }
  ],
  "object": "list",
  "first_id": "msg_AHBYC9jm1sWO4oUPUEJqsUev",
  "last_id": "msg_AHBYC9jm1sWO4oUPUEJqsUev",
  "has_more": false
}

このスレッドをアシスタントに渡して実行をします。

# 実行
run = client.beta.threads.runs.create(
  thread_id=thread.id,
  assistant_id=assistant.id,
)

runの型情報はopenai.types.beta.threads.run.Runstatusを見ることで実行状況を確認できます。

print(run.status)
>>> 'queued'

runの状況はスレッドのidとrunのidを使って再取得することで更新をする必要があります。

run = client.beta.threads.runs.retrieve(
  thread_id=thread.id,
  run_id=run.id
)
run.status
>>> 'completed'

'completed'になれば実行は完了です。

スレッドのメッセージ一覧を確認すると回答が得られていることがわかります。

thread_messages = client.beta.threads.messages.list(thread.id)
print(thread_messages.model_dump_json(indent=2))
{
  "data": [
    {
      "id": "msg_utCC1480K7j9wTMHEfnGuF0H",
      "assistant_id": "asst_*****,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "日本の首都は東京です。"
          },
          "type": "text"
        }
      ],
      "created_at": 1707403582,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_DjcOEkEOeSWsxio6KfZclM4w",
      "thread_id": "thread_*****"
    },
    {
      "id": "msg_AHBYC9jm1sWO4oUPUEJqsUev",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "日本の首都はどこですか?"
          },
          "type": "text"
        }
      ],
      "created_at": 1707403410,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_*****"
    }
  ],
  "object": "list",
  "first_id": "msg_utCC1480K7j9wTMHEfnGuF0H",
  "last_id": "msg_AHBYC9jm1sWO4oUPUEJqsUev",
  "has_more": false
}