
はじめに
こんにちは。LayerX のバクラク事業部で機械学習エンジニアをしております島越(@nt_4o54)です。 この記事は LayerX Tech Advent Calendar 2025の 22 日目の記事です! 今回の記事では、AI Agent のプロトタイプ開発において、Snowpark Container Service(SPCS)を活用したアプローチについてご紹介します。
AI Agent 開発における「データアクセス」という壁
AI Agent 開発は、従来の機械学習 API 開発とは異なる課題に直面します。
従来の機械学習 API では、入力されるデータは比較的限定的でした。例えば、AI-OCR では書類の画像や PDF が入力され、書類に記載された項目が出力されます。推薦モデルでは、ユーザーや商品の ID を入力に、事前計算された特徴量からランキングを出力します。どちらも、入力データの範囲が明確に定義されています。
一方、AI Agent では状況が大きく異なります。単に ID だけでなく、その ID に紐づく自然言語としての名前や説明、関連するメタデータをリアルタイムに取得する必要があります。いわゆる「Context Engineering」を突き詰めていくと、多種多様なデータソースからデータを取得していく必要があり、開発段階からすべてのデータ連携部分を作り込むのは、「使われないものを作る」ことに繋がりかねません。

開発環境と本番環境のギャップ
さらに厄介な問題があります。開発環境のダミーデータで AI Agent を作って上手くいったとしても、実際の本番データで同じように動作するかは保証されません。
精度の面では、本番データ特有のノイズや多様性に対応できるかという課題があります。 体験の面では、Agent 特有の待ち時間や、人間へのフォールバックが発生した際のユーザー体験は、実際にフロントエンドまで作って触ってみないと分からないことが多いです。
しかし、開発段階で本番の MySQL データベースを直接参照することは、本番環境への負荷増加やセキュリティインシデントのリスクがあり、気軽に行うことはできません。
そこで必要になるのが、「安全に」「簡単に取り替え可能な」データアクセス方法と、それを用いた Agent アプリを社内に簡単にデプロイする基盤です。
LayerX における AI Agent 開発の背景
LayerX では近年、AI-BPO 事業を展開しており、社内アプリでのみ動作する Agent 開発も行っています。 このような文脈では、最初から綺麗なアプリを作るよりも、まずは AI-BPO の業務で使えるような Agent を作り、実際の業務に組み込んだ上で社内メンバーで高速に検証することが重要です。
AI-BPO 事業については、代表の福島の記事などを参照してください。
LayerX のデータ基盤と Snowflake
LayerX では、データウェアハウス(DWH)として Snowflake を全社的に導入しています。さらに、データエンジニアリングチームによってデータ基盤が整備されており、本番データベース(MySQL など)のデータが 1 分以内でニアリアルタイムで Snowflake に連携される仕組みが構築されています。また、過去の任意時点でのスナップショットも取得できたりと、検証基盤としても充実した環境が整っています。
このように Snowflake 上に全てのデータが集まってくる基盤が整っているので、本番 DB ではなく Snowflake 上のデータを参照した上で AI Agent を動かす基盤をまず作ることを目指しました。 その上で、作成したプロトタイプを提供する基盤として我々が注目したのが Snowpark Container Service(SPCS) です。
Snowpark Container Service(SPCS)とは
概要
Snowpark Container Service は、Snowflake が提供するフルマネージドなコンテナ実行環境です。Kubernetes ライクなマルチコンテナ環境をデプロイでき、Snowflake のデータウェアハウスと密に連携したアプリケーションを構築できます。
SPCS の基本的な仕組み
SPCS を理解するには、以下の 4 つのコアコンポーネントを押さえておく必要があります。

