SnowflakeのLLM関数であるCortexを触ってみた！

この記事は [セゾンテクノロジー Advent Calendar 2024](https://qiita.com/advent-calendar/2024) 10日目の記事です。

# はじめに
SnowflakeのLLM関数である「Cortex関数」を触ってみた記事になります。

:::note warn
2024年12月時点の記事です。
使用可能なリージョンとモデルの確認をお願いします。
[大規模言語モデル (LLM) 関数 (Snowflake Cortex)](https://docs.snowflake.com/user-guide/snowflake-cortex/llm-functions#label-cortex-llm-count-tokens)
:::
## きっかけ
Databricksのハッカソンに参加した際、[Databricksが提供する「AI Function」](https://docs.databricks.com/en/large-language-models/ai-functions.html)を体験しました。SQLクエリから簡単にLLMに問い合わせが出来る事に感動し、業務で馴染みのあるSnowflakeの「Snowflake Cortex」も試してみたいと思ったので触ってみました！

# Snowflake Cortexとは
>Snowflake が開発したオープンなエンタープライズ グレードのモデルであるSnowflake Arcticを含む、Mistral、Reka、Meta、Google などの企業の研究者によってトレーニングされた業界をリードする大規模言語モデル (LLM) にすぐにアクセスできます。

SQLクエリの中でCortexを使えば特別なセットアップ無しにLLMへ問い合わせが出来るということです、わくわく。

# （ちょっと疑いつつ）やってみた
まず手始めにCOMPLETE関数を試してみました。Chat GPTみたいに使えるそうです。
日本の首都について聞いてみようと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/bacfd38c-dc5a-3888-1e58-fdb95216648a.png)

す、すごくない!?
Snowflakeのトライアルアカウントを作ってクエリを実行しただけだよ!?
結果は分かってはいたものの、こんなに簡単に使えるなんて！と感動しました。

# Cortexをいろいろ試してみる
2024年12月現在Snowflake Cortexには以下の関数が用意されています。
- COMPLETE関数
- タスク固有の機能（Task-specific functions）
    - CLASSIFY_TEXT
    - EXTRACT_ANSWER 
    - PARSE_DOCUMENT
    - SENTIMENT
    - SUMMARIZE
    - TRANSLATE
    - EMBED_TEXT_768
    - EMBED_TEXT_1024
- ヘルパー関数（Helper functions）
    - COUNT_TOKENS
    - TRY_COMPLETE

この中で気になった4つの関数を試してみました。

## 注意点
・リージョンは「AWS Asia Pacific (Tokyo)」を選択
・モデルは「llama3.1-8b」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/46c0c914-b2e2-4881-f79d-7f4b1535b74f.png)

:::note warn
※24/12/9時点の情報です。使用する場合は最新情報を確認して下さい。
[大規模言語モデル (LLM) 関数 (Snowflake Cortex)](https://docs.snowflake.com/user-guide/snowflake-cortex/llm-functions#label-cortex-llm-count-tokens)
:::

# 1.COMPLETE関数
プロンプトを投げると指定したモデルを使って回答を生成します。

https://docs.snowflake.com/sql-reference/functions/complete-snowflake-cortex

「赤色の食べ物で一番に思いつくものは何ですか？」と聞いてみます。（私はいちご）
```llama3.sql
SELECT SNOWFLAKE.CORTEX.COMPLETE('llama3.1-8b', '赤色の食べ物で一番に思いつくものは何ですか？') as response;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/a0099f2d-3b49-11df-cfc0-5ca7ec4c0d9a.png)
「トマトです。」と回答が返ってきました。

### モデルを変更してみる
モデルを「reka-flash」に変更し、先ほどと同じプロンプトを投げてみました。
「llama3.1-8b」に比べると詳細な回答が得られました。モデルによって結果は大きく変わることが分かります。（レモングラスの赤い部分は誰も思いつかないと思うけど:joy:）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/47c60e0c-4002-4a40-e0b2-8f899868ef88.png)

### パラメータも設定できる
引数でtemperatureやtopP、最大トークン数、有害な応答をフィルタリングするガードレール（guardrail）の設定も可能です。引数にオプションを設定すると、レスポンスの形がJSON形式に変わりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/a09e2c52-af5f-80c1-a1ed-51dedf464eac.png)

### ステートレス

「赤色の食べ物で一番に思いつくものは何ですか？」と聞いた後に「じゃあ2番目は？」というプロンプトを投げてみました。
過去の会話を覚えていれば、「何の」2番目を問われているかが分かるはずです。
（赤色の食べ物で二番目に思いつくもの）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/68a00bcd-b616-1c33-bbc0-42275159eac5.png)

分かってないようですね。逆に2番目は？と聞き返されました。ステートレスです。

:::note alert
COMPLETE関数は呼び出した結果を次の呼び出しまで保持しません！
:::

過去の会話内のユーザープロンプトとモデル応答を配列の一部として渡せば、ステートフルな会話を実現できるみたいです。
処理されるトークンの数は各「ラウンド」ごとに増加する為、コストも比例して増加することに注意が必要です。
[詳細はこちら](https://docs.snowflake.com/sql-reference/functions/complete-snowflake-cortex#usage-notes)


# 2.CLASSIFY_TEXT
自由形式で与えた文字列を指定したカテゴリに分類することが出来ます。

https://docs.snowflake.com/sql-reference/functions/classify_text-snowflake-cortex

「こたつでミカンが食べたいな～」というテキストを「夏」か「冬」に分類してみます。
```夏か冬か.sql
SELECT SNOWFLAKE.CORTEX.CLASSIFY_TEXT('こたつでミカンが食べたいな～', ['夏', '冬']);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/1073d349-cc45-a929-391e-a312c5061d17.png)

すごい！これも感動する。楽しくなったのでもう一発。
「忘年会がたのしみだな～」は「年末」か「年始」か。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/5fcd7661-0d39-4a59-388a-0487ec63296c.png)

