2026年7月1日水曜日

APEX 26.1のAIエージェントでデータベースを操作する

先の記事「APEX 26.1のAIエージェントでHTMLキャンバスに描画した車を動かす」にて、APEX 26.1のAIエージェントを使ってブラウザを操作するサンプル・アプリを作ってみました。本記事では、AIエージェントを使ってデータベースを操作するエージェントを作ってみます。

以下、プロンプトで従業員の給与を更新します。データ・ソースとしてはサンプル・データセットのEMP/DEPTの含まれる表EMPを使用します。

作成するAPEXアプリケーションは以下のように動作します。LLMにmacOSのLM Studioで実行しているgoogle/gemma-4-31b-qatを使用しているため、処理に時間がかかっています(動作も若干安定しないです)。

ページ・アイテムP1_ENAMEKINGが選択されているときに限り、AIエージェントのツールにupdate_salaryが含まれるようにしています。KING以外のときは「更新できません。」と返されます。


作成したAPEXアプリケーションのAPEXlang形式のエクスポートを以下に置きました。

https://github.com/ujnak/APEXlang-exports/tree/main/salary-management-agent

以下より、作成したAPEXアプリケーションについて紹介します。主にAIエージェントの紹介になります。

ホーム・ページに、AIエージェントに含まれるツールupdate_salaryサーバー側の条件に使用されるページ・アイテムP1_ENAMEが作成されています。

選択リストソースとなるSQL問合せとして、以下を記述しています。

select ename d, ename r from emp order by 1

選択時のページ・アクションとして値のリダイレクトと設定を選び、セッション・ステートストレージセッションごと(永続)を選んでいます。そのため、ここで選択した値をAIエージェントのコード中で、バインド変数:P1_ENAMEから参照できます。


従業員一覧はクラシック・レポートで作成し、ソース表名EMPを設定しています。

給与の更新後にJavaScriptの実行によりレポートをリフレッシュするため、詳細HTML DOM IDEMPを設定しています。


AIエージェントへのプロンプトを入力するリージョンとして、静的コンテンツのリージョンを作成し、ソースHTMLコードに以下を記述しています。

<div id="chat"></div>

AIアシスタントは、ページのロード時に実行する動的アクションで初期化しています。


作成したAIエージェントについて説明します。

AIエージェントの名前Salary Management Agentとしています。生成AIサービスとしてLM Studio Gemma4を設定しています。これはワークスペースに生成AIサービスとして作成済みです。

システム・プロンプトとして以下を記述しています。

「従業員の給与を更新します。
利用できるツールにupdate_salaryが含まれていない場合は、給与の更新手段がありません。その場合は、更新できません、と返します。」


4つのツールを作成しています。


システム・プロンプト拡張としてinject_schema_informationを作成しています。

このツールによって、システム・プロンプトに表EMPとDEPTの定義情報を追記しています。

実行ポイントシステム・プロンプト拡張のツールをツールと呼ぶと、LLMのツール呼び出しに含まれるツール定義と混同しそうです。実行ポイントオンデマンドのツールのみが、いわゆるLLMが扱うツールになります。

タイプデータの取得を選んでいます。データの取得の処理は、データベース・サーバー側で実行されます。サーバー側の処理は、設定タイプにてSQL問合せファンクション本体静的値の3つから選べます。

識別タイプで、クライアント側のコードを実行サーバー側のコードを実行データの取得が選べるように見えますが、実行ポイントシステム・プロンプト拡張の場合、データの取得サーバー側のコードを実行を含んでいるため、タイプサーバー側のコードを実行は選べません。選ぶと実行ポイントオンデマンドに変わります。

設定説明に「従業員給与を保持するスキーマ情報。」と記述します。この文章もシステム・プロンプトに追記されます。タイプファンクション本体を選択します。

言語PL/SQLを選び、CLOBを返すファンクション本体として以下を記述します。
declare
    l_text clob; 
begin
    l_text := apex_db_dictionary.get_table_info( 
        p_table_names => 'EMP, DEPT' );
    return l_text;
end;
以上で、表EMP/DEPTのメタデータが、つねにシステム・プロンプトに追記されるようになりました。


従業員名から従業員番号を取り出すツールをget_empno_from_enameとして作成しています。タイプサーバー側のコードを実行です。

