2023年12月5日火曜日

OpenAIのAssistants APIを呼び出すアプリのツールにCode InterpreterとFunction Callingを追加する

先日作成したOpenAI Assistants APIを呼び出してRetrievalを実行するAPEXアプリケーションに、ツールとしてCode InterpreterとFunction Callingを追加してみました。Function Callingを呼び出すアプリケーションは以前に「OpenAI ChatGPTのFunction Callingを使ってPL/SQLプロシージャを呼び出す」として記事にしています。Function Callingに関しては、この記事の実装を流用します。

Function Callingを使って東京の天気を問い合わせています。


今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-openai-assistant.zip

以下よりアプリケーションの作成手順を紹介します。

クイックSQLの以下のモデルから、表OPENAI_FUNCTIONSとOPENAI_FUNCTION_SETを作成します。


ページ作成ウィザードを起動し、対話モード・レポートを選択します。表OPENAI_FUNCTIONSのフォーム付き対話モード・レポートのページを作成します。

対話モード・レポートのページ番号は9(8は別のページで使うので空けておきます)、名前はFunctions、フォームのフォーム・ページ番号は10、フォーム・ページ名はFunction Detailとします。データ・ソースの表/ビューの名前にOPENAI_FUNCTIONSを指定します。

それ以外はデフォルトで次に進み、主キー列1にID (Number)を指定してページの作成を実行します。


同様に表OPENAI_FUNCTION_SETのフォーム付き対話モード・レポートのページを作成します。

対話モード・レポートのページ番号は11、名前はFunction Set、フォームのフォーム・ページ番号は12、フォーム・ページ名はFunction Set Detailとします。データ・ソースの表/ビューの名前にOPENAI_FUNCTION_SETを指定します。

それ以外はデフォルトで次に進み、主キー列1にID (Number)を指定してページの作成を実行します。


表OPENAI_FUNCTIONSとOPENAI_FUNCTION_SETを編集するページができたので、記事「OpenAI ChatGPTのFunction Callingを使ってPL/SQLプロシージャを呼び出す」を参照して、PL/SQLファンクションGET_CURRENT_WEATERを作成します。表OPENAI_FUNCTIONSにファンクションとしてget_current_weatherを登録し、表OPENAI_FUNCTION_SETにファンクションget_current_weaterを含んだFunction SetとしてWeatherを作成します。

アシスタントを作成する際に上記のファンクションセットを選択できるように、共有コンポーネントのLOVを作成します。

作成するLOVの名前はLOV_FUNCTION_SETとします。タイプはDynamicです。

次へ進みます。


表ビューの名前としてOPENAI_FUNCTION_SET (表)を選択します。

次へ進みます。


戻り列はID、表示列はFUNCTION_SET_NAMEです。

作成をクリックすると、LOV_FUNCTION_SETが作成されます。


Function Callingを呼び出す際に使用するパッケージUTL_OPENAI_TOOLS_APIを作成します。以下のパッケージのコードを実行します。


アシスタントの作成時にツールとしてCode InterpreterとFunction Callingを設定できるようにします。

ページ・デザイナでページ番号5のAssistant Detailのフォームを開きます。

ページ・アイテムP5_TOOLSを選択します。現在はデフォルトの値を[{ "type": "retrieval" }]として、ツールとしてRetrievalを使用する設定になっています。

識別のタイプをチェック・ボックス・グループに変更します。設定の列の数を3にします。LOVのタイプに静的値を選択し、静的値として以下を設定します。戻り値はCODE_INTERPRETER、RETRIEVAL、FUNCTION_CALLINGのどれか、または全てを含みます。


追加値の表示はオフです。

デフォルトのタイプを- 選択 -に戻し、無指定にします。


ツールに含めるfunctionを決めるfunction setを選択するページ・アイテムを作成します。作成したページ・アイテムはページ・アイテムP5_FILE_IDSの下に配置します。

識別の名前はP5_FUNCTION_SET_ID、タイプはラジオ・グループです。レイアウトの新規行の開始をオフにし、ページ・アイテムP5_FILE_IDSの右隣に配置します。

LOVのタイプに共有コンポーネントを選択し、LOVとしてLOV_FUNCTION_SETを選びます。追加値の表示はオフ、NULL値の表示もオフです。

セッション・ステートのストレージはリクエストごと(メモリーのみ)とし、サーバー側の条件のタイプはアイテムはNULL、アイテムにP5_IDを指定し、アシスタントの作成時のみ設定できるようにします。


