Cortex Analyst

概要

Cortex Analyst は完全に管理され、 LLM-powered Snowflake Cortex 機能で、Snowflake の構造化データに基づいてビジネス上の質問に確実に回答できるアプリケーションの作成を支援します。 Cortex Analyst により、ビジネスユーザーは SQL を記述することなく、自然言語で質問し、直接回答を受け取ることができます。便利な REST API として利用できる Cortex Analyst は、どのようなアプリケーションにもシームレスに統合できます。

本番レベルの会話型セルフサービス分析ソリューションを構築するには、正確なテキストから SQL への応答を生成するサービスが必要です。ほとんどのチームにとって、精度、遅延、コストのバランスをうまくとったこのようなサービスを開発するのは大変な作業です。 Cortex Analyst は、これらの複雑な問題をすべて処理し、高精度のテキストから SQL への応答を生成する、完全に管理された洗練されたエージェント型 AI システムを提供することで、このプロセスを簡素化します。複雑な RAG ソリューションパターン、モデル実験、 GPU 容量計画などの時間浪費を回避しながら、ビジネスチームへの高精度なセルフサービス会話型分析の提供を加速することができます。生成された SQL クエリは、スケーラブルなSnowflakeエンジンに対して実行され、業界トップクラスの価格性能と低い総所有コスト(TCO)を保証します。

Tip

Cortex Analyst をすぐに始めたいですか? チュートリアル: Cortex Analystで時系列収益データに関する質問に答える チュートリアルをお試しください。

主要な機能

  • 自然言語クエリによるセルフサービス分析。 Snowflakeの構造化データから即座に回答や洞察を得て、ビジネスチームや非技術系ユーザーを喜ばせましょう。 Cortex Analyst を使用すると、ユーザーが自然言語を使用して質問し、その場で正確な回答を受け取ることができるダウンストリームチャットアプリケーションを構築することができます。

  • 既存のビジネスワークフローに統合できる便利な REST API。 Cortex Analyst は、 APIファーストアプローチを採用しており、エンドユーザーエクスペリエンスを完全に制御できます。 Cortex Analyst を既存のビジネスツールやプラットフォームに簡単に統合し、Streamlitアプリ、Slack、Teams、カスタムチャットインターフェースなど、ビジネスユーザーがすでに操作している場所にデータインサイトのパワーをもたらします。

  • 最先端の大規模言語モデルを搭載: デフォルトで、 Cortex Analyst は最新のMeta LlamaとMistralモデルを搭載しています。これらのモデルは、 Snowflake Cortex、Snowflakeのインテリジェントなフルマネージド AI サービス内で安全に実行されます。オプションで、 Cortex Analyst にAzureがホストする OpenAI GPT の最新モデルへのアクセス権を与えることもできます。実行時に Cortex Analyst は、各クエリに対して最高の精度とパフォーマンスを保証するために、モデルの最適な組み合わせを選択します。詳細については、 Azure OpenAI モデルの使用を可能にする をご参照ください。LLMs が進化するにつれ、Snowflakeは性能と精度をさらに向上させるために、より多くのモデルをミックスに加えることを探求し続けます。

  • 高い精度と正確さのためのセマンティックモデル: 一般的な AI ソリューションは、データベーススキーマのみが与えられた場合、テキストから SQL への変換に苦労することがよくあります。スキーマには、ビジネスプロセスの定義やメトリクスの取り扱いといった重要な知識が欠けているためです。 Cortex Analyst は、ビジネスユーザーとデータベースの間のギャップを埋める セマンティックモデル を使用することで、この制限を克服しています。軽量な YAML ファイルに取り込まれたセマンティックモデルの全体的な構造と概念は、データベーススキーマと似ていますが、データ周辺のセマンティック情報をより豊かに記述することができます。

  • セキュリティとガバナンス。 Snowflakeのプライバシー第一の基盤とエンタープライズグレードのセキュリティにより、最高水準のプライバシーとガバナンスによってデータが保護されていることを認識しながら、 AI に基づいたユースケースを安心して検討することができます。

    • Cortex Analyst は、顧客データに関する訓練は行いません。当社は、当社の顧客ベース全体で使用できるようにするモデルの訓練または微調整のために、お客様の顧客データを使用することはありません。さらに、推論のために、 Cortex Analyst は、 SQL クエリ生成のためにのみ、セマンティックモデル YAML ファイルで提供されるメタデータ(例えば、テーブル名、列名、値のタイプ、説明など)を利用します。この SQL クエリは、Snowflake仮想ウェアハウスで実行され、最終的な出力を生成します。

    • データはSnowflakeのガバナンス境界内に留まります。デフォルトでは、 Cortex Analyst は、MistralとMetaのSnowflakeホスティング LLMs によって駆動され、メタデータやプロンプトを含むデータがSnowflakeのガバナンス境界を離れることがないようにします。Azure OpenAI モデルの使用を選択した場合、メタデータとプロンプトのみがSnowflakeのガバナンス境界の外部に送信されます。

    • Snowflakeのプライバシーおよびガバナンス機能とのシームレスな統合。 Cortex Analyst は、Snowflakeのロールベースのアクセス制御(RBAC)ポリシーと完全に統合され、 SQL クエリの生成と実行が確立されたすべてのアクセス制御を遵守することを保証します。これにより、データの強固なセキュリティとガバナンスが保証されます。