説明に「従業員名から従業員番号を取得します。」と記述しています。この説明を元に、LLMはツールを選択します。

パラメータとしてENAMEを追加しています。説明従業員名データ型VARCHAR2必須はいです。

設定言語PL/SQLを選択し、PL/SQLコードとして以下を記述します。
declare
    l_empno emp.empno%type;
    l_response clob;
begin
    select empno into l_empno from emp where ename = :ENAME;
    l_response := apex_string.format('empno %s found for ename %s', l_empno, :ENAME);
    apex_ai.set_tool_result( p_result => l_response );
exception
    when no_data_found then
        l_response := apex_string.format('No empno found for %s, perhapse the employee with the name does not exist.', :EMPNO);
        apex_ai.set_tool_result( p_result => l_response );
end;

ツールget_empno_from_enameはだれでも呼び出せるように、条件は設定していません。

従業員一覧のレポートをリフレッシュするツールをrefresh_reportとして作成しています。タイプクライアント側のコードを実行実行ポイントオンデマンドです。

ツールの説明として「従業員一覧のレポートをリフレッシュします。」を記述します。

設定コードに以下の1行を記述します。

apex.region("EMP").refresh();


本記事の主題である、従業員の給与を更新するツールをupdate_salaryとして作成しています。

タイプサーバー側のコードを実行です。実行ポイントは必ずオンデマンドになります。

ツールの説明として。以下を記述します。

「指定した従業員番号の従業員の給与を更新します。
更新後はツールrefresh_reportを呼び出して、レポートの表示を更新します。」

パラメータとしてEMPNOSALを追加します。

EMPNO説明従業員番号データ型NUMBER必須はいです。SAL説明給与データ型NUMBER必須はいです。

設定言語PL/SQLを選択し、PL/SQLコードとして以下を記述します。
declare
begin
    update emp set sal = :SAL where empno = :EMPNO;
end;

ツールupdate_salaryについては、以下の条件も設定します。

User ApprovalRequire Confirmationオンにします。Confirmation Title給与の更新とし、Confirmation Messageに以下を記述します。

「従業員&EMPNO.の給与を&SAL.に更新します。」

LLMがツールupdate_salaryを実行するようにレスポンスを返したときに、以下のようにユーザーに確認を求めるダイアログが開きます。

OKをクリックすると、ツールupdate_salaryが実行されます。OK取消といったラベルは、Approve LabelCancel Labelを設定して変更できます。


通知メッセージに「給与を更新しました。」と記述します。タイプ成功を選択します。

上記のように設定した通知は、以下のように表示されます。通知の設定の有無に関わらず、LLMからのレスポンスも表示されるようです。


サーバー側の条件として、タイプ言語PL/SQL式1に以下を記述しています。

:P1_ENAME = 'KING'

上記の条件により、ツールupdate_salaryはページ・アイテムP1_ENAMEKINGが設定されているときに限り、LLMに送信するツール定義に含まれます。それ以外の従業員はツールupdate_salaryがツールに含まれていないため、給与を更新するようにプロンプトを送信しても、システム・プロンプトに設定しているように「更新できません。」と返されます。


以下、設定画面のスクリーンショットです。


今回作成したAPEXアプリケーションの説明は以上になります。

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

APEX 26.1のAIエージェントでHTMLキャンバスに描画した車を動かす

Oracle APEX 26.1では共有コンポーネントとして、新たにAIエージェントが追加されました。新しいAIエージェントは、APEX 24.2にあった共有コンポーネントAI構成を置き換えています。また、古いAI構成RAGソースを含んでいました。新しいAIエージェントは、RAGソースがツールに置き換えられています。

以前のRAGソースは、サーバー側で検索した結果をコンテキストに含めるために使用しました。新しいAIエージェントツールにはタイプが3種類あります。クライアント側のコードを実行サーバー側のコードを実行データの取得がそれらのタイプです。この中で、データの取得が以前のRAGソースにあたります。クライアント側のコードを実行サーバー側のコードを実行が新しく追加されたタイプです。これらはタイプオンデマンドの場合、ツール呼び出しを行うためにLLMに送信するメッセージに含めるツール定義になります。

