❄️

Streamlit in Snowflake (SiS) から直接 Amazon Bedrock を呼び出してみる

2024/07/17に公開

はじめに

SiS がついに外部ネットワークアクセスに対応しました!これでネットワークルールで許可されたドメインに対して SiS から直接アクセスをすることができるようになりました。

そこで今回は AWS の Amazon Bedrock の API を直接コールし、SiS で作った Web アプリで Cortex LLM も Amazon Bedrock も使えるようにしてみたいと思います。

本手順からわからない点は以下の Snowflake ドキュメントを参照してください。

Streamlit における外部ネットワークアクセス

機能概要

実現したいこと

  • UDF / UDTF を使わずに SiS から直接 Amazon Bedrock を呼び出す

実際の画面 (抜粋)

前提条件

  • Snowflake
    • Cortex LLM が利用できる Snowflake アカウント (SiS から Amazon Bedrock だけを利用したい場合は Cortex LLM が利用できない Snowflake アカウントでも問題ありません)
    • snowflake-ml-python 1.1.2 以降
    • boto3 1.28.64
  • AWS
    • Amazon Bedrock が利用できる AWS アカウント (今回の手順では Claude 3.5 Sonnet を利用するため us-east-1 リージョンを利用しています)

手順

Amazon Bedrock で対象モデルを有効化する

AWS のマネジメントコンソールから Amazon Bedrock のコンソールに接続します。

左ペインの『モデルアクセス』をクリックし、使用したいモデルを有効化します。今回は Claude 3.5 Sonnet を使いたいため、Claude 3.5 Sonnet を有効化しています。

リクエストには AWS からの承認プロセスがあるため承認されるまで待ちます。私はすぐに承認されましたが、アカウントによっては時間がかかる可能性があるため注意しましょう。

AWS IAM ユーザーを作成する

SiS からアクセスするための IAM ユーザーを作成します。

AWS のマネジメントコンソールから IAM のコンソールに接続します。

左ペインの『ユーザー』をクリックし、遷移した画面から『ユーザーの作成』をクリックします。

ユーザー名を入力 (今回は sis_bedrock_user とする) し、『AWS マネジメントコンソールへのユーザーアクセスを提供する』のチェックボックスにチェックを入れずに『次へ』をクリックします。

『ポリシーを直接アタッチする』にチェックを入れて、AmazonBedrockFullAccess の管理ポリシーにチェックを入れて『次へ』をクリックします。
AmazonBedrockFullAccess は Amazon Bedrock に関するフルの権限を与えるため、必要に応じてより権限を絞った IAM ポリシーを割り当てていただくことも検討することを推奨します。

『ユーザーの作成』ボタンをクリックすると Amazon Bedrock を利用する権限のある IAM ユーザーが作成されます。

IAM のユーザーの画面から今作成した IAM ユーザーを検索しユーザー名をクリックします。

『セキュリティ認証情報』タブをクリックし、『アクセスキーを作成』ボタンをクリックします。

『サードパーティーサービス』にチェックを入れ、『上記のレコメンデーションを理解し、アクセスキーを作成します。』にチェックを入れ、『次へ』ボタンをクリックします。

『説明タグを設定 - オプション』の画面で何も入力せずに『アクセスキーを作成』ボタンをクリックします。

『アクセスキー』と『シークレットアクセスキー』が生成されるため手元に安全に保管するようにします。(CSVファイルとして取得することも可能)
※ ここで『アクセスキー』と『シークレットアクセスキー』を保管しないと再発行はされません。紛失してしまった場合は再度アクセスキーを作成しましょう。

これで AWS での作業は終了です。

Snowflake でネットワークルールを作成する

Snowflake からの外部アクセスはデフォルトで閉じているため、Amazon Bedrock にアクセスするためのネットワークルールを作成します。ネットワークルールを作成しただけでは外部アクセスできるようになるわけではないのでご安心ください。

Snowflake の Snowsight からワークシートを開き以下の SQL を実行します。

-- 外部アクセス用のネットワークルールを作成
CREATE OR REPLACE NETWORK RULE bedrock_network_rule
mode = EGRESS
type = HOST_PORT
value_list = ('bedrock-runtime.us-east-1.amazonaws.com','bedrock-runtime-fips.us-east-1.amazonaws.com');

シークレットを作成する

ワークシートの続きから以下の SQL を実行します。

-- シークレットの作成
CREATE OR REPLACE SECRET bedrock_key
  TYPE = PASSWORD
  USERNAME = '<アクセスキー>'
  PASSWORD = '<シークレットアクセスキー>';

※ アクセスキーとシークレットアクセスキーは、先ほど AWS IAM ユーザーを作成する際に控えた値です。

外部アクセス統合を作成する

ワークシートの続きから以下の SQL を実行します。

-- 外部アクセス統合を作成
CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION bedrock_access_integration
ALLOWED_NETWORK_RULES = (bedrock_network_rule)
ALLOWED_AUTHENTICATION_SECRETS = (bedrock_key)
ENABLED = TRUE;

SiS アプリを作成する

Snowsight の左ペインから『Streamlit』をクリックし、『+ Streamlit』ボタンをクリックし SiS アプリを作成します。

SiS アプリが起動したら、ブラウザに表示されている URL を確認します。URL 末尾は

