🤖

Cortex Analyst のリクエスト数を用途ごとにモニタリングしよう

に公開

Snowflake の AI 機能、とても便利ですよね。弊社でも Cortex Analyst/Search や AISQL といった各種 AI 機能の業務活用について模索・検証しています。

一方で、Snowflake に限らずこうした AI/LLM 系機能の利用は通常の SQL ワークロードと比較してコストが大きくなりがちです。検証段階であればそこまで気にする必要がなくても、社内で広く利用してもらうことを考えた際にはガードレールを適切に敷き、コストコントロール可能な状態にしておくことが重要だと思います。

本記事では Cortex Analyst のコストコントロールを念頭に、利用料(=リクエスト数)を用途ごとにモニタリングする方法についてご紹介したいと思います。

Cortex Analyst の課金体系

Cortex Analyst は、自然言語からのクエリ自動生成 (Text2SQL) をサポートする Snowflake Cortex 機能の一つです。ユーザーが独自定義したセマンティックレイヤーに対してビジネスユーザーが自然言語で問いかけると、LLM はその意図を解釈して対応する SQL の生成を試みます。

Cortex Analyst の課金体系は メッセージ数ベース となっていて、執筆時点で 67 Credits per 1,000 messages [1] となっています。メッセージ数は Cortex Analyst にリクエストを投げた回数で、以降「リクエスト数」と表現します。

参考までに、AWS・東京リージョンの Snowflake アカウントの場合、各 Edition のリクエスト単価は以下のようになります。(1ドル=150円換算)

  • Standard Edition ... 約29円/Request
  • Enterprise Edition ... 約43円/Request
  • Business Critical Edition ... 約57円/Request

このように、Cortex Analyst におけるコスト的ガードレールを検討する場合、そのリクエスト数を計測する仕組みがまず必要になります。

モニタリング実現のアプローチ

Budgets について

Snowflake の Budgets 機能を使用することで、特定の Snowflake オブジェクトグループに対するクレジット使用状況をアカウントレベルでモニタリングすることが可能です。[2]

Cortex Analyst を含む AI/LLM 系機能の利用は、サービスタイプ AI_SERVICES として記録されるので、Budgets を利用するとアカウント全体での AI/LLM 系機能のクレジット使用状況を把握することができます。

しかし、実際にはより詳細な粒度で計測したい場合も多いと思います。例えば、Cortex Analyst の利用において、用途 A では n_{a} 回まで、用途 B では n_{b} 回まで利用を許可したい、といったようなケースです。この場合、Budgets では上記要件を満たすことができません。

CORTEX_ANALYST_REQUESTS_V について

上記要件を満たす方法について調べていたところ、Snowflake 担当 SE の方より SNOWFLAKE.LOCAL.CORTEX_ANALYST_REQUESTS_V を利用する方法をご紹介いただきました。

この View には、Cortex Analyst のみに対するリクエストが記録されており、user_id, primary_role_name, semantic_model_name のような詳細な情報を含みます。例えば用途毎に利用するアカウントロールを分けるなどしておけば、やりたいことを実現できそうです。

アーキテクチャ

(アーキテクチャというほどのものでもないですが、)全体像は以下の通りです。

  • Procedure で CORTEX_ANALYST_REQUESTS_V を集計し、その結果を Slack 通知させます
  • 定期的に Procedure を CALL する Serverless Task を用意します

Task の部分は、Alert(例えば一時間おきに View を集計し、条件を満たしたら Slack 通知させる)に置き換えても良いかもしれません。

実装

具体的な実装手順について、以降で説明していきます。

View 参照権限の付与

CORTEX_ANALYST_REQUESTS_V View を参照するには、使用するロールにアプリケーションロール SNOWFLAKE.CORTEX_ANALYST_REQUESTS_ADMIN が Grant されている必要があります。[3]

If you are using a role that has been granted the SNOWFLAKE.CORTEX_ANALYST_REQUESTS_ADMIN application role, you can query the SNOWFLAKE.LOCAL.CORTEX_ANALYST_REQUESTS_V view. This view includes all requests to Cortex Analyst across all semantic models and views.

以下を実行し、cortex_admin_role にアプリケーションロールを Grant します。

USE ROLE accountadmin;

GRANT APPLICATION ROLE snowflake.cortex_analyst_requests_admin
TO ROLE cortex_admin_role;

これにより cortex_admin_role で目的の View を参照できるようになります。

USE ROLE cortex_admin_role;

SELECT *
FROM snowflake.local.cortex_analyst_requests_v
ORDER BY timestamp DESC
LIMIT 100;

通知統合の作成

Slack 通知用の通知統合リソース、およびそれに必要な Snowflake シークレットを作成します。
Webhook タイプの通知統合など、一部リソースが Terraform Provider 対応していないため、本記事では SQL で作成していきます。

Snowflake シークレット

Slack Webhook 用 URL の https://hooks.slack.com/services/ 以降の値を、Snowflake シークレットオブジェクトとして作成します。

CREATE OR REPLACE SECRET mydb.myschema.slack_webhook_cortex
  TYPE = GENERIC_STRING
  SECRET_STRING = 'T..../B..../........'
  COMMENT = 'Secret for Slack Webhook'

次の手順で通知統合を作成する際にシークレットを利用できるよう、accountadmin ロールに USAGE 権限を Grant します。

USE ROLE <SECRET_OWNER_ROLE>;

GRANT USAGE ON SECRET mydb.myschema.slack_webhook_cortex
TO ROLE accountadmin;

通知統合

続いて Webhook タイプの通知統合を作成します。

