はじめに
まず簡単な自己紹介をさせていただきます。
都内のIT企業でデータサイエンティストをしております。
趣味でLLMコンペなどに参加したりとデータ分析が好きなので、
この度、一般社団法人金融データ活用推進協会(FDUA)が主催する「第4回 金融データ活用チャレンジ」に参加しました。
本コンペのテーマは「生成AIで実現する経営支援~提案書作成チャレンジ~」です。
有価証券報告書(定性データ)と財務データ(定量データ)から、企業の課題解決に向けた提案書を作成するタスクに取り組みました。
今回私は、金融機関の実務にそのまま導入できるレベルの「完全セキュアなAIアーキテクチャ」を目指し、DataikuとSnowflake Cortex AIを組み合わせて、提案書の自動生成・評価を行うWebアプリケーションを構築しました。
※以後扱うデータはコンペ中に配布されたダミーデータになります。
構築したアーキテクチャのコンセプト
本アプリの3つのコンセプト
-
セキュアなデータ&LLM環境
データ(CSV)とLLMの実行環境をすべてSnowflake内にクローズ。
外部API(OpenAI等)にデータを一切出さず、Snowflake Cortex AIを利用してセキュアに完結させます。 -
作成・評価のマルチエージェント構成
「提案書を作成するエージェント」と「客観的に評価・採点するエージェント」を分離して構築。生成しっぱなしではなく、AI自身に評価させる自動改善ループを組み込んでいます。 -
ビジネス部門も使えるノーコード&ユーザーライクな設計
テクニカル部門だけでなく、現場のビジネス担当者でも簡単に利用・運用できるように、DataikuのVisual Agentを活用した「視覚的に分かりやすいノーコード構築」にこだわりました。
本記事では、この環境をゼロから構築する手順をステップ・バイ・ステップで解説します。
今回は前半戦として、「セキュアな基盤構築(SnowflakeとDataikuの連携)」までの手順をご紹介します。
フェーズ1:Snowflakeのセットアップ
まずは、データとLLMの基盤となるSnowflake側の準備を行います。
Snowflakeの画面左側メニューから「Projects」>「Worksheets」を開き、SQLを実行していきます。
Step 1: クロスリージョン推論の有効化(高性能LLMを使うため)
Snowflake Cortex AIでは、ご自身のアカウントがあるリージョン(東京リージョンなど)によっては、最新の高性能モデルが直接提供されていない場合があります。 そこで、claude-4-5-sonnetなどの高性能モデルを他リージョン経由でスムーズに呼び出せるよう、アカウントレベルでクロスリージョン推論を許可しておきます。
sql
-- ロールをACCOUNTADMINに設定
USE ROLE ACCOUNTADMIN;
-- クロスリージョン推論を全リージョンで許可(これでClaude等が使えます)
ALTER ACCOUNT SET CORTEX_ENABLED_CROSS_REGION = 'ANY_REGION';
-- 確認テスト(エラーが出ず、挨拶が返ってくれば成功です)
SELECT SNOWFLAKE.CORTEX.COMPLETE('claude-3-5-sonnet', 'こんにちは、テストです。');
Step 2: データベース・スキーマ・ウェアハウスの作成
次に、Dataikuからアクセスするための専用の箱(データベース)と計算リソース(ウェアハウス)を作っておきます。(ここの設定値は任意で大丈夫です)
USE ROLE ACCOUNTADMIN;
-- データベースとスキーマの作成
CREATE DATABASE IF NOT EXISTS PROPOSAL_DB;
CREATE SCHEMA IF NOT EXISTS PROPOSAL_DB.DATA_SCHEMA;
-- Dataiku処理用のウェアハウス(最小サイズ)の作成
CREATE WAREHOUSE IF NOT EXISTS DATAIKU_WH
WAREHOUSE_SIZE = 'XSMALL'
AUTO_SUSPEND = 60
AUTO_RESUME = TRUE;
-- 普段使いのSYSADMINロールに権限を付与
GRANT USAGE ON DATABASE PROPOSAL_DB TO ROLE SYSADMIN;
GRANT ALL ON SCHEMA PROPOSAL_DB.DATA_SCHEMA TO ROLE SYSADMIN;
GRANT USAGE ON WAREHOUSE DATAIKU_WH TO ROLE SYSADMIN;
GRANT OPERATE ON WAREHOUSE DATAIKU_WH TO ROLE SYSADMIN;
フェーズ2:SnowflakeとDataikuのセキュア連携(OAuth2設定)
ここが今回のアーキテクチャのキモであり、最も重要な初期設定です。
【なぜOAuth2認証が必要?】
DataikuからSnowflakeに接続する際、通常のパスワードやKey-Pair認証でもデータにはアクセスできます。
しかし、後続でDataikuの「Visual Agent(Tool Use機能など)」を使ってCortexのLLMを高度に呼び出すためには、仕様上OAuth2認証が必須となる場合がございます。
そのため、必ず最初にこの連携を済ませておきます。
Step 1: Snowflake側でOAuth2のセキュリティ統合を作成
Snowflake側でDataiku専用の認証窓口を作ります。
USE ROLE ACCOUNTADMIN;
CREATE OR REPLACE SECURITY INTEGRATION DATAIKU_OAUTH
TYPE = OAUTH
ENABLED = TRUE
OAUTH_CLIENT = CUSTOM
OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'
-- ※ ご自身のDataiku環境のURLに合わせて変更してください
OAUTH_REDIRECT_URI = 'https://<ご自身のDataikuのURL>/dip/api/oauth2-callback'
OAUTH_ISSUE_REFRESH_TOKENS = TRUE
OAUTH_REFRESH_TOKEN_VALIDITY = 86400
OAUTH_ENFORCE_PKCE = FALSE;
作成後、以下のコマンドを実行して OAUTH_CLIENT_ID と OAUTH_CLIENT_SECRET を取得し、メモしておきます。
(※SECRETは結果の行をクリックすると表示されるJSONの中にあります)
DESCRIBE SECURITY INTEGRATION DATAIKU_OAUTH;
SELECT SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('DATAIKU_OAUTH');
Step 2: Dataiku側でConnectionを設定する
Dataikuの画面(Administration > Connections)に移動し、「+ NEW CONNECTION」からSnowflakeを選択して設定します。
・DBなどの情報は先ほど設定した内容を入力
・Auth type: OAuth2
・Client id / Client secret: 先ほどメモした値
・Scope: refresh_token session:role:SYSADMIN
(※真ん中に半角スペース。この指定がないと権限エラーになるので注意!)
・Credentials mode: Per user に変更(※ここも重要です)
設定を保存後、自分のプロフィールアイコンから「Credentials」タブへ進み、SnowflakeへログインしてOAuth連携を許可(Allow)します。
画面に Connection success! と表示されれば、強固でセキュアなパイプラインの開通です!
フェーズ3:DataikuのLLM Mesh設定(Cortexモデルの有効化)
Snowflakeとのセキュアな通信経路が開通したので、次はこの経路を使って「どのLLM(生成AI)を利用するか」をDataiku側に登録します。
DataikuのAI管理機能である「LLM Mesh」を利用して設定していきます。
Step 1: LLM MeshでCortex接続を新規作成
Dataikuの設定画面(Administration)から「LLM Mesh」を開き、「Connections」タブから + NEW CONNECTION > Snowflake Cortex を選択します。
-
Connection: フェーズ2で作成したOAuth接続(
snowflake_oauth_conn)をドロップダウンから選択します。
※これにより、このLLM通信はすべてOAuthのセキュアな認証を経由して実行されるようになります。
Step 2: テキスト生成モデル(LLM)の選択
「Text completion models」のリストから、利用したいLLMにチェックを入れていきます。
今回は提案書作成と評価用に、以下の高性能モデルを選択しました。
-
Claude 4.5 Sonnet/Claude 4.5 Haiku -
Llama 3.3 70Bなどのオープンモデル
【💡 ここがポイント:クロスリージョン推論の恩恵】
実は、利用しているリージョン(東京など)によっては、これらの最新・高性能モデルが直接提供されていない場合があります。
しかし、フェーズ1のStep1でSnowflakeの「クロスリージョン推論」を有効化しておいたおかげで、ここではリージョンの壁を越えて、チェックボックスを入れるだけで複数の強力なLLMを自由に選択・利用できるようになっています!
Step 3: 埋め込みモデル(Embedding)の選択
画面を少し下にスクロールし、「Text embedding models」の項目を設定します。
これは後ほど、有価証券報告書のPDFを読み込ませてRAG(Knowledge Bank)を構築する際に、文章をベクトル化するために必須となるモデルです。
-
Snowflake Arctic Embed Mなどにチェックを入れます。
Step 4: ガードレール(Guardrails)について
画面のさらに下部には「Guardrails」という設定項目もあります。
ここでは「禁止用語チェッカー」や「個人情報(PII)のマスキング」など、金融機関に必須のAIガバナンスをノーコードで設定できます。今回は後続のステップで各エージェントに対して詳細なルールを設定していくため、ここは一旦空欄のまま画面下部の「SAVE」をクリックして保存します。
これで、Dataikuの「脳」となる生成AI群のセキュアな登録が完了しました!
フェーズ4:定性データ(PDF)の格納とRAG(Knowledge Bank)の構築
LLMの準備が整ったので、いよいよコンペで配布されたデータを取り込んでいきます。
まずは、企業の定性的な情報が詰まった「有価証券報告書(PDF)」を読み込ませ、AIが検索・理解できるようにベクトル化(RAG構築)を行います。
Step 1: 有価証券報告書(PDF)のアップロード
Dataikuのプロジェクトメイン画面(Flow画面)から、データを格納するためのフォルダを作成します。
- 画面上部の
+ 新しいデータセットを追加(+ DATASET)をクリックします。 - メニュー内の「Dataiku管理」セクションにある
フォルダーを選択します。 - ラベル(Name)に
securities_reportsと入力し、作成します。 - フォルダの画面が開いたら、コンペで配布された10社分のPDFファイルをすべてドラッグ&ドロップして一括アップロードします。
Step 2: Knowledge Bank(RAG)のビルド
次に、アップロードしたPDFをベクトルデータベース化します。Dataikuの「Knowledge Bank」機能を使えば、面倒なチャンク分割やベクトルDBの構築が完全ノーコードで完了します。
Flow画面に戻り、先ほど作ったフォルダ(securities_reports)を選択した状態で、画面右側のパネルから Build Knowledge Bank をクリックします。
設定画面が開いたら、以下の通りに設定します。
-
Embedding model:
Snowflake Arctic Embed M
※フェーズ3で有効化したCortexのモデルです。
データを外部に出さず、Snowflakeのセキュアな環境内でベクトル化できるのが最大のメリットです。 -
Vector store type:
ChromaDB
※Dataikuに内蔵されているベクトルDBです。
別途クラウド上にPinecone等のインフラを立てる必要がなく、構築コストをゼロに抑えられます。 -
Strategy:
Text-first Extraction
※PDFからのテキスト抽出において最も推奨される安定した手法です。
設定できたら、左下の緑色の ▶ 実行(RUN) ボタンをクリックします!
裏側でPDFの読み込み、テキスト抽出、チャンク分割、そしてベクトル化処理が自動的に開始されます。
10社分のPDFで情報量が多いので、30分~60分程度待って「SUCCESS」と表示されればRAGの構築は完了です。
これで、AIが過去の文脈や企業の課題を正確に引き出すための「外部記憶(ナレッジ)」が完成しました!
フェーズ5:定量データ(財務CSV)のセキュアな格納と連携
定性データ(PDF)の次は、定量データ(財務諸表などの数値データ)を準備します。
セキュリティの観点から、CSVデータをDataikuに直接持たせるのではなく、Snowflake内に格納し、Dataikuからは「参照」のみを行う構成にします。
Step 1: SnowflakeへのCSVロード
SnowflakeのUI(Snowsight)の自動テーブル作成機能を使えば、日本語カラムのCSVもテーブル化できます。(日本語カラムの場合は"○○"で囲みましょう)
- Snowflake左側メニューから
Data>Databases>PROPOSAL_DB>DATA_SCHEMAを開きます。 - 右上の
+ Create(または+ボタン)からTable>From Fileを選択。 - 手元の
financial_data.csvをアップロードします。 - テーブル名を
FINANCIAL_DATAとし、ファイルフォーマット(1行目をヘッダーとする等)を確認してLoadします。
Step 2: DataikuからSnowflakeのデータを読み込む
DataikuのFlow画面に戻り、先ほど入れたデータを参照するデータセットを作成します。
-
+ 新しいデータセットを追加>Snowflakeを選択。 -
Connection: フェーズ2で作った
snowflake_oauth_connを指定。 -
Table: 「GET TABLES LIST」をクリックし、先ほど作成した
FINANCIAL_UTF8を選択して作成します。
これで、データの準備はすべて整いました!
フェーズ6:エージェントに持たせる「ツール(Agent Tool)」の開発
ここからがいよいよ本番です。
Dataiku上でLLMに「自律的にデータを検索・取得させる」ための武器(ツール)をノーコードで作成します。
今回は定性用・定量用で2つのツールを作ります。
Dataiku上部メニューの鳥のアイコン付近の黒いバーから Agent Tool を開き、+ NEW AGENT TOOL をクリックします。
ツール①:ナレッジバンク検索(定性データ用)
有価証券報告書の文章を読むためのツールです。
-
Tool type:
Knowledge Bank Search -
Knowledge Bank: フェーズ4で作成した
securities_reports_embeddedを選択。 - Description for LLM:
- (※ここが重要です。AIが「いつこのツールを使えばいいか」を判断する材料になります)
「企業の事業内容、経営課題、事業方針、リスクなどの定性的な情報を、有価証券報告書の文章から検索する際に使用します。」
ツール②:Custom Python(定量データ取得用)
財務データを検索するためのツールです。
今回は標準の検索ツール(Dataset Lookup)ではなく、LLMに複数年分のデータをより正確なフォーマット(JSON)で渡すために、「Custom Python」ツールを使用します。
-
Tool type:
Custom Python -
目的: LLMが生成した「企業コード」を受け取り、Dataiku上の財務データセット(
FINANCIALDATA_UTF8)から該当企業の過去の財務データを抽出し、LLMが理解しやすいJSON形式で返却します。
以下のPythonコードをエディタ画面に貼り付けます。
import dataiku
import pandas as pd
from dataiku.llm.agent_tools import BaseAgentTool
class MyAgentTool(BaseAgentTool):
def set_config(self, config, plugin_config):
self.config = config
self.plugin_config = plugin_config
def get_descriptor(self, tool):
# LLMにこのツールの使い方(引数と説明)を教える部分
return {
"description": "対象企業の具体的な財務数値を企業コードをキーにして取得します。",
"inputSchema": {
"type": "object",
"properties": {
"company_code": {
"type": "string",
"description": "企業コード"
}
},
"required": ["company_code"]
}
}
def invoke(self, input, trace):
# 実際にデータセットを検索して返す処理
args = input["input"]
company_code = args["company_code"]
dataset = dataiku.Dataset("FINANCIALDATA_UTF8")
df = dataset.get_dataframe()
filtered_df = df[df["コード"].astype(str) == str(company_code)]
if filtered_df.empty:
return {"output": "データが見つかりませんでした。"}
result = filtered_df.to_json(orient="records", force_ascii=False)
return {"output": result}
コード内の get_descriptor でLLMに対する説明と必要な引数(company_code)を定義し、invoke で実際のPandasを使ったフィルタリング処理を記述しています。
これにより、コンペの要件である「過去の財務推移」を網羅したデータをLLMへ確実に提供できるようになります。
フェーズ7:マルチエージェントの構築(Structured Visual Agent)
準備したツールを持たせて、「提案書作成エージェント」と「評価・採点エージェント」の2つを連携させるパイプラインを構築します。
上部メニューから Agent/GenAI Model を開き、+ NEW AGENT をクリック。
今回は複数エージェントを連携させるため、**「Structured Visual Agent(構造化エージェント)」**を選択します。
ブロック1:core_loop(提案書生成モジュール)
ユーザーからの指示を受け取り、自分で考えてツールを使い、提案書を執筆するメインブロックです。
-
Block type:
Core Loop(ReActエンジン) -
LLM:
Claude 4.5 Haiku(コストと速度のバランスが良いため) - Tools: 先ほど作成した2つのツールを両方追加します。
-
Pass conversation history:
ON -
Additional output handling:
Add to internal conversation history(生成した提案書を次の評価ブロックに読ませるため必須) -
Default next block:
評価LLM_v2(生成後、自動で評価ブロックへ遷移させます)
【💡 Instructions(プロンプト)の工夫】
- ロール定義:「大手コンサルティングファームのシニアパートナーとして振る舞うこと」
- ルール:「数値はすべてツール経由で取得し、推測は禁止」「各章800文字以内」
- フォーマット:第1章〜第3章の構成を厳密に定義
- 終了条件:「『提案書作成完了』と出力して停止すること」(※これを書かないとLLMが不要なツール呼び出しを無限に続けてしまうため重要です)
ブロック2:評価LLM_v2(自動評価・採点モジュール)
完成した提案書をコンペの審査基準(地域性、業界課題への対応など)に照らし合わせて自動評価します。
-
Block type:
Core Loop -
LLM:
Claude 4.5 Haiku -
Pass conversation history:
ON -
Max loop iterations:
1(ツールを使わず1回で出力させるため)
【⚠️ 構築時のハマりポイントと突破方法(重要!)】
この評価ブロックの構築時、Claude APIの厳格な仕様によりHTTP 400エラーが連発しましたが、以下のテクニックで回避しました。
-
ツール定義の不一致エラー(tool_use blocks must include tool definition)
前の生成ブロックでツールを使った履歴がそのまま評価ブロックに渡されると、評価ブロック側にも「ツールの定義」がないとAPIがエラーを吐きます。
解決策:評価ブロックにもダミーとして同じ2つのツールを登録し、Instructionsの冒頭に「注意:ツールが利用可能ですが、絶対に使用しないでください。」と明記して制御しました。 -
履歴の末尾がAssistantだとエラーになる
解決策:評価ブロックのAdditional user messageという項目に「上記の提案書を評価してください。」と設定することで、強制的に履歴の最後をUserメッセージにしてエラーを回避しました。
(参考)Block 2: 評価(評価LLM_v2)の設定とシステムプロンプト
System Prompt(Instructions): 以下のプロンプトを設定しました
""""""""""""""""""""""""""""""""""""""
あなたは評価担当者です。
この会話でassistantが出力した内容を提案書として扱い、以下の表を必ず出力してください。
提案書が短い・不完全でもC評価として表を出力すること。評価拒否は禁止。
評価結果
| 基準 | 評価 | コメント |
|---|---|---|
| 1. 財務分析の正確性 | ? | コメント |
| 2. 戦略の具体性 | ? | コメント |
| 3. 実行可能性 | ? | コメント |
総合判定:合格 or 不合格
改善指示:
""""""""""""""""""""""""""""""""""""""
フェーズ8:マルチエージェントのエンドツーエンド実行と結果確認
全ての設定が完了したら、構築した「Structured Visual Agent」のチャットモードを開き、実際にテスト実行を行います。
結論から言うと、チャットモードでのエンドツーエンド実行は完璧に動作しました!
実行プロセスの確認ポイント
以下の全ステップが、事前のシステムプロンプトの指示通りにシームレスに実行されていることが確認できます。
-
core_loopの動作とツール呼び出し: OK- Custom Python(財務データ取得)と Knowledge Bank Search(RAG検索)が正しく呼び出されています。
-
3章構成の提案書生成: OK
- ハルシネーション(情報の捏造)なく、取得した定性・定量データに基づく正確な提案書が生成されました。
-
core_loopから評価LLM_v2への自動遷移: OK- 提案書完成の合言葉が出力された直後、ユーザーの介入なしで自動的に評価エージェントへ処理が移行しています。
-
評価表の厳格な出力: OK
- プロンプトで強制した通り、「財務分析の正確性(B)」「戦略の具体性(B)」「実行可能性(C)」の評価表と総合判定(不合格)が、指定フォーマット通りに崩れることなく出力されました。
-
改善指示の提示: OK
- 優先度(1〜4)と詳細な改善項目が提示されています。
ここで重要なのは、提案エージェントも評価エージェントも、プロンプトの指示を完璧に遵守しているという点です。
評価結果は単なるダメ出しではなく、「2025年度の営業利益率低下の要因を売上原価率などに分解すべき」「1人当たり売上目標達成のための比較分析がない」といった、取得したソース(根拠)に基づいた具体的かつ実用的な改善案が提示されています。
VIEWタブでのエージェント構成の可視化
このような複雑なマルチエージェントの処理フローは、Dataikuのエージェント設計画面にある「VIEW」タブから、直感的なフロー図として確認できます。
Start地点から始まり、core_loop ブロック(Claude 4.5 Haikuと2つのツール)を通過し、Default case を経て 評価LLM_v2 ブロック(同LLMと評価ロジック)へと流れるプロセスが一目でわかります。
また、Dataiku全体のFlow画面を見ても、Snowflakeから取得した構造化データ(財務データ)と、PDFから構築した非構造化データ(Knowledge Bank)、そしてそれらを束ねるエージェントの繋がりが綺麗に可視化されています。
おわりに
本記事では、Dataiku と Snowflake Cortex を活用し、セキュアな環境下で「提案書自動生成&自動評価ループ」を構築する手順を全公開しました。
今回のアーキテクチャの強力なポイントは以下の3点です。
- セキュアなデータ&LLM環境(Snowflake内でデータとAI処理を完結させつつ、クロスリージョン推論で最新LLMを活用)
- 生成と評価のマルチエージェント構成(プロンプトエンジニアリングによる自律的な品質改善ループ)
- 視覚的でノーコードな構築(技術部門・ビジネス部門どちらも理解しやすいGUI/ノーコード機能)
金融業界をはじめとする厳格なデータ管理が求められる現場において、生成AIを安全かつ強力なビジネスの武器にするためのベストプラクティスとして、本記事が皆様のプロジェクトの参考になれば幸いです!




























