TechBLOG

ChatGPT のAssistant API を利用し独自のアシスタントを作ってみた

目次

はじめに

  • アシスタントは、次のようないくつかのパラメータを使用して、ユーザーのメッセージに応答するように設定できるエンティティを表します:
    • Instructions: アシスタントとモデルがどのように振る舞い、対応すべきか。
    • Model: GPT-3.5またはGPT-4モデルを指定できます(微調整モデルは近日公開予定)。
    • ToolsCode InterpreterKnowledge retrieval, and Function calling.
  • 上記のパラメータを設定することで、アシスタントに異なる機能と異なるコストを与えることができます。GPTモデルには、高レベル言語を生成する機能、モデルを思い通りの方向に導くためのインストラクション、各機能に対応したツールが用意されています。

Tools

Code Interpreter

  • Code Interpreterは、Assistants APIがサンドボックス化された実行環境でPythonコードを記述し、実行することを可能にします。
  • Code Interpreter は、アシスタントにコードを実行させます。
  • Code Interpreterは1セッションにつき$0.03で課金されます。各セッションはデフォルトで1時間有効です。つまり、ユーザーが同じスレッドで1時間までCode Interpreterとやりとりしても、1セッションにつき1回しか課金されません。
  • アシスタントレベルで渡されたファイルは、そのアシスタントを持つすべてのランからアクセスできます。ファイルはスレッドレベルでも渡すことができ、これらのファイルには特定のスレッドでのみアクセスできます。
  • Code Interpreterを使用した場合、アシスタントやメッセージに添付されたファイルはインデックス化されないため、これらのファイルに対する支払いは発生しません。

Knowledge Retrieval

  • 検索は、アシスタントのモデル外からの知識でアシスタントを補強する。
  • ファイルがアップロードされ、アシスタントに渡されると、OpenAIは自動的にドキュメントをチャンキングし、インデックスを作成し、エンベッディングを保存し、ユーザーのクエリに答えるために関連するコンテンツを検索するベクトル検索を実装します。
  • 検索技術には2つある:
    • 短いドキュメントのプロンプトにファイルの内容を渡す
    • 長い文書のベクトル検索を行う
  • 検索は現在、モデルコールのコンテキストに関連するすべてのコンテンツを追加することで、品質を最適化している。
  • 検索は、アシスタント1人あたり1日$0.20/GBです。アシスタントからファイルを削除すると、検索インデックスからファイルが削除されます。

Function Calling

  • 関数呼び出しでは、アシスタントに関数を記述し、呼び出しが必要な関数を引数とともにインテリジェントに返すことができます。
  • AssistantsAPIは、関数を呼び出すと実行を一時停止し、関数呼び出しの結果を返して実行を継続することができます。

アシスタントを作る

独自のアシスタントを構築するには、Assistants playgroundAssistants APIの2つの方法があります。

  • Assistants APIは、開発者がタスクを実行する強力なAIアシスタントを構築できるように設計されている。
  • Assistants playgroundは、Assistants APIの機能を探求し、コードを書かずに独自のアシスタントを構築する方法を学ぶのに最適な方法です。

作業の流れ

  • Assistant: 設定された指示、モデル、ツールを備えたあなただけのAIアシスタント。
  • Thread: アシスタントとユーザー間の会話セッション。スレッドはメッセージを保存し、コンテンツをモデルのコンテキストに合わせるために自動的に切り捨てを処理します。
  • Message: アシスタントまたはユーザーが作成したメッセージ。テキスト、画像、その他のファイルを含むことができます。スレッドにリストとして保存されるメッセージ。
  • Run: アシスタントはメッセージを使用してモデルやツールを呼び出し、タスクを実行します。実行オブジェクトは複数のステータスを持つことができます。
  • Run step: アシスタントがランの一部として行ったステップの詳細なリスト。

メリット

  • アシスタントは、モデルのコンテキストの長さを超えないように、自動的にコンテキストウィンドウを管理します。
  • メッセージにはテキスト、画像、ファイルを含めることができます。
  • アシスタント1人につき最大20個のファイルを添付できます。各ファイルは最大 512 MB、最大 2,000,000 トークンを含むことができます。
  • アシスタントは複数のツールに並行してアクセスできる (Code interpreterKnowledge retrievalFunction calling).
  • アシスタントは、いくつかの形式のファイルにアクセスできます。ツールを使用する際、アシスタントはファイル(画像、スプレッドシートなど)を作成し、作成したメッセージで参照するファイルを引用することもできます。
  • 既存のアプリケーションとの統合が容易。