1. Image Registry
Snowflake が提供する OCI 準拠のコンテナレジストリです。Docker Hub や Amazon ECR 、Google Container Registry のような役割を果たします。
-- Image Repository の作成 CREATE IMAGE REPOSITORY my_db.my_schema.my_repo; -- リポジトリの URL を確認 SHOW IMAGE REPOSITORIES;
# Snowflake CLI (snow) を使う場合 snow spcs image-repository create my_db.my_schema.my_repo # リポジトリの URL を確認 snow spcs image-repository url my_db.my_schema.my_repo
Docker CLI を使って、ローカルでビルドしたイメージをこのリポジトリにプッシュします。SPCS は外部レジストリ(Docker Hub など)から直接イメージを pull することはできないため、必ず Snowflake の Image Registry を経由する必要があります。
# Docker イメージのビルドとプッシュ docker build -t my-agent-app . # Snowflake レジストリへのログイン snow spcs image-registry login # タグ付けとプッシュ docker tag my-agent-app <snowflake-registry-url>/my_db/my_schema/my-agent-app:latest docker push <snowflake-registry-url>/my_db/my_schema/my-agent-app:latest
2. Compute Pool
サービスが実行される仮想マシン(VM)ノードの集合です。Snowflake の Virtual Warehouse に似た概念ですが、コンテナワークロード向けに最適化されています。
-- Compute Pool の作成 CREATE COMPUTE POOL my_pool MIN_NODES = 1 MAX_NODES = 3 INSTANCE_FAMILY = CPU_X64_S; -- インスタンスタイプを指定
# Snowflake CLI (snow) を使う場合 snow spcs compute-pool create my_pool \ --min-nodes 1 \ --max-nodes 3 \ --family CPU_X64_S # Compute Pool の状態確認 snow spcs compute-pool status my_pool
CPU_X64_XS/CPU_X64_S/CPU_X64_M/CPU_X64_L: CPU 最適化HIGHMEM_X64_M: メモリ最適化GPU_NV_S/GPU_NV_M/GPU_NV_L: GPU 搭載(ML ワークロード向け)
Compute Pool は負荷に応じて MIN_NODES から MAX_NODES の範囲で自動スケールします。
T4 や A100 といった GPU も使えるので GPU を使ったサービスを作ることができるのも特徴です。
3. Service Specification
サービスの構成を定義する YAML ファイルです。Kubernetes の Manifest に相当します。コンテナの定義、環境変数、エンドポイント、ボリュームマウントなどを記述します。
公式 Documentを AI に読み込ませれば特に問題なく使えると思います。
ここで、public: trueと設定されているのを見て「大丈夫か?」と感じるかもしれませんが、これはインターネットに公開しているわけじゃなくて、SPCS 外のネットワークに公開するという設定です。
そのため、実際にアクセスするときは Snowflake 上で認証・認可されたユーザーだけがアクセス可能なのでセキュアに保たれています
spec: containers: - name: frontend image: /my_db/my_schema/my_repo/nextjs-app:latest resources: requests: memory: 1Gi cpu: 0.5 limits: memory: 2Gi cpu: 1 - name: backend image: /my_db/my_schema/my_repo/fastapi-backend:latest env: SNOWFLAKE_WAREHOUSE: my_warehouse resources: requests: memory: 2Gi cpu: 1 endpoints: - name: app port: 3000 public: true
4. Service
Specification をもとに Compute Pool 上で起動される、長期稼働型のコンテナアプリケーションです。明示的に停止するまで継続して動作し、コンテナがクラッシュした場合は Snowflake が自動的に再起動します。
-- Service の作成 CREATE SERVICE my_db.my_schema.my_agent_service IN COMPUTE POOL my_pool FROM SPECIFICATION $$ spec: containers: - name: app image: /my_db/my_schema/my_repo/my-agent-app:latest endpoints: - name: app port: 8080 public: true $$; -- Service の状態確認 SHOW SERVICES; DESCRIBE SERVICE my_agent_service;
# Snowflake CLI (snow) を使う場合 # spec.yaml に Service Specification を記述しておく snow spcs service create my_db.my_schema.my_agent_service \ --compute-pool my_pool \ --spec-path spec.yaml # Service の状態確認 snow spcs service status my_db.my_schema.my_agent_service # Service のログ確認 snow spcs service logs my_db.my_schema.my_agent_service --container-name app --instance-id 0 # Service のエンドポイント URL を取得 snow spcs service list-endpoints my_db.my_schema.my_agent_service
コンポーネント間の連携フロー
- イメージの準備: ローカルで Docker イメージをビルドし、Image Repository にプッシュ
- インフラの構築: Compute Pool を作成(または既存のものを利用)
- 仕様の定義: Service Specification で構成を記述
- デプロイ:
CREATE SERVICEで Compute Pool 上にサービスを起動 - アクセス: 公開エンドポイント経由でアプリケーションにアクセス
サービス内のコンテナからは、Snowflake に直接接続して SQL を実行したり、Snowflake ステージ上のファイルにアクセスしたりできます。これが SPCS の大きな強みです。
補足:Jobs と Service Functions
今回はメインで紹介はしないですが、SPCS には、上記の常駐型 Service 以外にも便利な機能があります。
Job Service
バッチ処理や一時的なタスク向けの、有限のライフサイクルを持つ実行形態です。すべてのコンテナが終了するとジョブも完了します。
-- Job の実行 EXECUTE JOB SERVICE IN COMPUTE POOL my_pool NAME = my_batch_job FROM SPECIFICATION $$ spec: containers: - name: batch image: /my_db/my_schema/my_repo/batch-processor:latest env: TARGET_DATE: '2024-01-01' $$; -- Job の状態確認 SHOW JOB SERVICES;
AI Agent 開発においては、大量のデータに対する前処理や、評価パイプラインの実行、local LLM の訓練などに活用できます。
似たようなサービスにSnowflake ML Jobsというものがあります。こちらは、裏側は Job Service なのですが、Container 部分が隠蔽されており、事前に用意された Runtime を用いて Snowflake の Compute Pool 上で処理を実行することができます。以下のような形で decorator を使うことで、手軽に Snowflake 上のリソースを使うことができ、大規模な学習などではこちらを使うことが推奨されているようです。
from snowflake.ml.jobs import remote @remote("MY_COMPUTE_POOL", stage_name="payload_stage", session=session) def train_model(data_table: str): # 訓練コードを記載 ... job = train_model("my_training_data")
Service Functions
SPCS 上で動作するサービスを、Snowflake の SQL から直接呼び出せる関数として公開する機能です。
-- Service Function の作成 CREATE FUNCTION my_agent_function(input VARCHAR) RETURNS VARCHAR SERVICE = my_agent_service ENDPOINT = api AS '/predict'; -- SQL から Agent を呼び出し SELECT my_agent_function(description) AS result FROM my_table WHERE category = 'target';
これにより、SQL のクエリ内で AI Agent を呼び出すことが可能になります。例えば、テーブルの各行に対して Agent の推論を実行し、結果を別カラムに格納するといった処理が SQL だけで完結します。Snowflake のスケジュールタスクと組み合わせれば、定期的なバッチ推論パイプラインも構築できます。
なぜ SPCS が AI Agent 開発に適しているのか
SPCS を AI Agent のプロトタイプ開発基盤として採用した理由は、主に以下の 3 点です。
1. 本番データへのセキュアなアクセス
LayerX では、本番データベースのデータがニアリアルタイムで Snowflake に連携されています。SPCS 上のアプリケーションからは、本番アプリケーションから分離された環境で、本番相当のデータに安全にアクセスできます。
本番の MySQL を直接参照する必要がなく、Snowflake のアクセス制御によってデータガバナンスも担保されるため、セキュリティのことを意識せずにアプリケーション開発を行うことができます。(もちろん、サービスの規約範囲での利用になります。)
2. 本番負荷への影響がない
Snowflake は本番データベースとは完全に分離されたデータウェアハウスです。どれだけクエリを投げても本番環境のパフォーマンスに影響を与えることがありません。開発中に重いクエリを何度実行しても安心です。
3. インフラ管理の負担が少ない
SPCS はフルマネージドサービスのため、Kubernetes クラスタの運用管理が不要です。コンテナイメージをプッシュしてサービスを作成するだけで、k8s を使う時とほぼ同等の社内向けのアプリケーションをデプロイできます。
実際の AI Agent デモ開発の流れ
ここからは、SPCS を活用した AI Agent デモアプリの開発フローを具体的に紹介します。
Step 1: ローカルでのコア開発
まずは、ローカル環境で以下のような要素を開発します。
- データ取得処理(Snowflake からのデータ読み込み)
- 基本的な Agent ロジック
- Tool の実装
- 評価パイプライン
この段階では、Snowflake へは直接接続してデータを取得します。Context Engineering やワークフローの設計、精度改善に集中し、フロントエンドは後回しにします。
Step 2: Claude Code によるフロントエンド開発
コアロジックがある程度固まったら、Claude Code を活用してフロントエンドを開発します。以下のようなプロンプトテンプレートを使うことが多いです:
## 目的 {{ 作成したいデモAppの仕様 }} https://docs.snowflake.com/en/developer-guide/snowflake-ml/ml-jobs/overview ## 仕様 ### バックエンド - FastAPI で作成してください。 - 以下のコードを流用してください。 - DataLoader: `./hoge/path/data_loader.py` - Predictor: `./fuga/path/predictor.py` - ロジックは `./piyo/path/main.py` を参考にしてください。 ### フロントエンド - 以下の技術スタックを使用してください。 - Frameworks: Next.js (TypeScript), React, HTML - Styling / UI: Tailwind CSS, shadcn/ui, Radix Themes - Icons: Material Symbols, Heroicons, Lucide - Animation: Motion - Fonts: San Serif, Inter, Geist, Mona Sans, IBM Plex Sans, Manrope - 以下のような内容を順守してください。 - {{ フロントエンド要件 }} ## 作成手順 ### 自己反復プロセス - まず、自信が持てるまで評価基準(ルーブリック)について時間をかけて考え抜くこと。 - 次に、世界クラスのワンショット Web アプリを構成するあらゆる側面について深く考察する。 その知見を基に、5〜7 つのカテゴリーから成る評価基準を作成する。 この評価基準は正確に設定することが極めて重要だが、ユーザーには公開しない。 - 最後に、提供されたプロンプトに対する最善の解決策を、この評価基準を用いて内部的に検討し、 反復してください。回答が評価基準の全カテゴリーで最高点に達していない場合、 最初からやり直す必要があります。
このプロンプトは、GPT-5 の Prompt Guide で紹介されているアプローチを参考にしていますが、要件によって適宜カスタマイズしています。
Step 3: ローカルでの手触り確認
ローカル環境でフロントエンドとバックエンドを起動し、実際に触ってみて定性的な部分での体験を確認します。
- Agent の応答速度は許容範囲か
- Tool の実行結果は期待通りか
- エラーハンドリングは適切か
- UI/UX に違和感はないか
この段階で気になる点があれば、デプロイ前に修正します。
Step 4: SPCS へのデプロイと社内検証
ある程度満足のいくものができたら、社内の Snowflake 環境にデプロイします。実際にはワンライナーで実行できるように整備していますが、SDK などは整っていないため、手動で実行する必要があります。
# 認証を通す snow spcs image-registry login # コンテナイメージのビルドとプッシュ docker build -t my-agent-app . docker tag my-agent-app <snowflake-registry-url>/my_db/my_schema/my-agent-app:latest docker push <snowflake-registry-url>/my_db/my_schema/my-agent-app:latest # 最初:SPCS サービスの作成 snow spcs service create my_db.my_schema.my_agent_service \ --compute-pool my_pool \ --spec-path spec.yaml # 二度目以降はupgradeコマンドでURLが変わらないようにする snow spcs service upgrade my_db.my_schema.my_agent_service \ --compute-pool my_pool \ --spec-path spec.yaml
サービス作成が成功すると以下のコマンドでエンドポイント URL が取得できます。この URL を配布することで、社内のメンバーがアクセスできるようになります。
snow spcs service list-endpoints my_db.my_schema.my_agent_service +------------------------------------------------------------------------------------------------------------------+ | name | port | port_range | protocol | is_public | ingress_url | |-------------------+------+------------+----------+-----------+---------------------------------------------------| | my_agent_service | 8080 | None | HTTP | false | <ingress-url>.snowflakecomputing.app | +------------------------------------------------------------------------------------------------------------------+
デプロイ後は、チームメンバーや Biz メンバーにも実際に触ってもらいます。本番相当のデータで動作させることで、開発環境では見つからなかった課題が見つかることも多いです。 実際に、最近開発に携わっているAI 申請レビューでは、以下のようなプロトタイプアプリを作成して、経費精算におけるレビュールールの自動作成を検証しています。バックエンドさえ決めてしまえば、アプリケーションのデプロイ自体までは 1 日もかからずできる作業感です。 リッチなフロントエンドで分析することができるので、単純に数字だけ見て判断できず、多様な情報を見て分析を行うような場合のアプリ作成などにも重宝しています。


