
源内の ExApp(外部AIアプリ連携)を使って、行政実務用RAGテンプレートやカスタムAPIを源内 Web に登録してみた
いわさです。
前回の記事で、デジタル庁のガバメントAI「源内(GENAI)」の Web インターフェース(genai-web)を個人検証用 AWS アカウントにデプロイしました。
前回はチャットや文章生成などの汎用 AI 機能を確認しましたが、源内にはもうひとつ大きな特徴があります。
ExApp(外部AIアプリ連携)という仕組みで、REST API ベースの外部マイクロサービスを源内の UI から利用できる機能です。
GenU にはない源内独自の機能で、REST API のプロトコルに準拠すればクラウドや言語を問わず登録できます。
デジタル庁は源内 Web とは別に、源内 AI アプリ(genai-ai-api)というリポジトリで ExApp に登録できる行政実務用 AI アプリのテンプレートも公開しています。
ガバメントクラウドに採択された3つのクラウドサービス向けのテンプレートが含まれています。
| クラウド | テンプレート | 概要 |
|---|---|---|
| Amazon Web Services | クエリ拡張 RAG | Bedrock Knowledge Base + OpenSearch Serverless を使った RAG API |
| Microsoft Azure | vLLM セルフデプロイ | PLaMo 翻訳モデルを VMSS 上の vLLM でホスティング + Azure OpenAI |
| Google Cloud | 法制度 AI アプリ(Lawsy) | BigQuery ML ベクトル検索 + Gemini で法令レポートを生成 |
今回はこの中から AWS のクエリ拡張 RAG テンプレートをデプロイして ExApp に登録してみます。
さらに、Bedrock とは無関係な独自のカスタム API も作成して、ExApp のフォームカスタマイズも試してみます。
AWS クエリ拡張 RAG をデプロイして ExApp に登録する
クエリ拡張 RAG は以下の構成です。
- API Gateway が外部からのリクエストを受け付け、x-api-key ヘッダーで認証
- RAG Lambda(Python)がクエリ拡張 → Knowledge Base 検索 → 関連性評価 → 回答生成の一連の処理を実行
- Bedrock Knowledge Base が OpenSearch Serverless をバックエンドにドキュメントをベクトル検索
クエリ拡張については以前AWSさんの記事でも紹介されています。
ちなみに通信経路ですが、源内 Web から ExApp を呼び出す際は、源内 Web のバックエンド Lambda が VPC 内から NAT Gateway 経由でこの API Gateway にリクエストを送ります。
API Gateway の手前には WAF がホワイトリスト方式で配置されており、源内 Web の NAT Gateway Elastic IP のみ許可する構成です。
RAG パイプラインの各ステップで使用するモデルは TOML ファイルで設定できます。
デフォルトでは回答生成に Claude Haiku 4.5、クエリ拡張・検索生成・関連性評価に Nova 2 Lite が使われます。
config/apps/qerag.toml でデフォルト設定から変更したい項目だけを記述する仕組みです。
# アプリケーション基本情報
name = "Query Expansion RAG"
description = "クエリ拡張RAG(サンプル)"
# 回答生成の設定(デフォルトから変更する項目のみ)
[answer_generation]
systemPrompt = """
あなたはXXXアプリケーションに精通したアシスタントです。社内規約・利用マニュアルに精通したヘルプデスク担当者として、ユーザーからの質問に簡潔に回答してください。
...
"""
# 詳細回答生成・関連性評価・検索生成・クエリ拡張はすべて Nova 2 Lite に変更
[answer_generation_detail]
modelId = "jp.amazon.nova-2-lite-v1:0"
[relevance_rating]
modelId = "jp.amazon.nova-2-lite-v1:0"
[retrieve_and_generate]
modelId = "jp.amazon.nova-2-lite-v1:0"
[query_expansion]
modelId = "jp.amazon.nova-2-lite-v1:0"
デプロイは AWS CDK で行います。
前提条件(CDK bootstrap、Bedrock のモデルアクセス有効化など)は README に記載されているのでそちらを参照してください。
cd aws/query-expansion-rag
npm ci
npx cdk deploy --all -c env=-dev --profile hoge --require-approval never
5つのスタックが作成されます。
| スタック | 役割 |
|---|---|
| ApiWafStack | API Gateway 用の WAF WebACL |
| qerag-shared-1-SwitchRoleStack | データ管理者用の IAM スイッチロール |
| SharedCmekStack-dev | 共通 KMS 暗号化キー |
| qerag-shared-1-qeRagKB | Bedrock Knowledge Base + OpenSearch Serverless |
| qerag-shared-1-qeRagApi | API Gateway + RAG Lambda |
デプロイ中にいくつかエラーに遭遇しました。
WAF の allowedIpV4AddressRanges にデフォルトで 0.0.0.0/0 が設定されていますが、WAFv2 の IPSet はこの値を受け付けません。
公式ドキュメントによると、WAF は /0 をサポートしていません。
AWS WAF supports all IPv4 and IPv6 CIDR ranges except for /0.
デプロイ時点でホワイトリストで許可するIPアドレスレンジを指定する必要があります。
ここには源内 Web の NAT Gateway の Elastic IP を CIDR 形式で設定します。
allowedIpV4AddressRanges: [
"43.206.xxx.xxx/32", // 源内 Web の NAT Gateway Elastic IP 1
"3.113.xxx.xxx/32", // 源内 Web の NAT Gateway Elastic IP 2
],
また、SwitchRole スタックは IAM Identity Center(SSO)前提の設計なので、SSO 未使用の個人検証環境では IAM ユーザーの ARN を直接指定するよう修正が必要でした。
具体的には parameter.ts の switchRoleName に IAM ユーザーの ARN を設定し、switch-role-stack.ts の信頼ポリシー生成ロジックで ARN が arn:aws:iam で始まる場合は SSO ロールパスを組み立てずにそのまま使うよう分岐を追加しています。
apiLambdaIntegrationTimeout もデフォルトの 180 秒が REST API の上限(29 秒)を超えるため、parameter.ts で 29 にオーバーライドしています。
Knowledge Base にドキュメントをアップロード
デプロイ直後は Knowledge Base にドキュメントがないため、API を呼び出しても「情報が不足している」という回答になります。
リポジトリにサンプルデータは含まれていないので、自分でドキュメントを用意する必要があります。
データソースの S3 バケットには inclusionPrefixes: ['docs/'] が設定されているので、docs/ 配下にドキュメントをアップロードします。