制限事項

  • コードインタープリターはPythonコードのみを実行します。
  • 定期的にRunオブジェクトを取得して状態を確認する必要があります。
  • Runが進行中で終了状態にない場合、スレッドはロックされます。
  • ストリーミング出力(メッセージやRunステップを含む)には対応していません。
  • DALL·Eやブラウジングなどのツールには対応していません。
  • 画像を含むユーザーメッセージの作成には対応していません。

デモ

このデモでは、Assistants playgroundを使ってアシスタントを作成する。

Code Interpreter

まず、名前、命令、モデルの選択、コードインタープリターオプションを有効にして、アシスタントを1つ作成します。

この例では、このアシスタントに「1から100までの乱数を返す関数を書く」ことを要求します。アシスタントはpython環境上でコードを生成して実行するためにコードインタプリタを使用し、結果が表示されます。コードインタプリタを使えば、ユーザはアシスタント上で直接コードを実行できます。

ユーザーはアシスタントのプレイグラウンドの右側にあるAPIのログを見ることができる。

Retrieval

検索ツールをアクティブにするには、検索オプションを有効にし、1つまたは複数の知識ファイルをアップロードすることができます。アシスタントは、データを照会し、ユーザのメッセージに返すために、これらの知識ファイルを使用します。

この例では、アシスタントがknowledge.txtファイル内のピオネロの情報を検索し、その結果をユーザーに返します。

Functions

関数名、関数の説明、パラメータ、必須項目を定義します。定義が完了したら、保存します。

アシスタントは、関数の説明に基づいて、どのようなユーザーのメッセージがその関数とその関数のパラメータを発生させるかを決定します。

関数が発生した後、このスレッドは最終的な結果を待つために保留されます。しかし、アシスタントの責任は、関数名とその関数のパラメータを決定することだけで、関数の中身を決定することはできません。つまり、自分でget_wearther関数をホストしなければなりません。

このコードをご覧ください。

import OpenAI from "openai";
import 'dotenv/config'

const openai = new OpenAI({apiKey: process.env['OPENAI_API_KEY']});

// Create a assistant with function getCurrentWeather
const assistant = await openai.beta.assistants.create({
    name: "Weather Assistant",
    instructions: "You are a weather bot. Use the provided functions to answer questions.",
    model: "gpt-3.5-turbo",
    tools: [{
        "type": "function",
        "function": {
            "name": "getCurrentWeather",
            "description": "Get the weather in location",
            "parameters": {
                "type": "object",
                "properties": {
                "location": {"type": "string", "description": "The city and state e.g. San Francisco, CA"}
                },
                "required": ["location"]
            }
        }
    }]
});

// Create a thread
const thread = await openai.beta.threads.create();

// Add a message to the thread
const message = await openai.beta.threads.messages.create(
    thread.id,
    {
      role: "user",
      content: "What is the weather in Hanoi."
    }
  );  

// Assistant run process
const run = await openai.beta.threads.runs.create(
    thread.id,
    { assistant_id: assistant.id }
);

// Wait for run status change to requires_action
await new Promise(r => setTimeout(r, 2000));

// Retrieve the run status
const runRetrieve = await openai.beta.threads.runs.retrieve(
    thread.id,
    run.id
  );

// getCurrentWeather raised here
if (runRetrieve.status === 'requires_action' && runRetrieve.required_action.submit_tool_outputs.tool_calls[0].function.name === 'getCurrentWeather') {
    const toolCallId = runRetrieve.required_action.submit_tool_outputs.tool_calls[0].id
    await openai.beta.threads.runs.submitToolOutputs(
        thread.id,
        run.id,
        {
          tool_outputs: [
            {
              tool_call_id: toolCallId,
              // The final result will be placed here, it can be got from an API
              output: Math.floor(Math.random() * 30) + "C",
            },
          ],
        }
      );
}

await new Promise(r => setTimeout(r, 2000));

const messages = await openai.beta.threads.messages.list(
    thread.id
);

messages.data.forEach(element => {
    console.log("element:", element.content[0].text)
});
element: { value: 'The current weather in Hanoi is 16°C.', annotations: [] }
element: { value: 'What is the weather in Hanoi.', annotations: [] }

結論

この記事を通じて、アシスタントの特徴、長所、制限事項、および作成方法について学びました。ユーザーはアシスタント上でPythonプログラミング言語を直接使用でき、画像、エクセル、JSONなどの処理に利用できます。個別のデータセットやカスタム機能を取得することもできます。アシスタントはAssistants APIを使用して既存のアプリケーションに簡単に統合できます。

共有

SAME TOPIC

Sorry, your ID is maybe not correct (If you did not place any ID that means auto-detect does not work.). And please make sure that your selected element is developed with Swiper.