アクセス制御の要件

セマンティックモデルで Cortex Analyst を使用するには、以下の権限が必要です。

権限

オブジェクト

USAGE

セマンティックモデルがステージにアップロードされている場合、セマンティックモデル YAML ファイルを含むステージ。

SELECT

セマンティックモデルで定義されたテーブル。

Cortex Analyst API へのリクエストには認証情報を含める必要があります。このトピックの例では、セッショントークンを使用してSnowflakeアカウントを認証します。

リージョンの可用性

Cortex Analyst は以下の地域でネイティブに利用できます。

  • AWS ap-northeast-1(東京)

  • AWS ap-southeast-2(シドニー)

  • AWS us-east-1(バージニア)

  • AWS us-west-2(オレゴン)

  • AWS eu-central-1(フランクフルト)

  • AWS eu-west-1(アイルランド)

  • Azure東 US 2(バージニア)

  • Azure西ヨーロッパ(オランダ)

Snowflakeアカウントが別のクラウドリージョンにある場合でも、 クロスリージョン推論 を活用して Cortex Analyst を使用することができます。クロスリージョン推論が有効になると、 Cortex Analyst は、デフォルトのリージョンでは利用できないモデルについて、他のリージョンからのリクエストを処理します。最適なパフォーマンスを得るには、 AWS US リージョンとクロスリージョンを構成します。

注釈

Azure OpenAI モデルの使用を選択した場合、 Cortex Analyst は、Gov および VPS デプロイメントを除く、すべての AWS 、Azure、および GCP リージョンで使用できます。

既知の問題と制限

  • セマンティックモデル YAML ファイルをステージにアップロードした場合、そのセマンティックモデルへのアクセスは、アップロードされたステージへのアクセスによって制御されます。これは、ステージにアクセスできるロールであれば、そのロールが基礎となるテーブルにアクセスできなくても、そのステージ上のセマンティックモデルにアクセスできることを意味します。

  • 結合はセマンティックモデルでは直接サポートされていません。代わりに、事前に結合されたデータを含むビューを使用します。

  • デフォルトでは、 Cortex Analyst は毎分20リクエストにレート制限されており、コンセプトの実証には十分です。より高い限度額をご希望の場合は、セールスエンジニアにお問い合わせください。

Azure OpenAI モデルの使用を可能にする

デフォルトでは、 Cortex Analyst はSnowflakeがホストするCortex LLMs で動作します。ただし、明示的にオプトインすることで、 Cortex Analyst がSnowflakeがホストするモデルと並行して、Microsoft Azureがホストする最新の OpenAI GPT モデルを使用できるようにすることができます。実行時には、 Cortex Analyst は、各クエリに対して最高の精度とパフォーマンスを確保するために、モデルの最適な組み合わせを選択します。

ENABLE_CORTEX_ANALYST_MODEL_AZURE_OPENAI パラメーターを使用して、Azure OpenAI GPT モデルの使用を許可するようにアカウントを設定できます。デフォルトでは、パラメーターは無効になっており、 ALTER ACCOUNT コマンドを使用して ACCOUNTADMIN ロールにのみ設定できます。

