新機能のAgent Workbenchを簡単なチュートリアルシナリオで試してみる。
Agent WorkbenchはAIモデルを使ったService Actionを作るフレームワーク的な機能。
Agentic Appで作成するService Actionの構成
各AgentはService Actionになる。
Service Actionは以下の通り、自動で作成されるAgentsFlow Server Actionを呼び出しその結果を返す。

AgentsFlowは、
- GetGroundingData Server Action: あちこちから関連データを集めてくる
- BuildMessages Server Action: GroundingData・Service Actionの入力・予め用意したプロンプトを組み合わせてAI Modelに渡すメッセージを構築
- AI Modelにメッセージを渡し、結果を返す
という構成になっている。本来はさらに、ユーザーと会話を行うための履歴保存機能もあるが、簡単な動作確認目的なので今回は省略する。
環境情報
ODC Studio (Version 1.6.3)
ODC Personal Edition
チュートリアルシナリオ
ユーザーが自分で商品や場所のレビューを投稿できるサイトを検討する。
投稿されるレビューを自動でAI Agentが審査し、明らかに安全なものは即承認・疑いが残るものは人間の担当者にタスクを割り当て(疑問点の種類をタグづけ、コメントをつける)・明らかに規約違反であれば自動で却下する。
AI Model
ODC Portalに用意されているTrialのAI Modelを使う。
PEでは、以下の2つのModelが事前に登録済み。
ODC PortalのINTEGRATE > AI modelsページで確認できる。

Agentic Appを作成
App作成時のオプションにAgentic appが追加されている。

NameとDescriptionを指定するUIは同じなので省略(Nameは「CommentReviewAgent」とした)。
利用するAIモデルを選択して「Create agentic app」。

Service Actionの実装
GetGroundingData
そもそもGrounding Dataが何かについては、
https://learn.outsystems.com/training/journeys/build-agentic-powered-app-3411/ground-data-for-ai-agent/odc/11013
に解説動画がある。
Grounding supplies your AI agent with factual, up-to-date information from your system.
要は、AI Agentの判断に利用するデータを提供する場所。データを集めてJSONに変換してOutput Parameterに詰めるまでが仕事。
ここでは以下の二点を取得する。修正後のActionのI/Fは以下の通り。

ユーザーから受け取ったIdでEntityを検索し、レビューコメントを取得する
GetGroundingDataにはEntityのIdをInput Parameterとして追加した。
このIdはさらに、Service ActionのInput ParameterとしてConsumerから受け取る。Consumerは、Service Actionを呼ぶ前に、ユーザーが入力したレビューコメントをこのEntityに保存しておくことを想定している。
実装はIdでEntityをAggregateし、取得したレコードのレビューコメント属性を編集するだけなのでイメージは省略。
結果は、Output ParameterのReviewCommentに編集する。
AIが判定結果に付与するタグをStatic Entityから取得する
利用できるタグはStatic EntityのTagとして事前に用意しておいた。

このStatic Entityを全件Aggregateで取得し、タグ名が入っているLabel属性を取り出してText Listに詰め替える。
解説動画では、AIに渡すデータはJSONにする、ようなことが書いてあったので、このListをJSONSerializeしたものをOutput Parameter AvailableTagsInJsonに編集。