忘年会は年末にやることを分かっているのね、すごい。

# 3.TRANSLATE
指定した言語に翻訳します。言語はコードで指定します。

https://docs.snowflake.com/sql-reference/functions/translate-snowflake-cortex

### サンプルデータの準備
お菓子に関するサンプルデータを用意しました。良ければお使いくださいませ。
```sample_sweets.sql
CREATE DATABASE raw;
USE DATABASE raw;

CREATE SCHEMA public;
USE SCHEMA public;

-- テーブルの作成
CREATE TABLE raw.public.sweets (
    "商品名" STRING,
    "価格" INTEGER,
    "重量" INTEGER,
    "商品説明" STRING
);

-- データの挿入
INSERT INTO raw.public.sweets VALUES
('サクサクポテト', 150, 60, 
 'サクサクした食感が楽しめます。一口ごとに美味しさが広がるポテトチップスです。'),
('コンソメスナック', 160, 70, 
 '濃厚なコンソメ味が特徴です。おやつにも、おつまみにもぴったりのポテトスナックです。'),
('のり塩チップス', 140, 65, 
 '風味豊かなのり塩味のポテトチップス。のりと塩のバランスが絶妙です。'),
('ミルクチョコバー', 120, 50, 
 '滑らかなミルクチョコレートバーです。食べるたびにミルクの甘さが広がります。'),
('ダークチョコミント', 130, 55, 
 '爽快なミントとダークチョコのハーモニー。一口で爽やかさが広がります。'),
('アーモンドクランチ', 170, 60, 
 'アーモンドの食感が楽しいチョコバー。アーモンドとチョコの絶妙なバランスです。'),
('フルーツミックスグミ', 100, 80, 
 '色々なフルーツ味が楽しめます。噛むたびに異なるフルーツの味が広がります。'),
('コーラ味グミ', 90, 75, 
 '甘酸っぱいコーラ味のジューシーグミ。コーラ好きにはたまらない一品です。'),
('ソーダグミ', 110, 85, 
 '爽やかなソーダ味のグミキャンディ。噛むたびにソーダの風味が口に広がります。'),
('グレープグミキャンディ', 105, 70, 
 'ジューシーなグレープ味のキャンディグミ。一粒で果汁感をたっぷりと味わえます。');

SELECT * FROM raw.public.sweets;

```

お菓子の商品説明を英語に翻訳してもらいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/c88862cf-f597-a86d-5d6f-d9904a1c3902.png)

```translate.sql
SELECT *, SNOWFLAKE.CORTEX.TRANSLATE("商品説明", 'ja', 'en') FROM raw.public.sweets;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/021de4cc-3df8-7779-db0e-ffaa12c23f75.png)

試しに生成結果をdeeplで翻訳してみましたがいい感じですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/7c9391af-142e-71d7-d854-283d2605f1a9.png)


# 4.COUNT_TOKENS
お助け関数の1つです。引数で与えるプロンプトのトークン数を教えてもらえます。

https://docs.snowflake.com/sql-reference/functions/count_tokens-snowflake-cortex

```.sql
SELECT SNOWFLAKE.CORTEX.COUNT_TOKENS( 'llama3.1-8b', '三重県の良いところを教えて下さい' );
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/d4ae1736-8758-44b2-5626-29655144dd7a.png)

モデルが変わるとトークン数も変わる。(知らなかった）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/a7c4b393-2e83-caaf-804e-3b725aa9b14f.png)

引数のfunction_nameにタスク固有の関数名前を指定することも出来ます。
「translate」を指定すると翻訳して欲しいプロンプトのトークン数が返ってきます。

:::note warn
function_nameに指定する関数名は小文字であることに注意
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/4ce123a3-cde1-05e4-43ee-db0c0d861165.png)

# 終わりに
はじめて「Cortex関数」を触ってみましたが、SQLクエリからとっても簡単にLLMに問い合わせることが出来ました。こうしたAIの機能はオレゴンリージョン等、海外のリージョンでしか使えないイメージがあったので、東京リージョンで使えるようになっていることに驚きました。
今回は簡単なプロンプトや10件程度のごく少量データを使ったので回答時間は気にならなかったですが、データ量が増えると回答時間がネックになってきそうです。
今回はDatabricksのハッカソンがきっかけでしたが、きっかけは何でも良く、あるサービスに機能が追加されるなど新しい発表がある時には、じゃあ他のサービスではどうなのか？を調べたいなと思いました。各サービスの似たところや違いから、各ベンダーの思想や、サービス全体の流行を掴めるようになりたいと感じました。
お付き合いいただきありがとうございました。