USE ROLE ACCOUNTADMIN;

ALTER ACCOUNT SET ENABLE_CORTEX_ANALYST_MODEL_AZURE_OPENAI = TRUE;
Copy

Tip

このパラメーターの現在値を見るには、以下の SQL ステートメントを使用します。

SHOW PARAMETERS LIKE 'ENABLE_CORTEX_ANALYST_MODEL_AZURE_OPENAI' IN ACCOUNT
Copy

詳細については、 ENABLE_CORTEX_ANALYST_MODEL_AZURE_OPENAI をご参照ください。

このパラメーターが有効な場合、 Cortex Analyst は以下のいずれかの組み合わせで給電されます。

  • Snowflakeホストモデル、現在はMistral LargeとLlama3モデル

  • Azure OpenAI モデル、現在は GPT-4o(明示的なオプトインが必要)

注釈

Cortex Analyst は今後、パフォーマンスと精度をさらに向上させるために、異なるモデルを使用する可能性があります。

考慮事項

セマンティックモデルファイルは メタデータ として分類されます。 Cortex Analyst で Azure OpenAI モデルの使用を選択した場合、あなたのセマンティックモデルはサードパーティであるMicrosoft Azureによって処理されます。ただし、顧客データがAzureと共有されたり、Azureによって処理されたりすることはありません。

ENABLE_CORTEX_ANALYST_MODEL_AZURE_OPENAI

TRUE の場合、 ENABLE_CORTEX_ANALYST_MODEL_AZURE_OPENAI アカウントパラメーター は、 Cortex Analyst がAzure OpenAI モデルを使用できるようになります。

パラメータータイプ

セッション

データ型

BOOLEAN

説明

Cortex Analyst がリクエストを処理するためにAzure OpenAI モデルを使用できるかどうかを制御します。

  • FALSE: Cortex Analyst は、リクエストを処理するためにSnowflakeホストモデルのみを使用します。

  • TRUE: Cortex Analyst は、リクエストを処理するために、Snowflakeホストモデルに加えて、Azure OpenAI モデルを使用することができます。

デフォルト

FALSE

Cortex Analyst の例

以下の手順に従って、Snowflake(SiS)でインタラクティブなStreamlitを作成するか、 Cortex Analyst を使用するスタンドアロンのStreamlitアプリを作成してください。

  1. セマンティックモデルを作成する

  2. セマンティックモデルをステージにアップロードする

  3. Snowflakeアプリで Streamlit を作成し、実行する

  4. SnowflakeアプリのStreamlitで交流する

セマンティックモデルの作成

セマンティックモデル は、データセットに関する追加のセマンティックな詳細を指定できるようにすることで、ビジネスユーザーとデータベース定義の間の言語の違いに関連する問題に対処する軽量なメカニズムです。より説明的な名前や同義語のような、このような追加的なセマンティックな詳細によって、 Cortex Analyst は、データに関する質問に対してより確実に回答できるようになります。

  1. Cortex Analyst に答えてもらいたい質問のリストから始めます。それに基づいて、セマンティックモデルのデータセットを決めます。

  2. 仕様 に基づいて、セマンティックモデル YAML を作成します。便宜上、 セマンティックモデルジェネレーター をお試しください。また、 セマンティックモデルを作成するためのヒント も必ず確認してください。

セマンティックモデルのアップロード

セマンティックモデル YAML ファイルを ステージ にアップロードするか、セマンティックモデル YAML をリクエストボディの文字列として渡すことができます。セマンティックモデル YAML をステージにアップロードした場合、そのセマンティックモデルへのアクセスは、アップロードされたステージへのアクセスによって制御されます。これは、ステージへのアクセス権を持つロールが、そのモデルのベースとなるテーブルへのアクセス権を持っていなくても、そのステージ上のセマンティックモデルにアクセスできることを意味します。ステージにアクセス権を付与されたロールが、そのステージ上のすべてのセマンティックモデルで参照されるすべてのテーブルに対して、 SELECT アクセス権を持つようにします。

以下は、セマンティックモデルを含むステージのセットアップ方法の例です。あるステージ(public)には組織の全メンバーがアクセスできますが、別のステージ(sales)には sales_analyst ロールにしかアクセスできません。