新しいAIエージェントの動作を理解するために、以下のAPEXアプリケーションを作成しました。HTMLキャンバスにbabylon.jsを使って車を描画し、APEXのチャット画面からの指示により車を動かします。

LLMにはmacOSのLM Studioで実行しているgoogle/gemma-4-31b-qatを使用しています。


以下、APEXアプリケーションの作り方を紹介します。

空のAPEXアプリケーションを作成します。名前はDriving with APEXとします。


アプリケーションが作成されます。車の描画やコマンド入力は、ホーム・ページに実装します。


ページ・プロパティのJavaScriptファイルURLに以下を記述し、ページにbabylon.jsを組み込みます。

https://cdn.babylonjs.com/babylon.js

本記事はAPEXのAIエージェントを紹介することを目的としています。babylon.jsについてはChatGPTやClaudeに聞いて実装しています。動作することは確認しましたが、最適な実装かどうかについては分かりません。


車を描画する領域を、静的コンテンツのリージョンCarとして作成します。

ソースHTMLコードとして以下を記述します。

<div id="babylonRegion" style="width:100%; height:500px;">
    <canvas id="renderCanvas" style="width:100%; height:100%; touch-action:none;"></canvas>
</div>


APEXのAIエージェントに紐付け、車を操作するプロンプトを入力するリージョンを静的コンテンツとして作成します。リージョンの名前はDriveとします。

ソースHTMLコードに以下を記述します。

<div id="drive"></div>

車が描画されているリージョンの右隣に配置するため、レイアウト新規行の開始をオフにします。


HTMLキャンバスに車を描画するコードを記述します。

ページ・プロパティのJavaScriptファンクションおよびグローバル変数の宣言に以下を記述します。


ページ・ロード時に実行に以下を記述します。

initBabylonCar();


ここまでの状態でアプリケーションを実行すると、キャンバスに車が描画されているところまでを確認できます。

これからAPEXのAIエージェントを実装していきます。


あらかじめワークスペースに生成AIサービスが登録ずみであることを前提とします。本記事ではLM Studioとgoogle/gemma-4-31b-qatを使用していますが、日本語の解釈ができてツール呼び出しに対応していれば、他のモデルでも動くでしょう。


共有コンポーネントAIエージェントを開きます。


作成済みのAIエージェントが一覧されます。作成を開始します。


作成するAIエージェントの名前Car Driverとします。生成AIサービスとして、すでにワークスペースに作成されている生成AIサービスを選択します。

システム・プロンプトに以下を記述します。

babylon.jsでキャンバスに描画された車を移動します。

ようこそメッセージに以下を記述します。

さあ、車を動かしましょう。

以上で、一旦AIエージェントを作成します。


AIエージェントCar Driverが作成されたら、ツールの追加をクリックします。


生成AIツールを作成します。

名前move_car_rightとします。タイプクライアント側のコードを実行を選択します。実行ポイントオンデマンドを選択します。

説明として以下を記述します。実行ポイントオンデマンドの場合、以下の説明はツールの説明としてLLMに送信され、LLMによるツール選択の基準になります。

車を右に、指示した距離だけ移動します。

パラメータの追加をクリックし、パラメータを追加します。

パラメータ名DISTANCE説明移動する距離データ型NUMBER必須はいにします。このパラメータ定義もLLMに送信され、ツールが必要とするプロパティとして認識されます。

設定コードに、ツールmove_car_rightが選択されたときに実行するコードを記述します。タイプクライアント側のコードを実行を選択しているため、ブラウザで実行されるJavaScriptのコードを記述します。
car.position.x += this.data.DISTANCE;
return {};

本記事ではこれ以上の設定を行いませんが、AIツールにはこの他に以下の設定があります。

User Approvalをオンにすると、ツールを実行する前にユーザーに確認を求めることができます。通知を設定すると、ツールの実行後に通知を表示できます。

サーバー側の条件セキュリティでは、設定した条件に応じてAIエージェントにこのツールを含めるかどうかを決めることができます。例えば、特定の部門に所属している人が実行できる、管理者であれば実行できる、といった条件のツールを作れます。また、これらの条件はAIエージェントが呼び出される度に評価されるため、それまでのコンテキストを参照してProgressive Tool Disclosureのような実装もできるでしょう。