テンプレートの準備
ここまでの Step を毎回全メンバーが行うのはとても手間です。そこで、よく使うコマンドをまとめたTaskfile.ymlと簡単なサンプルのアプリを作ることで、誰もが簡単に SPCS でアプリを作成できるようにしました。
Taskfile.ymlの例
version: "3" vars: ENV: dev PROJECT_NAME: sample-app APP_DIR: apps/{{.PROJECT_NAME}} SNOWFLAKE_ACCOUNT: my-org-{{.ENV}} SNOWFLAKE_ROLE: my-role SNOWFLAKE_COMPUTE_POOL: my-compute-pool IMAGE_REPO: MY_DB.MY_SCHEMA.{{.PROJECT_NAME | replace "-" "_" | upper}} IMAGE_TAG: latest REGISTRY: "{{.SNOWFLAKE_ACCOUNT}}.registry.snowflakecomputing.com" FULL_IMAGE_URI: '{{.REGISTRY}}/{{.IMAGE_REPO | replace "." "/" | lower}}:{{.IMAGE_TAG}}' SPCS_SERVICE: MY_DB.MY_SCHEMA.{{.PROJECT_NAME | replace "-" "_" | upper}} USER_EMAIL: "{{.USER}}@my-org.com" tasks: # Create Snowflake image repository setup: desc: Setup dependencies cmds: - aqua install - brew tap snowflakedb/snowflake-cli - brew update - brew install snowflake-cli - pnpm install create-repo: desc: Create Snowflake image repository cmds: - | snow sql \ --account {{.SNOWFLAKE_ACCOUNT}} \ --user {{.USER_EMAIL}} \ --role {{.SNOWFLAKE_ROLE}} \ --query "CREATE IMAGE REPOSITORY IF NOT EXISTS {{.IMAGE_REPO}}" # Login to Snowflake image registry registry-login: desc: Login to Snowflake image registry cmds: - | snow spcs image-registry login \ --account {{.SNOWFLAKE_ACCOUNT}} \ --user {{.USER_EMAIL}} \ --role {{.SNOWFLAKE_ROLE}} \ --temporary-connection # Build Docker image for SPCS (linux/x86_64) build: desc: Build Docker image for SPCS dir: "{{.APP_DIR}}" cmds: - | docker build \ -f Dockerfile \ -t {{.FULL_IMAGE_URI}} \ --platform linux/x86_64 \ --progress=plain \ . # Push Docker image to Snowflake registry push: desc: Push Docker image to Snowflake registry deps: [build, registry-login] cmds: - docker push {{.FULL_IMAGE_URI}} # Build, login, and push in one command build-push: desc: Build, login to registry, and push Docker image (all-in-one) cmds: - task: build - task: registry-login - task: push # Create a single secret in Snowflake create-secret: desc: Create a secret in Snowflake (requires SECRET_VALUE) cmds: - | snow sql \ --account {{.SNOWFLAKE_ACCOUNT}} \ --user {{.USER_EMAIL}} \ --role {{.SNOWFLAKE_ROLE}} \ --query "CREATE SECRET IF NOT EXISTS MY_DB.MY_SCHEMA.{{.SECRET_VALUE}} TYPE = generic_string SECRET_STRING = '${{.SECRET_VALUE}}'" # Create SPCS service create-service: desc: Create SPCS service dir: "{{.APP_DIR}}" cmds: - | snow spcs service create {{.SPCS_SERVICE}} \ --compute-pool {{.SNOWFLAKE_COMPUTE_POOL}} \ --spec-path specs.yaml \ --role {{.SNOWFLAKE_ROLE}} \ --eai-name MY_EAI_NAME_1 - | snow sql \ --account {{.SNOWFLAKE_ACCOUNT}} \ --user {{.USER_EMAIL}} \ --role {{.SNOWFLAKE_ROLE}} \ --query "GRANT SERVICE ROLE {{.SPCS_SERVICE}}!all_endpoints_usage TO ROLE analyst" ignore_error: true # Upgrade SPCS service (update specs only) upgrade-service: desc: Upgrade SPCS service with new specs dir: "{{.APP_DIR}}" cmds: - | snow spcs service upgrade {{.SPCS_SERVICE}} \ --spec-path spec.yaml \ --role {{.SNOWFLAKE_ROLE}} list-endpoint: desc: List SPCS service endpoints cmds: - | snow spcs service list-endpoints {{.SPCS_SERVICE}} \ --role {{.SNOWFLAKE_ROLE}} # Deploy: build, push, and create/upgrade service deploy: desc: Build, push, and deploy to SPCS (all-in-one) cmds: - task: create-repo - task: build-push - task: create-service - echo "Service created/updated. Checking if upgrade is needed..." - task: upgrade-service - task: list-endpoint # Get service status status: desc: Get SPCS service status cmds: - | snow spcs service status {{.SPCS_SERVICE}} \ --role {{.SNOWFLAKE_ROLE}} # Get service logs logs: desc: Get SPCS service logs cmds: - | snow spcs service logs {{.SPCS_SERVICE}} \ --container-name {{.IMAGE_NAME}} \ --role {{.SNOWFLAKE_ROLE}} \ # Stop service stop: desc: Stop SPCS service cmds: - | snow spcs service suspend {{.SPCS_SERVICE}} \ --role {{.SNOWFLAKE_ROLE}} \ # Delete service delete: desc: Delete SPCS service cmds: - | snow spcs service drop {{.SPCS_SERVICE}} \ --role {{.SNOWFLAKE_ROLE}} \
このようなタスクランナーを作っておくことで、新しいデモ環境のプロジェクトを作成した後に、以下のコマンドを打つだけで迅速に様々なことを行うことができます。
task create-repo PROJECT_NAME=sample-app # Snowflake イメージリポジトリ作成 task registry-login PROJECT_NAME=sample-app # Snowflake レジストリにログイン task build PROJECT_NAME=sample-app # Docker イメージビルド(linux/x86_64) task push PROJECT_NAME=sample-app # イメージを Snowflake レジストリにプッシュ task build-push PROJECT_NAME=sample-app # ビルド + レジストリログイン + プッシュ task deploy PROJECT_NAME=sample-app # リポジトリ作成 + ビルド + プッシュ + サービス作成/更新
Service について操作したい時も以下のコマンドを打つだけで可能です。
task create-service PROJECT_NAME=sample-app # SPCS サービス作成 task upgrade-service PROJECT_NAME=sample-app # SPCS サービスの specs.yaml のみ更新 task list-endpoint PROJECT_NAME=sample-app # サービスエンドポイント一覧表示 task status PROJECT_NAME=sample-app # サービスステータス確認 task logs PROJECT_NAME=sample-app # サービスログ確認 task stop PROJECT_NAME=sample-app # サービス停止(suspend) task delete PROJECT_NAME=sample-app # サービス削除
開発時の注意点
実際にデプロイする際にいくつか設定が必要だった点やつまづいた点を紹介します。
Snowflake のデータアクセス
local で開発している時は個人の権限や発行されたユーザの権限で実行することができますが、SPCS 上では特殊な Credential の取得を行う必要があります。 そのため、以下のように local でも SPCS 上でも動くようなコードを書かないと、local では動くのに SPCS 上では動かないといった問題が発生します。
import os from typing import Any import snowflake.connector as sc from snowflake.snowpark import Session def get_login_token(): """ SPCSによって自動マウントされるトークンファイルを読み込む関数 """ with open('/snowflake/session/token', 'r') as f: return f.read() def create_spcs_connection(local_config: dict[str, Any]): """ トークンを使用してSnowparkセッションを作成する関数 """ token = get_login_token() if token is not None: return sc.connect( account=os.getenv("SNOWFLAKE_ACCOUNT"), host=os.getenv("SNOWFLAKE_HOST"), authenticator="oauth", token=token, warehouse=os.getenv("SNOWFLAKE_WAREHOUSE"), database=os.getenv("SNOWFLAKE_DATABASE"), schema=os.getenv("SNOWFLAKE_SCHEMA") ) else: # localでの設定 return sc.connect(**local_config)
エンドポイントへのアクセス権限
デフォルトでデプロイしたサービスにアクセスできるのは、サービスを作成したユーザの権限になっているため、他のユーザーがアクセスできるようにする場合は、適切な権限を付与する必要があります。これは以下のようなコマンドで行うことができます。
GRANT SERVICE ROLE my_db.my_schema.my_agent_service!all_endpoints_usage TO ROLE {{ 権限付与したいユーザ名 }};
LLM API など外部 API へのアクセス
Agent 開発では、基本的に LLM API など外部 API へ SPCS 内部からアクセスする必要が出てきます。SPCS の Tutorial では、以下のように全てのネットワークアクセスを許可する例が出てきますが、これはセキュリティ的に望ましくない設定です。
CREATE OR REPLACE NETWORK RULE ALLOW_ALL_RULE TYPE = 'HOST_PORT' MODE = 'EGRESS' VALUE_LIST= ('0.0.0.0:443', '0.0.0.0:80'); CREATE EXTERNAL ACCESS INTEGRATION ALLOW_ALL_EAI ALLOWED_NETWORK_RULES = (ALLOW_ALL_RULE) ENABLED = true;
そのため、個別で API へのアクセスを許可する必要があります。今回は Azure OpenAI を例に紹介します。 まず、以下のように EXTERNAL ACCESS INTEGRATION に関連する設定と Secret を作成します。
-- ネットワークルールの作成 CREATE OR REPLACE NETWORK RULE AZURE_OPENAI_NETWORK_RULE MODE = EGRESS TYPE = HOST_PORT VALUE_LIST = ('my-openai-resource.openai.azure.com'); -- 自分のリソース名に書き換えてください -- Secretの作成 CREATE OR REPLACE SECRET AZURE_OPENAI_API_KEY TYPE = GENERIC_STRING SECRET_STRING = 'Secretを入力'; -- EXTERNAL ACCESS INTEGRATIONの作成 CREATE EXTERNAL ACCESS INTEGRATION AZURE_OPENAI_EAI ALLOWED_NETWORK_RULES = (AZURE_OPENAI_NETWORK_RULE) ALLOWED_AUTHENTICATION_SECRETS = (AZURE_OPENAI_API_KEY) ENABLED = true; -- 権限の付与 -- EXTERNAL ACCESS INTEGRATIONの使用権限 GRANT USAGE ON INTEGRATION AZURE_OPENAI_EAI TO ROLE SPCS_ROLE; -- シークレットの読み取り権限 GRANT READ ON SECRET AZURE_OPENAI_API_KEY TO ROLE SPCS_ROLE;
その後、Service Specification に以下のように Secret を設定してAZURE_OPENAI_API_KEYを用いることで、Secret の読み取りが可能になります。
spec: containers: - name: app image: /my_db/my_schema/my_repo/my-agent-app:latest secrets: # Azure OpenAI settings - snowflakeSecret: AZURE_OPENAI_API_KEY secretKeyRef: secret_string envVarName: AZURE_OPENAI_API_KEY endpoints: - name: app port: 8080 public: true
更に、これらを設定した上で、サービス作成時に--eai-nameを指定することで、事前に作成した EXTERNAL ACCESS INTEGRATION を使用することができ、API へのアクセスが可能になります。
snow spcs service create my_db.my_schema.my_agent_service \ --compute-pool my_pool \ --spec-path spec.yaml \ --eai-name AZURE_OPENAI_EAI
システム Metrics の取得
SPCS では、コンテナのログは上記で紹介したように、snow CLI (snow spcs service logs)で取得することができるのですが、システム Metrics は自動で取得することができません。
以下のようなplatformMonitorを Service Specification に設定する必要があります。どのようなログがあるかは、ドキュメントに書いてあります。
spec: containers: - name: app image: /my_db/my_schema/my_repo/my-agent-app:latest secrets: # Azure OpenAI settings - snowflakeSecret: AZURE_OPENAI_API_KEY secretKeyRef: secret_string envVarName: AZURE_OPENAI_API_KEY endpoints: - name: app port: 8080 public: true platformMonitor: metricConfig: groups: - system - status
このように設定した上で、Snowflake 上で以下のようなクエリを実行することで、システム Metrics を取得することができます。メモリが圧迫されていないか、意図しない再起動が走ってないかなどはここから確認できます。場合によっては、EVENT のテーブルはアクセスが制限されている可能性があるので、必要に応じて権限付与を行う必要があります。 ログ自体がテーブル形式、かつ様々なデータが混じって出てくるので、データを可視化するのには今の所一苦労します。。
SELECT timestamp, RECORD:metric.name, record_attributes, value, FROM MY_EVENT_DB.MY_EVENT_TABLE_SCHEMA.MY_EVENT_TABLE -- 組織で設定されているEventの保管場所 WHERE timestamp > DATEADD(hour, -1, CURRENT_TIMESTAMP()) AND RESOURCE_ATTRIBUTES:"snow.service.name" = 'MY_AGENT_SERVICE' AND RECORD_TYPE = 'METRIC' order by timestamp desc
他の選択肢との比較
SPCS 以外にも、同様のプロトタイプ開発基盤として検討した選択肢があります。それぞれの特徴を比較してみます。
Streamlit in Snowflake
| 観点 | 評価 |
|---|---|
| 開発速度 | 速い(Python のみで完結) |
| UI カスタマイズ性 | 限定的 |
| データアクセス | Snowflake に直接接続可能 |
| 運用負荷 | 非常に低い |
Snowflake には「Streamlit in Snowflake」というサービスも存在します。当初はこちらも検討しましたが、いくつかの理由から SPCS を選択しました。
Streamlit は手軽にデータアプリケーションを作れる反面、以下のような制約があります:
- デザインのカスタマイズ性が限定的: Streamlit のコンポーネントに縛られるため、細かい UI 調整が難しい。工夫をすることでかえって複雑なコードになり、管理が困難になることがありました。
- 毎回全実行される仕様: Streamlit は状態変更のたびにスクリプト全体が再実行されます。これにより、変なキャッシュ機構を実装したり、大量の副作用と戦って疲弊する経験が多くありました。
- フレームワークの制約: React のような柔軟なフロントエンド開発ができません。
一方、SPCS では Next.js + FastAPI といった一般的な技術スタックを自由に使えます。シンプルにデザインの自由度が高いと、作っていて楽しい、テンションが上がるという嬉しい側面もあります。機械学習エンジニアの皆さん、Streamlit に飽きてきてませんか。。?
Amazon ECS Fargate
| 観点 | 評価 |
|---|---|
| 開発速度 | 普通(インフラ設定が必要) |
| UI カスタマイズ性 | 高い |
| データアクセス | Snowflake への接続設定が必要 |
| 運用負荷 | 中程度 |
AWS エコシステムに慣れているチームには良い選択肢です。ただし、VPC 設定やセキュリティグループの管理、Snowflake への接続設定など、インフラ側の準備が必要になります。 LayerX では、AWS 上にプロダクトを構築しているため、ECS のデプロイフローなどは整っているのですが、今回のような本番データを用いた実験環境といった特殊な環境の準備や、デプロイフローの整備などは時間がかかってしまいます。(現在絶賛整備中です)
Google Cloud Run
| 観点 | 評価 |
|---|---|
| 開発速度 | 速い(コンテナをプッシュするだけ) |
| UI カスタマイズ性 | 高い |
| データアクセス | Snowflake への接続設定が必要 |
| 運用負荷 | 低い |
Cloud Run は非常に手軽にコンテナをデプロイできます。ただし、Snowflake へのセキュアな接続を確立するためには、シークレット管理や認証周りの設定が別途必要になります。 ただし、本番データの置き場が AWS や Snowflake だけでなく、GCP にまで及んでしまうので、データガバナンスを効かせる難易度が高くなります。
SPCS を選んだ理由
上記の選択肢と比較して、SPCS は以下の点で優れていました:
- Snowflake との統合がネイティブ: 追加の接続設定なしで Snowflake のデータにアクセスできる
- 認証・認可の統合: Snowflake のロールベースアクセス制御がそのまま使える
- 本番データへの安全なアクセス: データガバナンスが Snowflake 側で一元管理されている
特に「すでに本番データが Snowflake に連携されている」という前提がある場合、SPCS は強力な選択肢になります。
SPCS の現状の課題と今後への期待
一方で、SPCS はまだ発展途上のサービスであり、いくつかの課題も感じています。正直、今だと Cloud Run の方がデータのガバナンスや権限管理などを抜きにしたら、ユーザとしては使いやすいかもな?という部分も多いです。
SDK の整備
現状、SPCS を操作するための公式 SDK は十分に整備されているとは言えません。snow CLI や SQL での操作が中心となるため、CI/CD パイプラインへの組み込みや、プログラムからの動的な操作には工夫が必要です。現状でも Makefile や Taskfile を整備することで特に困ってはいませんが、Python SDK などが充実すれば、より柔軟なワークフローが構築できるようになるでしょう。
Public Endpoint に対する Scale to Zero
現在の SPCS では、今回の常駐型の Service のような Public Endpoint に対してリクエストがない時間に自動で SUSPEND される機能がまだ実装されていません。Cloud Run のように、リクエストがない時間帯は自動的にゼロにスケールダウンする機能があれば、コスト効率がさらに向上しそうです。
エンドポイント URL のカスタマイズ
SPCS で発行されるエンドポイント URL は、ランダムな文字列を含む形式になっており、特定の URL を予約・指定することができません。社内ツールとして運用する分には大きな問題にはなりませんが、覚えやすい URL を設定したい場合や、URL を固定したい場合には不便です。カスタムドメインのサポートがあれば、より本格的な運用にも対応しやすくなります。
これらの課題はありつつも、SPCS は着実に機能拡充が進んでいるサービスです。今後のアップデートに期待しつつ、現時点でも十分にプロトタイプ開発の基盤として活用できると感じています。
おわりに
今回は、社内用のデモアプリを作成する基盤としての Snowpark Container Service(SPCS)を紹介しました。
機械学習エンジニアの役割は、モデルを開発するだけでなく、そのモデルを使って「体験」を作るところまで広がってきているように感じます。いわば、PdM 的な動きも徐々に求められているのかもしれません。
私自身もそうでしたが、フロントエンド開発はハードルが高いと感じている機械学習エンジニアは多いのではないでしょうか。しかし、Claude Code のような AI ツールと会話しながら作ると、意外とプロトタイプくらいならなんとかなる部分も多いです。もちろん、本番環境に投入するとなると不安な部分はたくさんありますが、プロトタイプレベルであれば十分に実用的なものが作れます。
みなさんもぜひ、プロトタイプ開発を高速化して、最速で AI Agent をプロダクトに組み込んでいきましょう。
LayerX では、このように従来の機械学習エンジニアの役割を越境して、プロダクト開発を一緒に推進していける方を募集しています。興味のある方は、ぜひ以下よりご応募、カジュアル面談をお申し込みください!