今回は genai-ai-api リポジトリ自身の README やドキュメント(26 ファイル)をデータソースとしてアップロードしてみました。
なお Knowledge Base はデータソースと同期をする必要がありますのでやっておきます。

26 ドキュメントすべてがインデックスされました。
ExApp として登録する
API エンドポイントと API キーは CloudFormation の出力から取得できます。

源内 Web のチーム管理画面から ExApp を登録します。
「AI アプリを作成」画面で、名前・概要・使い方のほか、API エンドポイントの URL、API キー、API リクエストのデータ形式(JSON)を入力します。

ExApp の API は {"inputs": {...}} を受け取り {"outputs": "..."} を返す REST API のプロトコルに準拠する必要があります。
「API リクエストのデータ形式」には、源内の UI に自動生成するフォームの定義を JSON で記述します。
今回は質問テキストを入力するテキストエリアだけのシンプルな構成にしました。
{"question": {"type": "textarea", "title": "質問", "desc": "ドキュメントに関する質問を入力してください", "required": true}}
登録後、AI アプリ一覧に表示されるようになりました。


ExApp を開いていみるとこんな感じで質問して回答を得ることができます。

源内 Web の UI から、裏側の AWS Bedrock Knowledge Base + OpenSearch Serverless を使った RAG が動いている状態です。
カスタム API を作って ExApp に登録する
ExApp は REST API であれば何でも登録できるので、Bedrock とは無関係なシンプルなテキスト処理 API を作って、フォームのカスタマイズも試してみました。
Lambda + API Gateway で、テキストの大文字変換・文字数カウントなどを行う API を CDK でデプロイしました。
def handler(event, context):
body = json.loads(event.get("body", "{}"))
inputs = body.get("inputs", {})
input_text = inputs.get("input_text", "")
operation = inputs.get("operation", "uppercase")
result = process_text(input_text, operation)
return response(200, {"outputs": result})
{"inputs": {...}} を受け取り {"outputs": "..."} を返すだけ。
これが ExApp プロトコルの最小要件です。
先ほどの RAG では textarea だけでしたが、今回は select(ドロップダウン)と file(ファイルアップロード)も追加してみます。
源内 Web のソースコードを確認したところ、ExApp のフォームタイプは text、number、textarea、select、radio、checkbox、file、hidden の8種類が使えるようです。
今回は textarea、select、file の3種類を使ってみました。
{
"input_text": {
"type": "textarea",
"title": "テキスト",
"desc": "処理したいテキストを入力してください",
"required": true
},
"operation": {
"type": "select",
"title": "処理内容",
"desc": "実行する処理を選択",
"items": [
{"value": "uppercase", "title": "大文字変換"},
{"value": "lowercase", "title": "小文字変換"},
{"value": "char_count", "title": "文字数カウント"}
],
"required": true
},
"files": {
"type": "file",
"title": "ファイル",
"desc": "CSVファイルをアップロードするとテーブル表示します"
}
}