プロセス・ビューを開き、プロセスCreate Assisantのパラメータp_toolsを選択します。

値のタイプをファンクション本体に変更し、PL/SQLファンクション本体として以下を記述します。



以上で作成するアシスタントのツールにCode Interpreter、RetrievalおよびFunction Callingを含めることができるようになりました。

現在の天気を確認するアシスタントを作成します。NameはMy Weather Forecast Assistant、Instructionsは「あなたは日本の天気を教えてくれるアシスタントです。」とします。ToolsのFunction Callingにチェックを入れ、Function SetとしてWeatherを選択します。

作成をクリックします。


APIを呼び出して作成したアシスタントも、OpenAIのAssistantsのPlaygroundで扱うことができます。


アシスタントを作成したので、Messagesのページよりスレッドの作成を行います。メッセージとして「現在の東京の天気を教えてください。」を作成し、スレッドを実行します。

実行したスレッドはStatusがrequires_actionで停止します。

アシスタントがファンクションの呼び出しを要求していて、その結果を待っている状態です。Oracle APEX側で要求されているストアド・プロシージャを実行し、その実行結果をOpenAI Assistants APIのSubmit Tool Outputsを呼び出してアップロードする必要があります。


Runオブジェクトの内容を表示するページを作成し、そのページにSubmit Tool Outputsを呼び出すボタンを作成します。

ページの作成をクリックし、ページ作成ウィザードを開始します。

フォームを選択します。


ページ番号は8、名前はRun Detailとします。ページ・モードはドロワーを選択します。データ・ソースとしてRESTデータ・ソースを選択し、RESTデータ・ソースとしてList runsを選びます。

ドロワーなので、ナビゲーションは双方ともオフです。

次へ進み、主キー列1にID (Varchar2)を選択し、ページを作成します。


作成されたページを編集します。

ページ・アイテムP8_IDの除くすべてのページ・アイテムを選択し、識別のタイプを表示のみに変更します。


デバッグ用にページ・アイテムP8_RESPONSEを作成します。タイプはテキスト領域、ラベルはResponseとします。

セッション・ステートのデータ型はCLOB、ストレージはリクエストごと(メモリのみ)を指定します。


レンダリング前のヘッダーの前にあるプロセス初期化フォームRun Detailを選択します。

識別のタイプをAPIの呼出しに変更し、設定のパッケージとしてUTL_OPENAI_ASSISTANTS_API、プロシージャまたはファンクションとしてRETRIEVE_RUNを指定します。

サーバー側の条件のタイプにアイテムはNULLではないを選択し、アイテムとしてP8_IDを指定します。


パラメータp_run_idを選択し、値のアイテムとしてP8_IDを指定します。


パラメータファンクションの結果、p_tools、p_file_ids、p_metadataを選択し、パラメータの出力を無視をオンにします。


Assistants APIのSubmit Tool Outputsを発行するボタンを作成します。

識別のボタン名はSUBMIT_TOOL_OUTPUTS、ラベルはSubmit Tool Outputsとします。外観のホットをオン、テンプレート・オプションのWidthをStretchにします。

動作のアクションはデフォルトのページの送信です。

サーバー側の条件のタイプにアイテム = 値を選択し、アイテムとしてP8_STATUS、値にrequires_actionを指定します。


プロセス・ビューを開き、Submit Tool Outputsを発行するプロセスを作成します。作成したプロセスはダイアログを閉じるの上に配置します。

識別の名前はSubmit Tool Outputs、タイプとしてAPIの呼出しを選択します。設定のパッケージはUTL_OPENAI_TOOLS_API、プロシージャまたはファンクションとしてSUBMIT_TOOL_OUTPUTSを指定します。

サーバー側の条件のボタン押下時にSUBMIT_TOOL_OUTPUTSを指定します。


パラメータp_run_idの値のアイテムはP8_IDとします。


パラメータp_credential_static_idの値は、静的値の&G_OPENAI_API_KEY.です。

パラメータp_required_actionとp_tool_outputは、パラメータの出力を無視をオンにします。


プロセスダイアログを閉じるを選択し、サーバー側の条件の値にSUBMIT_TOOL_OUTPUTSを追記します。ボタンSUBMIT_TOOL_OUTPUTSを押した後にドロワーが閉じられます。


フォームのページについては、以上で完成です。

ページ番号6のList runsをソースとした対話モード・レポートから、ドロワーを開く設定を追加します。

