1. はじめに
SELECT AI_COMPLETE(
model => 'snowflake-arctic',
prompt => concat('Summarize this transcript in less than 200 words', transcript)
) as summary
FROM call_transcripts LIMIT 1;
これはSnowflakeで実際に動くSQLです。見ての通り、SELECT文の中でLLM(大規模言語モデル)を呼び出して、テーブルに格納されたテキストデータを要約しています。
SnowflakeにはCortex AI関数という機能があり、SQLの中でAI処理を直接実行できます。テキストの要約、分類、感情分析、ドキュメントからのデータ抽出など、従来であれば専用のMLパイプラインやAIツールが必要だった処理を、普段使い慣れたSQLで実現できるのが特徴です。
本記事では、Cortex AI関数には「どんな関数があるのか」「実際に動かすとどんな感じなのか」を、SQLサンプルと実行結果を交えてレポートします。
SQLは日常的に書くけれどAI/MLは専門外、という方にとって参考になれば幸いです。
2. Cortex AI関数とは
Snowflake Cortex AIの中での位置づけ
Snowflakeは「Cortex AI」というブランドのもとで、生成AI関連の機能を一つのスタックとして提供しています。このスタックには、非構造化データの検索を行うCortex Search、構造化データに対して自然言語で問い合わせるCortex Analyst、これらを組み合わせてAIエージェントを構築するCortex Agentsなど、さまざまなコンポーネントが含まれています。
Cortex AI関数は、このスタックの中で「スケーラブルなAI処理」を担うレイヤーに位置します。SQLの関数としてAIの機能を呼び出せるため、既存のSQLワークフローにそのまま組み込める点が最大の特徴です。
3つの特徴
- サーバレスで動作する
GPUインフラの管理は不要です。Snowflakeがフルマネージドで提供するLLM推論基盤の上で関数が実行されるため、利用者はSQLを書くだけで済みます。 - 複数のAIモデルを選択できる
OpenAI、Anthropic(Claude)、Meta(Llama)、Mistral AI、Google(Gemini)、DeepSeek、そしてSnowflake独自のモデルなど、複数ベンダーのモデルが利用可能です。関数のパラメータでモデルを指定するだけで切り替えられます。 - SQLの構文と自然に統合されている
これがCortex AI関数の最も面白い点です。AI処理がSQLの各機能と対応する形で設計されています。- SELECT句(スカラー計算)→ AI_COMPLETE、AI_EXTRACT
- WHERE句(フィルタリング)→ AI_FILTER
- GROUP BY句(集約)→ AI_AGG、AI_SUMMARIZE_AGG
- CASE…WHEN句(条件分岐)→ AI_CLASSIFY
- JOIN句 → JOIN ON AI_FILTER
つまり、普段SQLで書いている処理パターンの延長線上でAIを使えるということです。新しいフレームワークやAPIの作法を覚える必要がないため、SQLユーザーにとっては非常に取り組みやすい設計になっています。
3. Cortex AI関数カタログ
Cortex AI関数として提供されている関数を、用途別に整理しました。「どんな関数があって、何ができるのか」をまず全体像として把握してください。
汎用テキスト処理
| 関数名 | 機能概要 | 対象データ |
|---|---|---|
| AI_COMPLETE | プロンプトを指定して汎用的なタスクを実行する、最も基本的なLLM関数。 要約、生成、分析など幅広い用途に対応。利用するモデルを選択可能 | テキスト / 画像 |
| AI_TRANSLATE | テキストの翻訳を行う | テキスト |
| SUMMARIZE | テキストの要約を行う。プロンプト不要でシンプルに使える | テキスト |
| EXTRACT_ANSWER | テキストからプロンプトに従い回答を抽出する | テキスト |
AI_COMPLETEはCortex AI関数の中で最も汎用的な関数です。モデルを指定し、プロンプトとデータを渡すだけで、要約・分類・生成など多様なタスクを実行できます。テキストだけでなく画像も入力に取れるマルチモーダル対応で、出力もテキストとJSON(構造化出力)の両方に対応しています。
分類・フィルタリング
| 関数名 | 機能概要 | 対象データ |
|---|---|---|
| AI_CLASSIFY | ユーザーが指定したラベルにデータを分類する。 1つの入力に複数ラベルを付けるマルチラベル分類にも対応 | テキスト / 画像 |
| AI_FILTER | 入力に対してTrue / Falseの判定を行う。 WHERE句と組み合わせてセマンティックなフィルタリングが可能 | テキスト / 画像 |
| AI_SENTIMENT | テキストの感情を分類する。 文章全体の判定に加え、「価格」「味」などカテゴリ別に感情を分析するアスペクトベースの分類にも対応 | テキスト |
AI_FILTERは従来のフィルタリングと比べて大幅に工程を削減できるのが特徴です。たとえば「ポジティブなレビューだけ抽出する」という処理は、従来であれば感情スコア化やクレンジングなどの前処理が必要でしたが、AI_FILTERなら「ポジティブな内容か?」と自然言語で条件を書くだけで実現できます。
集約・要約
| 関数名 | 機能概要 | 対象データ |
|---|---|---|
| AI_AGG | プロンプトを指定して、グループ単位のインサイトを出力する集計関数。 GROUP BYと組み合わせて使う | テキスト |
| AI_SUMMARIZE_AGG | グループ単位の要約を出力する集計関数。AI_AGGと異なりプロンプト不要で手軽に使える | テキスト |
この2つはSQLのGROUP BY句と組み合わせて使う集計関数です。AI_AGGはプロンプトで「価格に関する内容を要約して」のように分析の切り口を指定できるのに対し、AI_SUMMARIZE_AGGはプロンプト不要で汎用的な要約を返します。用途に応じて使い分けるイメージです。
データ抽出・変換
| 関数名 | 機能概要 | 対象データ |
|---|---|---|
| AI_EXTRACT | 入力データからプロンプトに従ってデータを抽出する。 事前学習なしにQA形式で項目を取り出せる | テキスト / ドキュメント / 画像 |
| AI_PARSE_DOCUMENT | ドキュメントからテキストやレイアウト(表組みなど)を抽出する。OCR処理にも対応 | テキスト / ドキュメント / 画像 |
| AI_TRANSCRIBE | 音声データからテキストを抽出する。 タイムスタンプや話者識別にも対応 | 音声 |
| AI_REDACT | テキスト内の個人情報(PII)を検出し、マスキングする。 氏名、住所、電話番号、クレジットカード番号など幅広い項目に対応 | テキスト |
AI_EXTRACTは請求書や契約書からの項目抽出に便利です。「合計金額はいくら?」「請求元企業の名前は?」のようにQA形式で抽出項目を指定でき、事前のモデル学習が不要な点が実用的です。AI_REDACTは日本語の住所やマイナンバーにも対応しており、コンプライアンス用途で重宝しそうです。
ベクトル・類似度
| 関数名 | 機能概要 | 対象データ |
|---|---|---|
| AI_EMBED | テキストや画像をベクトル(数値の配列)に変換する。 同一関数で複数のモデル・データ形式に対応 | テキスト / 画像 |
| AI_SIMILARITY | 2つの入力のコサイン類似度を数値で出力する。 ベクトル化と類似度計算を1つの関数で実行できる | テキスト / 画像 |
この2つは、テキストや画像を数値ベクトルに変換し、意味的な近さを計算するための関数です。Cortex Searchを使ったRAG(検索拡張生成)チャットボットの構築や、類似ドキュメントの検索など、検索・推薦系のユースケースの基盤技術となります。
4. 実際に動かしてみた — 注目関数ピックアップ
事前準備
CREATE OR REPLACE TABLE sample_reviews (
review_id INT,
review_text STRING,
purchase_channel STRING
);
INSERT INTO sample_reviews VALUES
(1, '生鮮食品の価格は安くて満足しています。特に野菜の鮮度が良いです。', '実店舗'),
(2, '電化製品の値段が高すぎます。他のサイトの方が安かったです。', '実店舗'),
(3, '全体的に安くて助かっています。ただ送料がもう少し安いと嬉しいです。', 'ECサイト'),
(4, '商品の品質は良いのですが、配送に3週間かかりました。改善してほしいです。', 'ECサイト'),
(5, '週末は観光を楽しんできました。美味しいレストランで食事もできて最高でした。', 'ECサイト');
AI_COMPLETE
AI_COMPLETEはプロンプトとモデルを指定してLLMを呼び出す、最も基本的な関数です。まずはシンプルなテキスト要約を試しました。
SELECT
review_id,
AI_COMPLETE(
'snowflake-arctic',
CONCAT('以下のレビューを1文で要約してください: ', review_text)
) AS summary
FROM sample_reviews;
| REVIEW_ID | SUMMARY |
|---|---|
| 1 | 生鮮食品の価格が安く、野菜の鮮度が高いため満足しています。 |
| 2 | 電化製品の値段が高く、他のサイトで安いものがあった。 |
| 3 | 安いが助かっているが、送料が安くなると嬉しい。 |
| 4 | 商品品質良好ですが、配送速度改善を希望。 |
| 5 | 週末は観光と美味しい食事で楽しい時間を過ごしました。 |
別のモデル「llama4-maverick」を試してみます。
SELECT
review_id,
AI_COMPLETE(
'llama4-maverick',
CONCAT('以下のレビューを1文で要約してください: ', review_text)
) AS summary
FROM sample_reviews;
| REVIEW_ID | SUMMARY |
|---|---|
| 1 | 生鮮食品の価格が安く、特に野菜の鮮度が良いので、レビューアーはこの店に満足している。 |
| 2 | 商品の価格が高すぎて、他のサイトの価格の方が安かった。 |
| 3 | 安いので助かっているが、送料をもっと安くしてほしい。 |
| 4 | 商品の品質は良いが、配送に3週間かかったので改善してほしい。 |
| 5 | 週末は観光や食事を楽しみました。 |
review_id=3の「安くて助かるが送料が不満」を「中立」と判定しているあたり、ニュアンスをきちんと捉えています。
AI_CLASSIFY
AI_CLASSIFYは、ユーザーが指定したラベルにデータを分類する関数です。シングルラベルとマルチラベルの2つのモードがあります。ここではマルチラベルの挙動をご紹介します。
-- マルチラベル分類
SELECT
review_id,
AI_CLASSIFY(
review_text,
['価格', '品質', '配送', '食事', '観光', 'サービス'],
{'output_mode': 'multi'}
) AS categories
FROM sample_reviews;
| REVIEW_ID | CATEGORIES |
|---|---|
| 1 | [“価格”, “品質”] |
| 2 | [“価格”] |
| 3 | [“価格”, “配送”] |
| 4 | [“品質”, “配送”] |
| 5 | [“観光”, “食事”] |
マルチラベルの精度がかなり高いです。review_id=1の「価格が安くて満足、野菜の鮮度が良い」を「価格+品質」、review_id=4の「品質は良いが配送が遅い」を「品質+配送」と的確に分類しています。
ちなみにシングルラベルモードではreview_id=4が「価格」に誤分類される結果になりました。複数の話題を含むテキストにはマルチラベルモードを使うのがおすすめです。
AI_FILTER
AI_FILTERは、自然言語の条件でデータをフィルタリングする関数です。WHERE句の中で使えるのが直感的です。
-- ポジティブなレビューだけ抽出
SELECT review_id, review_text
FROM sample_reviews
WHERE AI_FILTER(CONCAT('ポジティブな内容か? : ', review_text)) = TRUE;
| REVIEW_ID | REVIEW_TEXT |
|---|---|
| 1 | 生鮮食品の価格は安くて満足しています。特に野菜の鮮度が良いです。 |
| 3 | 全体的に安くて助かっています。ただ送料がもう少し安いと嬉しいです。 |
| 5 | 週末は観光を楽しんできました。美味しいレストランで食事もできて最高でした。 |
-- 価格への不満を含むレビューを抽出
SELECT review_id, review_text
FROM sample_reviews
WHERE AI_FILTER(CONCAT('価格や料金に対する不満を含んでいるか? : ', review_text)) = TRUE;
| REVIEW_ID | REVIEW_TEXT |
|---|---|
| 2 | 電化製品の値段が高すぎます。他のサイトの方が安かったです。 |
| 3 | 全体的に安くて助かっています。ただ送料がもう少し安いと嬉しいです。 |
review_id=3が両方のフィルタに引っかかっている点が面白いです。「全体的には満足しているが送料に不満」というニュアンスを、ポジティブ判定でも価格不満判定でもきちんと拾っています。従来であれば感情スコア化やルールベースの前処理が必要だった処理が、WHERE句に自然言語を書くだけで5行のサンプルコードとは言え0.5〜0.9秒で返ってくるのは衝撃的でした。
AI_AGG
AI_AGGは、GROUP BYでグルーピングしたデータに対して、プロンプトで指定した切り口でAIが集約する関数です。
SELECT
purchase_channel,
AI_AGG(
review_text,
'顧客が不満に感じている点や改善要望を箇条書きで挙げてください'
) AS improvement_points
FROM sample_reviews
GROUP BY purchase_channel;
| PURCHASE_CHANNEL | IMPROVEMENT_POINTS |
|---|---|
| ECサイト | • 送料が安いと嬉しい • 配送が遅いので改善してほしい |
| 実店舗 | • 電化製品の価格が高すぎる • 他のサイトと比較して価格が高い |
プロンプトを「価格面で要約して」に変えれば価格に特化した要約が、「改善要望を挙げて」に変えれば不満点の一覧が返ってきます。同じデータに対して切り口を変えるだけで異なるインサイトを引き出せる点は、従来のSQLのGROUP BY+集計関数では不可能だった体験です。
AI_SENTIMENT
AI_SENTIMENTは、テキストの感情をpositive / negative / mixedで判定する関数です。カテゴリを指定すると、カテゴリごとに感情を分析するアスペクトベース分類も利用できます。
SELECT
review_id,
AI_SENTIMENT(review_text, ['価格', '品質', '配送']) AS sentiment
FROM sample_reviews;
| REVIEW_ID | overall | 価格 | 品質 | 配送 |
|---|---|---|---|---|
| 1 | positive | unclassified | unclassified | unclassified |
| 2 | negative | unclassified | unclassified | unclassified |
| 3 | mixed | unclassified | unclassified | unclassified |
| 4 | mixed | unclassified | unclassified | unclassified |
| 5 | positive | unclassified | unclassified | unclassified |
文章全体のoverall判定は正確です。review_id=3「安くて助かるが送料が不満」やreview_id=4「品質は良いが配送が遅い」をmixedと判定しており、ニュアンスを捉えています。一方で、アスペクトベース分類は日本語のカテゴリ名(「価格」「品質」「配送」)を指定した場合、すべて「unclassified」になりました。overallは使えるが、アスペクト別の分類は日本語では課題が残る状態です。
AI_REDACT
AI_REDACTは、テキスト内の個人情報(PII)を検出してマスキングする関数です。
SELECT AI_REDACT(
'私は山田太郎、38歳の男性です。住所は東京都渋谷区神宮前1-2-3です。
電話番号は03-1234-5678、メールアドレスはtaro.yamada@example.co.jpです。'
) AS redacted_text;
私は[NAME]、[AGE]歳の[GENDER]です。住所は[ADDRESS]です。
電話番号は[PHONE_NUMBER]、メールアドレスは[EMAIL]です。
氏名、年齢、性別、住所、電話番号、メールアドレスをすべて正確に検出し、[NAME]、[ADDRESS]のようなタグ付きで置換しています。日本語特有の住所表記(「東京都渋谷区神宮前1-2-3」)もきちんと認識しており、コンプライアンスやデータプライバシーの用途で実用レベルにあると感じました。処理時間は7.1秒と他の関数に比べてやや長めでしたが、PII検出の精度を考えれば許容範囲です。
5. 試してわかった3つのこと
日本語対応は概ね実用的
ただし関数によって差がある。今回試した15関数のうち、大半は日本語で十分な精度を発揮しました。AI_COMPLETE、AI_CLASSIFY、AI_FILTER、AI_AGGは日本語のテキストに対して期待通りの結果を返してくれます。 AI_REDACTの日本語対応は特に印象的でした。以下のように、氏名、年齢、性別、住所、電話番号、メールアドレスをすべて正確にマスキングしてくれます。
日本語特有の住所表記にも対応しており、コンプライアンスやデータプライバシーの用途で実用レベルにあると感じました。 一方で、AI_SENTIMENTのアスペクトベース分類は課題が残りました。日本語のカテゴリ名(「価格」「品質」「配送」)を指定した場合、文章全体のoverall判定は正確でしたが、個別カテゴリがすべて「unclassified」(分類不能)になりました。
アスペクト名を英語にすると改善する可能性はありますが、今回は未検証です。アスペクトベースの感情分析を日本語で使いたい場合は、AI_COMPLETEでプロンプトを工夫する方が現時点では確実かもしれません。
SQLが書ければAIが使える
これは使ってみて一番強く感じたことです。AI_FILTERのWHERE句やAI_AGGのGROUP BYなど、普段のSQLの延長線上でAI処理を実行できる設計は、学習コストが非常に低いです。 使用感としては、ChatGPTやGeminiをブラウザで使うのに近い感覚です。違いは、それがSQLのSELECT文の中でテーブルデータに対して一括実行できること。1件ずつコピー&ペーストでチャットに貼り付ける必要はありません。 特にAI_FILTERとAI_CLASSIFYは、従来であれば感情スコア化のモデル構築やルールベースのロジック実装が必要だった処理が、SQL1行に置き換わります。データエンジニアやアナリストが、MLエンジニアの手を借りずに自分で分析パイプラインに組み込める点は、チームの生産性にも影響が大きいと思います。
コスト意識は最初から持つべき
便利だからといって大量データに無計画にAI関数を流すと、コストが膨らむ可能性があります。事前の見積もりにはAI_COUNT_TOKENS関数が役立ちます。
今回の検証では、同じプロンプト・同じデータ(5行)でもモデルによって消費トークン数に大きな差がありました。
| MODEL | TOTAL_TOKENS |
|---|---|
| snowflake-arctic | 692 |
| llama4-maverick | 438 |
約1.6倍の差です。モデルごとにトークナイザが異なるため、同じ日本語テキストでも消費量が変わります。本番データに流す前にはAI_COUNT_TOKENSで見積もりを取り、実行後はCORTEX_AISQL_USAGE_HISTORYビューで実際のクレジット消費を確認する習慣をつけることをおすすめします。
6. まとめ
Cortex AI関数は、SQLユーザーにとってAI活用への最も手軽な入口です。SELECT、WHERE、GROUP BYといった馴染みのあるSQL構文の中でLLMを呼び出し、テキスト要約、分類、感情分析、データ抽出などを直接実行できます。新しいフレームワークを学ぶ必要はなく、GPUインフラの管理も不要です。
初めて試すなら、以下のステップがおすすめです。
- まずAI_COMPLETEから。テーブルを使わない単発クエリで動作確認ができます
- 次にAI_CLASSIFYとAI_FILTER。既存データに対する分類・フィルタリングの手軽さを体感できます
- 慣れてきたらAI_AGG。GROUP BYとの組み合わせで、従来のSQLでは不可能だった「AIによるグループ集約」という新しい分析パターンが見えてきます
今回の検証を通じて、Cortex AI関数は「AI専門家のためのツール」ではなく「SQLを書くすべての人のためのツール」だと感じました。まずは手元のデータで1クエリ試してみてください。