BuildMessages
BuildMessages ActionではAIに対するプロンプトを二種類用意して、Output Parameter Messagesに詰める。デフォルトで生成されるBuildMessagesにSystem PromptとUser Promptを設定する部分が用意されているので、必要な部分を編集して使う。
System Prompt
AIモデルに、果たすべき役割と制約などを伝えるプロンプト。
Geminiにプロンプトを考えてもらって、使いやすいようにmarkdown形式に手動で編集(Geminiは思うようにmarkdownにしてくれなかったので)、それをOutSystemsの文字列にした。また、ActionのInput Parameterとして受け取った利用できるタグリスト(AvaiableTagsInJson)を埋め込んでいる。
"# 役割と目的
あなたは、ユーザーが投稿した商品・場所のレビューコメントを、当サイトのコンテンツポリシーに基づき審査するAI Agentです。あなたの目的は、すべてのレビューを以下の3つのいずれかに分類し、その後の処理を決定することです。
1. 承認 (APPROVED): ポリシーに完全に準拠している
2. 却下 (REJECTED): 明らかにポリシーに違反している
3. 要確認 (PENDING_HUMAN): 自動判定が困難で、人間の担当者によるチェックが必要
# 判断基準
以下の基準に基づき、レビューを分類してください。
- 基準違反がなく、内容が適切である
- 承認 (APPROVED)
- 明白なポリシー違反がある
- 却下 (REJECTED)
- 具体例
- 1. 攻撃的コンテンツ: 誹謗中傷、差別、ハラスメント、個人情報の公開
- 2. 違法行為: 違法薬物、犯罪行為を助長・言及する内容
- 3. スパム/宣伝: 無関係な商品の宣伝、アフィリエイトリンク、同一内容の大量投稿
- 4. 性的コンテンツ: 露骨な描写
- グレーゾーンであり、AIでの最終判断が困難である
- 要確認 (PENDING_HUMAN)
- 具体例
- 1. 信頼性の懸念: 虚偽・誇張の可能性、極端なレビューだが断定できない
- 2. 不適切な表現: 軽度の暴言、俗語、公序良俗に反するが「却下」基準までは満たさない
- 3. 関連性の疑問: サービスと無関係な個人的な不満や意見だが、ポリシー違反とは断定できない
# 出力タスクと形式
あなたは、与えられたレビューテキストを分析し、必ず単一のJSON形式で結果を出力してください。JSONには以下の3つのフィールドを含めます。
- Status
- 必須
- 最終判定結果。値は APPROVED, REJECTED, または PENDING_HUMAN のいずれか
- Tags
- 任意
- PENDING_HUMAN または REJECTED の場合に必ず適用する、違反または疑問点のカテゴリタグ(複数選択可)
- comment_to_human
- 任意
- PENDING_HUMAN の場合に必ず記載する、人間担当者向けの簡潔なコメント。却下理由が明確な場合はREJECTEDの場合も記載する
# 使用可能なタグ一覧
tagsフィールドに使用できるタグは以下のリストに限定されます。
" + AvaiableTagsInJson + "
"
User Prompt
AIモデルに実行して欲しいタスクを伝えるプロンプト。
これもGeminiに考えてもらった。ユーザーが入力したレビューコメント(ReviewComment)を埋め込んでいる。
"# 実行指示
これからあなたにユーザーのレビューテキストを与えます。あなたは上記の役割、判断基準、および出力形式に従い、最も適切な結果のJSONのみをコードブロック内に出力してください。
" + ReviewComment
動作確認
上記BuildMessagesの結果(Output Parameter Messages)をAI Modelに渡す。

以下、いくつかのパターンで実行例を示す。想定通りに動いてくれていそうだ。なかなかの判断力に見える。フォーマットがプログラムで使いにくいもの(JSON前後の余計な装飾がついている)ので、プロンプトを改善し、JSON部分だけを出力するように要求したほうがいいかもしれない。
承認の例
OutSystemsSampleData/Sample_Reviews Entityに手頃な英語のレビューコメントがあったのでこれを処理してみる。→サンプルにあるような正当なレビューなので承認となった。
「Had an old one for years. Had several batteries around to ensure I was never without communications. Was time to upgrade due to application that no longer worked. Was hesitant to purchase a phone that did not have replaceable battery. Looked at other brand phones but decided to stick with this because of familiarity. I am exceptionally surprised by the battery life and how much more responsive it is. It also takes exceptional pictures.」

要確認の例
問題になりそうなレビューコメント例をGeminiに考えてもらった。
「店員の態度がクソすぎ。もう二度と行かねえわ。」→危険そうなコメントだが、想定通り人間の判断を仰ぐ結果になっている。この結果を処理し、WorkflowのHuman Activityで担当者にチェックタスクを割り当てればいいだろう。

却下の例
レビューに他サービス宣伝を混ぜた場合もGeminiに考えてもらった。
「この店の料理は正直がっかり。本当にコスパの良いグルメ情報が欲しければ、短縮URLをブラウザに貼り付けて見てください。私のおすすめの店が大量に載っています。」→ちゃんと却下された。判断根拠も正当なものが出力されたので、ログにでもはいておけば、後から分析に使うのにも問題なさそう。