リージョンRunsを選択し、プロパティ・エディタの属性タブを開きます。リンクのターゲットをクリックし、リンク・ビルダーを開きます。


ターゲットのタイプとしてこのアプリケーションのページ、ページとして先ほど作成したドロワーのページである8を指定します。

アイテムの設定の名前はP8_ID(P7_IDから変更します)に値は\#ID#\、その次に名前はP8_THREAD_IDに値は\&P6_THREAD_ID.\を設定します。


リージョンRunsから開かれたドロワーが閉じた時に、対話モード・レポートがリフレッシュされるように、動的アクションをリージョンRunsに作成します。

作成した動的アクションの識別の名前はダイアログのクローズとします。タイミングのイベントとしてダイアログのクローズを選択し、選択タイプはリージョン、リージョンとしてRunsを指定します。


TRUEアクションとしてリフレッシュを選択します。影響を受ける要素の選択タイプをリージョン、リージョンとしてRunsを選択します。


以上で、OpenAIのAssistants APIからCode InterpreterとFunction Callingを呼び出す機能を追加できました。

Code Interpreterの処理の過程を確認するためには、Run Stepsを見る必要があります。

Run Stepsを参照するページを追加します。

RESTソース・カタログのOpenAI Assistants APIよりList run stepsを選択し、RESTデータ・ソースList run stepsを作成します。


RESTデータ・ソースList run stepsをソースとしたフォーム付き対話モード・レポートのページを作成します。主キー列1はID (Varchar2)を選択します。


対話モード・レポートのページに、RESTソースList run stepsの必須パラメータであるRun IDを保持するページ・アイテムP13_RUN_IDを作成します。

タイプはテキスト・フィールド、ラベルはRun ID、セッション・ステートのストレージはセッションごと(永続)とします。


同様に必須パラメータであるThread IDを保持するページ・アイテムP13_THREAD_IDを作成します。ラベルはThread IDになります。


リージョンRun Stepsのパラメータを設定します。

パラメータrun_idの値のタイプはアイテム、アイテムとしてP13_RUN_IDを指定します。


パラメータthread_idの値のタイプはアイテム、アイテムとしてP13_THREAD_IDを指定します。


リージョンRun Stepsを選択し、ソースの送信するページ・アイテムとしてP13_RUN_ID、P13_THREAD_IDを指定します。


プロパティ・エディタの属性タブを開き、リンクのターゲットをクリックしてリンク・ビルダーを開きます。


アイテムの設定に、名前がP14_RUN_ID、値が\#RUN_ID#\と名前がP14_THREAD_ID、値が\#THREAD_ID#\の組み合わせを追加します。


ページ・デザイナでページ番号14のフォームのページを開きます。

Run Stepの詳細を確認するためにページ・アイテムを4つ作成します。タイプはすべて表示のみです。

作成するページ・アイテムはP14_RESPONSE、P14_STEP_DETAILS、P14_EXPIRE_AT、P14_METADATAです。セッション・ステートのデータ型はP14_EXPIRED_ATを除いてCLOB(P14_EXPIRED_ATはVARCHAR2)、ストレージはリクエストごと(メモリーのみ)とします。


ページ・アイテムP14_IDを除いた既存のページ・アイテムをすべて選択し、タイプを表示のみに変更します。


レンダリング前のヘッダーの前にあるプロセス初期化フォームRun Stepsを選択します。

識別のタイプをAPIの呼出しに変更し、設定のパッケージとしてUTL_OPENAI_ASSISTANTS_API、プロシージャまたはファンクションとしてRETRIEVE_RUN_STEPを指定します。

サーバー側の条件のタイプにアイテムはNULLではないを選択し、アイテムとしてP14_IDを指定します。


パラメータp_step_idの値のタイプはアイテム、アイテムはP14_IDとします。


パラメータファンクションの結果のパラメータの出力を無視をオンにします。


ページ番号6のMessagesの対話モード・レポートからRun Stepsのページに遷移できるように、リンクを設定します。

リージョンMessagesの列RUN_IDを選択し、タイプをリンクに変更します。リンクのターゲットをクリックし、リンク・ビルダーを開きます。


ターゲットのタイプはこのアプリケーションのページ、ページは13を指定します。

アイテムの設定に、名前がP13_RUN_ID、値が#RUN_ID#と名前がP13_THREAD_IDと値が#THREAD_ID#の組み合わせを追加します。


以上でRun Stepsを表示するページも完成です。

以下はCode Interpreterを呼び出したGIF動画になります。


今回の記事は以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。

完