USE ROLE accountadmin;

CREATE OR REPLACE NOTIFICATION INTEGRATION slack_webhook_cortex 
    TYPE = WEBHOOK
    ENABLED = TRUE
    WEBHOOK_URL = 'https://hooks.slack.com/services/SNOWFLAKE_WEBHOOK_SECRET'
    WEBHOOK_SECRET = mydb.myschema.slack_webhook_cortex
    WEBHOOK_HEADERS = ('Content-Type'='application/json')
;

-- 作成された通知統合の確認
DESC NOTIFICATION INTEGRATION slack_webhook_cortex;

Slack 通知用 Procedure

例えば以下のような通知内容の Procedure を実装してみます。
リソース名は、適当に MYDB.MYSCHEMA.NOTIFY_SLACK__CA_REQUESTS_COUNT(VARCHAR, NUMBER) としておきます。

処理ロジックは以下に示す SQL の通りです。引数として TARGET_ROLE (VARCHAR型) と REQUESTS_COUNT_LIMIT (NUMBER型) を受け取ります。

  • TARGET_ROLE に指定されたロール名で Cortex Analyst へのリクエスト数を集計し、Semantic View 毎のリクエストとその合計を通知しています。
  • また、リクエスト数合計が REQUESTS_COUNT_LIMIT で指定した数よりも大きい場合には、左のバーが赤くなるようにしています。
definition.sql
CALL SYSTEM$SEND_SNOWFLAKE_NOTIFICATION(
  SNOWFLAKE.NOTIFICATION.APPLICATION_JSON(
    WITH requests_count_table AS (
      SELECT 
        semantic_model_name,
        primary_role_name,
        COUNT(request_id) AS requests_count,
      FROM 
        snowflake.local.cortex_analyst_requests_v
      WHERE 
        semantic_model_type = 'SEMANTIC_VIEW'
        AND last_day(timestamp) = last_day(current_date())
        AND primary_role_name = :TARGET_ROLE
      GROUP BY semantic_model_name, primary_role_name
    ),
    message_table AS (
      SELECT 
        OBJECT_CONSTRUCT(
          'blocks', ARRAY_CONSTRUCT(
            OBJECT_CONSTRUCT('type', 'section', 'text', OBJECT_CONSTRUCT('type', 'mrkdwn', 'text', ':robot_face: *Cortex Analyst Requests Count Report (${account_env})*')),
            OBJECT_CONSTRUCT('type', 'divider')
          ),
          'attachments', ARRAY_CONSTRUCT(
            OBJECT_CONSTRUCT(
              'color', CASE WHEN SUM(requests_count) <= :REQUESTS_COUNT_LIMIT THEN '#26a69a' ELSE '#ef5350' END,
              'blocks', ARRAY_CONSTRUCT(
                OBJECT_CONSTRUCT('type', 'section', 'text', OBJECT_CONSTRUCT('type', 'mrkdwn', 'text', 'Target Role: `' || :TARGET_ROLE || '`\n')),
                OBJECT_CONSTRUCT('type', 'section', 'text', OBJECT_CONSTRUCT('type', 'mrkdwn', 'text', 'Total: `' || TO_VARCHAR(SUM(requests_count)) || '` requests\n')),
                OBJECT_CONSTRUCT('type', 'divider'),
                OBJECT_CONSTRUCT('type', 'section', 'text', OBJECT_CONSTRUCT('type', 'mrkdwn', 'text', LISTAGG('- `' || LOWER(semantic_model_name) || '` ... `' || TO_VARCHAR(requests_count) || '` requests\n') WITHIN GROUP (ORDER BY requests_count DESC)))
              )
            )
          )
        )::string AS message_json
      FROM requests_count_table
    )
    SELECT message_json FROM message_table
  ),
  SNOWFLAKE.NOTIFICATION.INTEGRATION('SLACK_WEBHOOK_COST')
);

Slack 通知定期実行用 Serverless Task

最後に、定期的に上記の通知 Procedure を実行する Serverless Task を作成します。

CREATE OR REPLACE TASK
  MYDB.MYSCHEMA.NOTIFY_SLACK__CA_REQUESTS_COUNT__CHAT_APP_DAILY
  SCHEDULE='USING CRON 00 8 * * * Asia/Tokyo'
  USER_TASK_MANAGED_INITIAL_WAREHOUSE_SIZE='XSMALL'
  USER_TASK_TIMEOUT_MS=60000
  AS $$
  CALL MYDB.MYSCHEMA.NOTIFY_SLACK__CA_REQUESTS_COUNT('CHAT_APP_ROLE', 100)
  $$
;

実装に関する説明は以上です。

さいごに

Cortex Analyst の利用量を用途毎にモニタリングする方法について書いてみました。

今年 9/11~12 で開催された SWTT でもやはり Cortex 機能に関するセッションも多く、特に Snowflake セッションだけでなく、ユーザー事例が着実に増えてきているのが印象的でした。

AI によって解決可能になった問題は一気に増えたので、ROI を説明可能にしておくことが長期的にはより大事になってくるのだと思います。今回は Cortex Analyst をテーマに扱いましたが、それ以外に関してもガバナンス向上のための施策は継続して取り組んでいきたいと考えています。

最後まで読んでいただき、ありがとうございました。

脚注
  1. Snowflake Service Consumption Table (PDF) - Snowflake ↩︎

  2. Monitor credit usage with budgets ↩︎

  3. Cortex Analyst administrator monitoring - Snowflake Documentation ↩︎

Snowflake Data Heroes

Discussion