ビルド・オプションを使うことで、開発環境に限りツール呼び出しに含めるといった設定もできます。


同様にして、以下の3つのツールを作成します。設定の異なる部分のみを記述します。

名前: move_car_left
説明: 車を左に、指示した距離だけ移動します。
コード: car.position.x -= this.data.DISTANCE;

名前: move_car_up
説明: 車を上に、指示した距離だけ移動します。
コード: car.position.y += this.data.DISTANCE;

名前: move_car_down
説明: 車を下に、指示した距離だけ移動します。
コード: car.position.y -= this.data.DISTANCE;

これらの4つのツールを持つAIエージェントが、Car Driverとして作成されました。


ページのロード時に、AIアシスタントがリージョンDriveで初期化されるように、動的アクションを作成します。

ページのロードで実行される動的アクションをInit Car Driverとして作成します。

TRUEアクションとしてAIアシスタントの表示を選び、生成AIエージェントとしてCar Driverを選択します。

外観表示形式インラインを選択し、コンテナ・セレクタとして#driveを設定します。


以上で、アプリケーションは完成です。アプリケーションを実行すると、記事の先頭のGIF動画のように動作します。

今回作成したAPEXアプリケーションのAPEXlang形式のエクスポートを以下に置きました。


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

2026年6月30日火曜日

APEX 26.1の対話モード・レポートでの生成AIの利用について

APEX 26.1では、生成AIを活用して自然言語で対話モード・レポートを操作できるようになりました。この機能はAI Interactive Reportと呼ばれています。

概ね、以下のGIF動画のように操作します。動画では以下のプロンプトを与えています。
  • プラム色の服を一覧して。
  • レポートをリセットして。
  • カテゴリ別の服の数を左から少ない順にチャート表示して。
  • このチャートをレポートとして保存して。
  • レポートをリセットして

以下より、対話モード・レポートで生成AIを使用するための設定手順と、その設定について調べたことを紹介します。

公式ブログの以下の記事とAPEX Office Hoursの録画を参考にしています。

Talk to Your Data, Trust the result. Introducing APEX AI Interactive Reports

What's New in APEX 26.1 - Part 4

最初にOracle APEXから生成AIを呼び出すには、ワークスペース・ユーティリティ生成AIに、生成AIサービスを作成する必要があります。

ワークスペース・ユーティリティ生成AIを開きます。


プロバイダのタイプ、APIのエンドポイントURL、APIキー、呼び出すモデルをまとめて、生成AIサービスとして作成します。


対応しているAIプロバイダは、OCI生成AIサービスOpenAICohereGoogle GeminiAnthropic ClaudeMistral AIOllama汎用(OpenAI API互換)です。

OpenAIについてはChat Completions APIで、Responses APIではありません。また、OpenAI汎用(OpenAI API互換)は、APIキーが必須かどうかが設定上の違いに見えます。


AIプロバイダとしてOpenAIを選択した場合を例にとります。

最低限、名前ベースURLAPIキー静的ID(これは名前からデフォルト値が生成されます)、AIモデルを設定します。

後ほど説明しますが、AI Interactive Reportで使用するLLMは、必ずツール呼び出しに対応しているモデルで、できるだけツール呼び出しに強いモデルを選びます。


ここで資格証明新規作成を選ぶと、新しく作成されたWeb資格証明にAPIキーが保存されます。


APIキーの更新は、Web資格証明から実施します。


動作確認に使用する、空のAPEXアプリケーションを作成します。名前AI Interactive Reportとします。


対話モード・レポートで生成AIを使用するには、APEXアプリケーションのアプリケーション定義AIで、サービスを設定します。

ワークスペース・ユーティリティ生成AIで作成した、生成AIサービスを選択します。


以上で対話モード・レポートで生成AIを使用する準備ができました。

ホーム・ページを開き、対話モード・レポートのリージョンを作成します。

識別名前Apparel ProductsタイトルApparel Productsタイプ対話モード・レポートとします。

ソース位置サンプル・データを選び、サンプル・データとして製品を選択します。

データベースに表を作成せずにレポートの動作を確認できるように、APEX 26.1から追加されたデータ・ソースです。

以上で、動作する対話モード・レポートが作成できました。


ページを実行します。APEX 26.1以前の対話モード・レポートです。