なお、select の選択肢は options ではなく items で、各要素は { title, value } の形式です。
ここを間違えるとドロップダウンの選択肢が表示されないのでご注意ください(実際にハマりました)。


テキストを入力してドロップダウンから「文字数カウント」を選択し「実行」を押すと、API からの Markdown レスポンスがテーブルとしてレンダリングされました。

Bedrock を使わないシンプルな API でも、ExApp として登録すれば源内の UI から利用できることが確認できました。
outputs に Markdown を返せばリッチな表示も可能です。
AWS 利用料金の試算
クエリ拡張 RAG は OpenSearch Serverless を使うのでランニングコストが少し気になります。
また、前回の記事では源内 Web 自体のランニングコストを確認していなかったので、あわせて試算してみました。
| 構成 | 月額固定費目安 | 主要コスト |
|---|---|---|
| 源内 Web のみ | 約 $20〜30 | WAF(WebACL × 3)が大半 |
| 源内 Web + クエリ拡張 RAG 1つ | 約 $200〜390 | OpenSearch Serverless の OCU が大半 |
| 源内 Web + カスタム API(Lambda + APIGW) | 約 $20〜30 | ExApp 自体の追加コストはほぼゼロ |
源内 Web のみの場合、WAF の WebACL 料金($5/月 × 3つ)が主要コストで、それ以外はほぼ従量課金です。
GenU だと WAF は CloudFront 用の1つだけですが、源内では API Gateway や Cognito User Pool にも Regional WAF が追加されているため、WAF のコストが少し高くなります。
クエリ拡張 RAG を追加した場合のコストの大部分は OpenSearch Serverless です。
1 OCU = $0.24/時間(東京リージョン)で、最低でもインデックス用 0.5 OCU + 検索用 0.5 OCU = 1 OCU が必要です。
スタンバイレプリカを有効にすると最低 2 OCU になります(今回のデプロイではデフォルトの無効設定)。
カスタム API のように Lambda + API Gateway だけの構成なら追加コストはほぼゼロなので、シンプルな API から始めるのが手軽です。
ExApp でできること・できないこと
検証を通じてわかった ExApp の特性を整理します。
できること:
- 8種類のフォームコンポーネント(text / number / textarea / select / radio / checkbox / file / hidden)を組み合わせた入力画面の自動生成
- REST API であればクラウドや言語を問わず登録可能
outputsに Markdown を返すことでリッチな結果表示- ファイルのアップロード(Base64 エンコードで API に送信)
artifactsでファイル(画像等)を返すことも可能
できないこと:
- チャット形式のインタラクティブなやり取り(1ショットのリクエスト/レスポンスのみ)
- ストリーミングレスポンス
- フォームのレイアウトやデザインのカスタマイズ(フィールドは縦に並ぶ固定レイアウト)
チャットのようなインタラクティブな機能は源内 Web の汎用 AI 側で提供されていて、ExApp は「特定の業務に特化した API を GUI から呼び出す」ための仕組みという位置づけですね。
さいごに
本日は源内の ExApp(外部 AI アプリ連携)の仕組みを確認し、行政実務用 RAG テンプレートのデプロイと、独自のカスタム API の登録を試してみました。
ExApp の仕組みは面白いですね。
API エンドポイントと API キー、リクエストのデータ形式を JSON で定義するだけで、源内の UI にフォームが自動生成されて外部 API を呼び出せます。
REST API のプロトコルに準拠すれば AWS に限らず Azure や Google Cloud 上の API も登録できるので、源内 Web を共通のフロントエンドとしてマルチクラウドの AI アプリを束ねられる設計になっています。