https://(中略)/streamlit-apps/<DB名>.<スキーマ名>.<Streamlitオブジェクト名>

となっているため、Streamlit オブジェクト名を手元に控えます。
※ SiS アプリのタイトルとは異なるため注意してください。
SHOW STREAMLITS コマンドで確認することも可能です。

Streamlit オブジェクトに外部アクセス統合を紐付ける

ワークシートに戻り以下 SQL を実行します。

-- Streamlit オブジェクトと外部アクセス統合のマッピング
ALTER STREAMLIT <DB名>.<スキーマ名>.<Streamlitオブジェクト名>
  SET EXTERNAL_ACCESS_INTEGRATIONS = (bedrock_access_integration)
  SECRETS = ('bedrock_key' = <DB名>.<スキーマ名>.bedrock_key);

SiS アプリから Amazon Bedrock を実行する

Snowsight の左ペインから『Streamlit』をクリックし、先ほど作成した SiS アプリを開きます。
編集画面で『パッケージ』から以下を選択しインストールします。

  • snowflake-ml-python 1.5.3
  • boto3 1.28.64

以下のソースコードを貼り付けて実行します

from snowflake.snowpark.context import get_active_session
import streamlit as st
from snowflake.cortex import Complete as CompleteText
import json
import boto3
import _snowflake

# Snowflakeのセッションを取得
snowflake_session = get_active_session()

# アプリケーションのタイトル
st.title("Cortex & Bedrock チャットアプリ")

# AWSの認証情報を取得する関数
def get_aws_credentials():
    aws_key_object = _snowflake.get_username_password('bedrock_key')
    region = 'us-east-1'

    boto3_session_args = {
        'aws_access_key_id': aws_key_object.username,
        'aws_secret_access_key': aws_key_object.password,
        'region_name': region
    }

    return boto3_session_args, region

# Bedrockクライアントの設定
boto3_session_args, region = get_aws_credentials()
boto3_session = boto3.Session(**boto3_session_args)
bedrock = boto3_session.client('bedrock-runtime', region_name=region)

# AI設定
st.sidebar.title("LLM の設定")
lang_model = st.sidebar.radio("使用したい言語モデルを選んでください", 
                              ("Cortex AI の LLM", "Bedrock の Claude3.5 Sonnet"))

if lang_model == "Cortex AI の LLM":
    lang_model = st.sidebar.radio("Cortex AIのモデルを選択してください",
                                  ("snowflake-arctic", "reka-flash", "reka-core", 
                                   "mistral-large2", "mistral-large", "mixtral-8x7b", "mistral-7b", 
                                   "llama3.1-405b", "llama3.1-70b", "llama3.1-8b", 
                                   "llama3-70b", "llama3-8b", "llama2-70b-chat", 
                                   "jamba-instruct", "gemma-7b")
    )
else:
    lang_model = "anthropic.claude-3-5-sonnet-20240620-v1:0"

# BedrockのAPIを呼び出す関数
def ask_claude3(prompt):
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 100000,
        "messages": [
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": prompt
                    }
                ]
            }
        ]
    })

    response = bedrock.invoke_model(
        body=body,
        modelId=lang_model,
        accept='application/json',
        contentType='application/json'
    )

    response_body = json.loads(response.get('body').read())
    return response_body.get('content')[0].get('text')

st.header("自由にチャットしよう!")

# チャット履歴の初期化
if 'messages' not in st.session_state:
    st.session_state.messages = []

# チャット履歴の表示
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# ユーザー入力
if prompt := st.chat_input("文章を入力してください。"):
    # ユーザーメッセージの追加と表示
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)

    # AI応答の生成
    if lang_model.startswith("anthropic.claude-3"):
        response = ask_claude3(prompt)
    else:
        response = CompleteText(lang_model, prompt)

    # AI応答の追加と表示
    st.session_state.messages.append({"role": "assistant", "content": response})
    with st.chat_message("assistant"):
        st.markdown(response)

最後に

いかがでしたか? UDF / UDTF 無しに SiS から外部アクセスできることで、より高度な Web アプリケーションをより簡単に作れるようになりました!また UDF / UDTF を噛ませないせいかレスポンスも向上しており、さらに良いユーザー体験を提供することが可能となります。

是非皆様も SiS の外部ネットワークアクセス機能を使って素敵な Web アプリ作りにチャレンジしてみてください。

宣伝

SNOWFLAKE WORLD TOUR TOKYO の参加登録受付中 (残席僅かです!)

Snowflake の最新情報を知ることができる大規模イベント『SNOWFLAKE WORLD TOUR TOKYO』が2024/9/12(木)@ANAインターコンチネンタル東京で開催されます!
残席が少なくなってきておりますので参加登録お急ぎください!
私も Snowflake の概要をお伝えするセッションで登壇する予定です!超分かりやすく Snowflake AI Data Cloud についてご紹介しますので、是非ご来場ください〜!

X で Snowflake の What's new の配信してます

X で Snowflake の What's new の更新情報を配信しておりますので、是非お気軽にフォローしていただければ嬉しいです。

日本語版

Snowflake の What's New Bot (日本語版)
https://x.com/snow_new_jp

English Version

Snowflake What's New Bot (English Version)
https://x.com/snow_new_en

変更履歴

(20240717) 新規投稿
(20240901) 全体的に体裁修正、ソースコードに mistral-large2 などを追加

Discussion