生成AIを使った自然言語による操作を有効にします。

属性タブの生成AIにある自然言語サポートオンにします。

デフォルトの検索モードとしてAIによる検索行検索のどちらかを選べます。

レポート・コンテキストに、このレポートについてAIに解釈させる説明を記述します(レポートの定義情報は、システム・プロンプトに含まれています。レポート・コンテキストはこれらの定義情報に追加されます)。

ここで記述した文章は、レポートの定義情報のひとつとして、生成AIに送信されるシステム・プロンプトに含まれます。生成AIに送信されるのはレポートの定義情報で、レポートのソースが表やビューであっても、それらのメタ・データは生成AIに送信されません。

以上の設定で、対話モード・レポートで生成AIを使用できるようになりました。


対話モード・レポートの検索フィールドへの入力に、AIによる検索行検索のどちらかを選べます。


対話モード・レポートで設定したデフォルトの検索モードは、この設定にあたります。

検索モードがAIによる検索の場合、検索フィールドに自然言語を入力してレポートを操作できるはずなのですが、APEX 26.1ではなぜか、日本語だけ(英語はもちろん韓国語や中国語も大丈夫)が行検索として認識されてしまうようです。


アシスタントを開いて入力すると、生成AIを使った自然言語による操作ができます。


アシスタントに「Shirtsだけを一覧して。」と伝えます。

対話モード・レポートのフィルタとしてCategory = 'Shirts'が追加され、レポートがリフレッシュされます。


このとき、対話モード・レポートのアシスタントに入力したメッセージが、生成AIに送信されます。対話モード・レポートには、アクションとしてレポートに適用できる操作が実装されていますが、それらの操作がツール定義としてメッセージと一緒に送信されています。


すべてのアクションがツール定義に含まれてはいないようですが、例えば、フィルタ・ツール、ソート・ツール、ハイライト・ツールといったツールが(OpenAIでの説明ではFunction calling)利用可能なツールとして、生成AIに送信されています。

生成AIはメッセージが「Shirtsだけを一覧して。」であることを認識して、フィルタ・ツールを呼び出してCategory = 'Shirts'を設定するように、レスポンスを返します。それを受けて、APEXはAPEX_IR.ADD_FILTERといったAPIを呼び出す、といった処理の流れになっています。

そのような処理であるため、任意のSQLが実行できるといった、いわゆるNL2SQLにあるようなセキュリティ上の懸念はありません。生成AIができることは、生成AIへのリクエストにツールとして渡している処理に限定されます。

AI Interactive Reportの説明では「生成AIで検索」できるといったような表現が見られますが、対話モード・レポートのAPIを生成AI経由で呼び出しているというのが処理の実態なので、自然言語で対話モード・レポートを操作する、というのがより正しい説明になるでしょう。

対話モード・レポートの説明はレポート・コンテキストに記述し、それが生成AIに送信されます。レポートのそれぞれの列についても、生成AIに送信するメッセージを設定できます。

列のプロパティとして生成AIが追加されています。

列コンテキストに列の説明を記述します。ここで記述した文章は、生成AIに送信されるメッセージのシステム・プロンプトに追加されます。

それに加えて、参照データ型があります。なし共有コンポーネントSQL問合せ静的値から選んで設定します。


AI Interactive Reportから生成AIに送信されるメッセージに、対話モード・レポートから取り出される(つまり対話モード・レポートのソースから取り出されている)情報は含まれません。

その代わりに、参照データ型から取り出される情報を、その列の参照データ(referenceData)としてシステム・プロンプトに追加します。例えば、対話モード・レポートで個人情報を表示していたとしても、生成AIには参照データとして存在しない人名や電話番号といった情報を送信することができます。

参照データ型静的値を選択した場合、静的値として以下のように値を設定します。システム・メッセージを確認したところ、コンポーネントとしてLOVを流用しているためか、表示値戻り値がありますが、参照データとしてシステム・プロンプトに含まれるのは表示値のみのようです。そのため、参照データ型共有コンポーネントSQL問合せでも、表示値戻り値が同じ値になるように構成すると良いでしょう。


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

NL2SQLとは異なり、データベースに保存されている業務データが生成AIに送信されることが無いように設計されているため、気軽に自然言語でレポートを操作することができます。

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