こちらの記事「OpenAIのChat Completions APIを呼び出すAPEXアプリを作成する」で作成したAPEXアプリケーションに、ツール呼び出し(以前のFunction Calling)の機能を追加します。このアプリケーションが呼び出しているパッケージUTL_OPENAI_CHAT_APIには、すでにツール呼び出しをハンドリングするコードが含まれているため、主な作業はユーザー・インターフェースの追加になります。
作成したアプリケーションは以下のGIF動画のように動作します。
プロンプトとして「あなたはお天気お兄さんです。」を設定し、メッセージ「現在の東京とパリの天候を教えてください。」を送信します。
LLMはtool_callsとして引数をTokyoとしたツール呼び出しと、Parisを引数としたツール呼び出しを返します。ツールの並列呼び出しは2023年11月に追加された機能です。
TokyoとParisの現在の天候をOpenMeteo.comに問合せて回答を返し、最終的に「現在の東京とパリの天候はどちらも晴れです。」という回答を得ています。
以下より追加した実装について紹介します。
はじめに呼び出すツールに関する設定を保存する表OPENAI_TOOLSを操作するために、対話モード・レポートとフォームのページを作成します。
ページの作成をクリックします。
対話モード・レポートのページの名前はToolsとし、フォーム・ページを含めるをオンにします。フォーム・ページ名はTool Detailとします。
データ・ソースの表/ビューの名前にOPENAI_TOOLSを選択します。
次へ進みます。
主キー列1にID(Number)を選択します。
ページの作成をクリックします。
以上でツールの設定画面が作成できました。
ツール呼び出しに登録するツールは、PL/SQLのストアド・ファンクションとして作成します。OpenAIではLLMのレスポンスとしてツール呼び出し(roleがtool_calls)を返す時は、呼び出すファンクション名とその引数となるJSONドキュメントをレスポンスに含めます。
レスポンスとしてツール呼び出しを受け取った場合は、ファンクション名として返されたPL/SQLファンクションにJSONドキュメントを引数として渡して、動的にファンクションを呼び出します。呼び出したファンクションの戻り値(これもJSONドキュメント)をツールの応答(roleがtool)としてLLMに戻します。
ページを実行し、指定した都市(首都)の天候を取得するファンクションget_current_weatherを設定します。
作成をクリックします。
Tool SetはWeatherとします。Tool Typeはfunctionを指定します。現時点で指定できるTool Typeはfunctionのみのようです。DescriptionはGet the current weather in a given location、Tool Nameはget_current_weather、Parametersには以下のJSON Schemaを記述します。
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. Tokyo"
}
},
"required": [
"location"
]
}
作成をクリックします。
実際に呼び出されるPL/SQLファンクションget_current_weatherを作成します。
ファンクションget_current_weatherのコードは以下です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create or replace function get_current_weather( | |
p_args in clob | |
) | |
return clob | |
as | |
l_args json_object_t; | |
l_location varchar2(400); | |
l_location_tokens apex_t_varchar2; | |
l_lat number; | |
l_lon number; | |
l_url varchar2(4000); | |
l_response clob; | |
l_response_json json_object_t; | |
l_weathercode number; | |
l_weather varchar2(4000); | |
begin | |
l_args := json_object_t(p_args); | |
l_location := l_args.get_string('location'); | |
/* get first part (city name) from the location */ | |
l_location_tokens := apex_string.split(l_location, '[ ,]'); | |
l_location := l_location_tokens(1); | |
apex_debug.info('location = %s', l_location); | |
/* | |
* 都市名から緯度経度の情報を取り出す。 | |
* アマノ技研さんより提供されている「世界の百万都市の位置データ Location Data of Megacities」の | |
* CSVファイルを表AMANO_CITY_LOCATIONSにロードしています。 | |
* 参照: https://amano-tec.com/data/megacities.html | |
*/ | |
select lat, lon into l_lat, l_lon | |
from amano_city_locations | |
where upper(capital_en) = upper(l_location) or capital_jp = l_location; | |
/* | |
* Open-Meteo.comのAPIを呼び出し、指定した座標の現在の天気を取得しています。 | |
* 参照: https://open-meteo.com | |
*/ | |
l_url := 'https://api.open-meteo.com/v1/forecast?latitude=' || l_lat || '&longitude=' || l_lon || '¤t=weathercode'; | |
l_response := apex_web_service.make_rest_request( | |
p_url => l_url | |
,p_http_method => 'GET' | |
); | |
if apex_web_service.g_status_code <> 200 then | |
return '{ "error": "open-meteo.com api call failed, response = ' || l_response || '" }'; | |
end if; | |
l_response_json := json_object_t(l_response); | |
/* | |
* Weather Code (WMO 4501)のコードの説明は以下の気象関係コード表のWMO 4501の部分を | |
* 表WMO4501として読み込んでいます。 | |
* 参照: https://www.jodc.go.jp/data_format/weather-code_j.html | |
* | |
* たまにWMO 4677を返しているのでは?と思えるときもあります。なのでコードが10以上の場合は、WMO4677として | |
* 取り扱います。 | |
*/ | |
l_weathercode := l_response_json.get_object('current').get_number('weathercode'); | |
if l_weathercode < 10 then | |
select description into l_weather from wmo4501 where code = l_weathercode; | |
else | |
select description into l_weather from wmo4677 where code = l_weathercode; | |
end if; | |
return '{ "weather" : "' || l_weather || '" }'; | |
exception | |
when no_data_found then | |
return apex_string.format('{ "error": %s }', l_response); | |
end get_current_weather; | |
/ |
都市名から緯度経度を求めるために、アマノ技研様が公開している「世界の百万都市の位置データ Location Data of Megacities」のCSVデータをダウンロードし、表AMANO_CITY_LOCATIONS(新規作成)にロードしています。データのロードには、SQLワークショップのデータ・ワークショップを使用しています。
また、weathercodeについては「気象関連コード表」に記載されているWMO 4501のHTML表を表WMO4501、WMO 4677のHTML表を表WMO4677として、データをロードします。双方の表は列CODE(NUMBER)、列DESCRIPTION(VARCHAR2(4000))の列を持ちます。データ・ワークショップを使ってHTML表をコピペし、それぞれの表にロードします。
ファンクションget_current_weatherの作成は以上です。
ページ・デザイナでホーム・ページを開きます。
リージョンSystem Promptに、チャット呼び出しの際に含めるTool Setを選択するページ・アイテムを作成します。
識別の名前はP1_TOOL_SET、タイプは選択リスト、ラベルはTool Setとします。
LOVのタイプにSQL問合せを選択し、SQL問合せとして以下を記述します。
select tool_set d, tool_set r from openai_tools group by tool_set
追加値の表示はオフ、NULL値の表示をオンとし、NULL表示値は-- Select Tool Set --とします。
左ペインでプロセス・ビューを開き、プロセスSend Messageのパラメータp_tool_setを選択します。
値のタイプをアイテムに変更し、アイテムとしてP1_TOOL_SETを指定します。
アプリケーションを実行すると、記事の先頭にあるGIF動画のように動作します。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/chat-with-generative-ai-0-fc.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完