ステージ用のデータベースとスキーマを作成する。次の例では、 semantic_model という名前のデータベースを、 definition という名前のスキーマで作成していますが、これらの名前には任意の有効な識別子文字列を使用できます。

CREATE DATABASE semantic_model;
CREATE SCHEMA semantic_model.definitions;
GRANT USAGE ON DATABASE semantic_model TO ROLE PUBLIC;
GRANT USAGE ON SCHEMA semantic_model.definitions TO ROLE PUBLIC;

USE SCHEMA semantic_model.definitions;
Copy

次に、セマンティックモデルを保存するためのステージを作成します。

CREATE STAGE public DIRECTORY = (ENABLE = TRUE);
GRANT READ ON STAGE public TO ROLE PUBLIC;

CREATE STAGE sales DIRECTORY = (ENABLE = TRUE);
GRANT READ ON STAGE sales TO ROLE sales_analyst;
Copy

Snowsightを使用している場合は、ページをリフレッシュして、 データベースオブジェクトエクスプローラー で新しく作成されたステージを見つけることができます。新しいタブでステージページを開き、Snowsightの YAML ファイルをアップロードできます。

または、 Snowflake CLI クライアント を使用して、ローカルファイルシステムからアップロードすることもできます。

snow stage copy file:///path/to/local/file.yaml @sales
Copy

SnowflakeアプリでStreamlitを作成する

この例では、自然言語による質問を入力として受け取り、 Cortex Analyst を呼び出して、提供されたセマンティックモデルに基づいて回答を生成する、SnowflakeアプリのStreamlitを作成する方法を示します。

SnowflakeでのStreamlitアプリの作成と実行の詳細については、 Streamlit in Snowflake について をご参照ください。

  1. Snowsight を使用してStreamlitアプリを作成する の指示に従って、Snowsightに新しいStreamlitアプリを作成します。

  2. 以下のStreamlitのコードをコードエディターにコピーします。

  3. プレースホルダーの値をあなたのアカウント詳細に置き換えます。

  4. アプリをプレビューするには、 Run を選択し、Streamlitプレビューペインのコンテンツを更新します。

from typing import Dict, List, Optional

import _snowflake
import json
import streamlit as st
import time
from snowflake.snowpark.context import get_active_session

DATABASE = "SNOWFLAKE_SEMANTIC_CONTEXT"
SCHEMA = "DEFINITIONS"
STAGE = "PUBLIC"
FILE = "revenue_timeseries.yaml"

def send_message(prompt: str) -> dict:
    """Calls the REST API and returns the response."""
    request_body = {
        "messages": [
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": prompt
                    }
                ]
            }
        ],
        "semantic_model_file": f"@{DATABASE}.{SCHEMA}.{STAGE}/{FILE}",
    }

    resp = _snowflake.send_snow_api_request(
        "POST",
        f"/api/v2/cortex/analyst/message",
        {},
        {},
        request_body,
        {},
        30000,
    )

    if resp["status"] < 400:
        return json.loads(resp["content"])
    else:
        st.session_state.messages.pop()
        raise Exception(
            f"Failed request with status {resp['status']}: {resp}"
        )

def process_message(prompt: str) -> None:
    """Processes a message and adds the response to the chat."""
    st.session_state.messages.append(
        {"role": "user", "content": [{"type": "text", "text": prompt}]}
    )
    with st.chat_message("user"):
        st.markdown(prompt)
    with st.chat_message("assistant"):
        with st.spinner("Generating response..."):
            response = send_message(prompt=prompt)
            request_id = response["request_id"]
            content = response["message"]["content"]
            st.session_state.messages.append(
                {**response['message'], "request_id": request_id}
            )
            display_content(content=content, request_id=request_id)  # type: ignore[arg-type]


def display_content(
    content: List[Dict[str, str]],
    request_id: Optional[str] = None,
    message_index: Optional[int] = None,
) -> None:
    """Displays a content item for a message."""
    message_index = message_index or len(st.session_state.messages)
    if request_id:
        with st.expander("Request ID", expanded=False):
            st.markdown(request_id)
    for item in content:
        if item["type"] == "text":
            st.markdown(item["text"])
        elif item["type"] == "suggestions":
            with st.expander("Suggestions", expanded=True):
                for suggestion_index, suggestion in enumerate(item["suggestions"]):
                    if st.button(suggestion, key=f"{message_index}_{suggestion_index}"):
                        st.session_state.active_suggestion = suggestion
        elif item["type"] == "sql":
            display_sql(item["statement"])


@st.cache_data
def display_sql(sql: str) -> None:
    with st.expander("SQL Query", expanded=False):
        st.code(sql, language="sql")
    with st.expander("Results", expanded=True):
        with st.spinner("Running SQL..."):
            session = get_active_session()
            df = session.sql(sql).to_pandas()
            if len(df.index) > 1:
                data_tab, line_tab, bar_tab = st.tabs(
                    ["Data", "Line Chart", "Bar Chart"]
                )
                data_tab.dataframe(df)
                if len(df.columns) > 1:
                    df = df.set_index(df.columns[0])
                with line_tab:
                    st.line_chart(df)
                with bar_tab:
                    st.bar_chart(df)
            else:
                st.dataframe(df)


def show_conversation_history() -> None:
    for message_index, message in enumerate(st.session_state.messages):
        chat_role = "assistant" if message["role"] == "analyst" else "user"
        with st.chat_message(chat_role):
            display_content(
                content=message["content"],
                request_id=message.get("request_id"),
                message_index=message_index,
            )


def reset() -> None:
    st.session_state.messages = []
    st.session_state.suggestions = []
    st.session_state.active_suggestion = None


st.title("Cortex analyst")
st.markdown(f"Semantic Model: `{FILE}`")

if "messages" not in st.session_state:
    reset()

with st.sidebar:
    if st.button("Reset conversation"):
        reset()

show_conversation_history()

if user_input := st.chat_input("What is your question?"):
    process_message(prompt=user_input)

if st.session_state.active_suggestion:
    process_message(prompt=st.session_state.active_suggestion)
    st.session_state.active_suggestion = None
Copy

Streamlitアプリとの連動

  1. ブラウザのStreamlitアプリ、またはSnowflakeプレビューペインのStreamlitに移動します。

  2. データについて自然言語で質問を始める(例: 「どんな質問ができますか?」)。

スタンドアロンStreamlitアプリの作成

また、上記のサンプルコードを使用してスタンドアロンアプリを構築することもできます。

  1. Streamlit をインストールします。

  2. analyst_api.py というPythonファイルをローカルに作成します。

  3. 以下のStreamlitのコードをファイルにコピーします。

  4. プレースホルダーの値をあなたのアカウント詳細に置き換えます。

  5. streamlit run analyst_api.py を使用してStreamlitアプリを実行します。

次のコードで指定されたデータベースとスキーマは、セマンティックモデル YAML ファイルのステージの場所となる場所です。Snowflakeコネクタで使用されるロールは、セマンティックモデルで定義された基礎データにアクセスできる必要があります。

from typing import Any, Dict, List, Optional

import pandas as pd
import requests
import snowflake.connector
import streamlit as st


HOST = "<host>"
DATABASE = "<database>"
SCHEMA = "<schema>"
STAGE = "<stage>"
FILE = "<file>"

if 'CONN' not in st.session_state or st.session_state.CONN is None:
    st.session_state.CONN = snowflake.connector.connect(
        user="<user>",
        password="<password>",
        account="<account>",
        host=HOST,
        port=443,
        warehouse="<warehouse>",
        role="<role>",
    )


def send_message(prompt: str) -> Dict[str, Any]:
    """Calls the REST API and returns the response."""
    request_body = {
        "messages": [{"role": "user", "content": [{"type": "text", "text": prompt}]}],
        "semantic_model_file": f"@{DATABASE}.{SCHEMA}.{STAGE}/{FILE}",
    }
    resp = requests.post(
        url=f"https://{HOST}/api/v2/cortex/analyst/message",
        json=request_body,
        headers={
            "Authorization": f'Snowflake Token="{st.session_state.CONN.rest.token}"',
            "Content-Type": "application/json",
        },
    )
    request_id = resp.headers.get("X-Snowflake-Request-Id")
    if resp.status_code < 400:
        return {**resp.json(), "request_id": request_id}  # type: ignore[arg-type]
    else:
        st.session_state.messages.pop()
        raise Exception(
            f"Failed request (id: {request_id}) with status {resp.status_code}: {resp.text}"
        )


def process_message(prompt: str) -> None:
    """Processes a message and adds the response to the chat."""
    st.session_state.messages.append(
        {"role": "user", "content": [{"type": "text", "text": prompt}]}
    )
    with st.chat_message("user"):
        st.markdown(prompt)
    with st.chat_message("assistant"):
        with st.spinner("Generating response..."):
            response = send_message(prompt=prompt)
            request_id = response["request_id"]
            content = response["message"]["content"]
            st.session_state.messages.append(
                {**response['message'], "request_id": request_id}
            )
            display_content(content=content, request_id=request_id)  # type: ignore[arg-type]


def display_content(
    content: List[Dict[str, str]],
    request_id: Optional[str] = None,
    message_index: Optional[int] = None,
) -> None:
    """Displays a content item for a message."""
    message_index = message_index or len(st.session_state.messages)
    if request_id:
        with st.expander("Request ID", expanded=False):
            st.markdown(request_id)
    for item in content:
        if item["type"] == "text":
            st.markdown(item["text"])
        elif item["type"] == "suggestions":
            with st.expander("Suggestions", expanded=True):
                for suggestion_index, suggestion in enumerate(item["suggestions"]):
                    if st.button(suggestion, key=f"{message_index}_{suggestion_index}"):
                        st.session_state.active_suggestion = suggestion
        elif item["type"] == "sql":
            display_sql(item["statement"])


@st.cache_data
def display_sql(sql: str) -> None:
    with st.expander("SQL Query", expanded=False):
        st.code(sql, language="sql")
    with st.expander("Results", expanded=True):
        with st.spinner("Running SQL..."):
            df = pd.read_sql(sql, st.session_state.CONN)
            if len(df.index) > 1:
                data_tab, line_tab, bar_tab = st.tabs(
                    ["Data", "Line Chart", "Bar Chart"]
                )
                data_tab.dataframe(df)
                if len(df.columns) > 1:
                    df = df.set_index(df.columns[0])
                with line_tab:
                    st.line_chart(df)
                with bar_tab:
                    st.bar_chart(df)
            else:
                st.dataframe(df)


def show_conversation_history() -> None:
    for message_index, message in enumerate(st.session_state.messages):
        chat_role = "assistant" if message["role"] == "analyst" else "user"
        with st.chat_message(chat_role):
            display_content(
                content=message["content"],
                request_id=message.get("request_id"),
                message_index=message_index,
            )


def reset() -> None:
    st.session_state.messages = []
    st.session_state.suggestions = []
    st.session_state.active_suggestion = None


st.title("Cortex analyst")
st.markdown(f"Semantic Model: `{FILE}`")

if "messages" not in st.session_state:
    reset()

with st.sidebar:
    if st.button("Reset conversation"):
        reset()

show_conversation_history()

if user_input := st.chat_input("What is your question?"):
    process_message(prompt=user_input)

if st.session_state.active_suggestion:
    process_message(prompt=st.session_state.active_suggestion)
    st.session_state.active_suggestion = None
Copy

Cortex Analyst 機能を無効にする

アカウントで Cortex Analyst を使用したくない場合は、 ACCOUNTADMIN ロールを使用して ENABLE_CORTEX_ANALYST パラメーターを変更し、機能を無効にしてください。

USE ROLE ACCOUNTADMIN;
ALTER ACCOUNT SET ENABLE_CORTEX_ANALYST = FALSE;
Copy

パラメータータイプ

セッション

データ型

BOOLEAN

説明

アカウントで Cortex Analyst 機能を有効にするかどうかを制御します。

  • FALSE: Cortex Analyst 機能は利用できません。

  • TRUE: Cortex Analyst 機能が利用可能です。ENABLE_CORTEX_ANALYST_MODEL_AZURE_OPENAI が TRUE に設定されている場合、 Cortex Analyst はSnowflakeがホストするモデルだけでなく、Azure OpenAI モデルも使用できます。そうでない場合は、Snowflakeがホストするモデルのみが使用できます。

デフォルト

TRUE

コストの考慮事項

Cortex Analyst は2024年11月15日まで無料です。価格と請求に関する詳細は近日中に発表されます。