NTT DATA TECH
❄️

Snowflake Cortex Agents、ここまで分かった!次はどこまで挑める?

に公開

はじめに

最近、Techイベントやブログで「AIエージェント」という言葉を耳にする機会が増えています。
Snowflakeもこの流れに乗り、Cortex Agents(現在プレビュー機能) をリリースしています。
今回は、このCortex Agentsが現時点でどこまで賢く動けるのか、いくつかの質問シナリオを通じて検証してみたいと思います。

※本記事の内容は2025年8月4日時点のプレビュー版に基づく検証結果です。

注記
Cortex Agentsは現在プレビュー機能として提供されています。
プレビュー機能はSnowflakeに実装およびテストされていますが、完全なユーザビリティや特殊ケースへの対応は完了していない可能性があります。そのため、今後のバージョンで動作や仕様が変更される場合があります。

1.Cortex Agentsとは

Cortex Agentsは、Snowflakeが提供するAIエージェント機能で、構造化データ(テーブル)と非構造化データ(ドキュメントやチャットログなど)を横断的に扱えるのが特長です。
大規模言語モデル(LLM)を活用し、ユーザーの質問を理解して最適なツールを選択・実行し、回答を導きます。

まずは、Snowflake公式ブログに掲載されている図を見ながら、その全体像を整理してみましょう。

👉 公式ブログはこちら:エンタープライズデータに必要なのはエージェント

この図から読み取れるCortex Agentsの基本的なワークフローは、次のとおりです。

  1. 呼び出し:アプリケーションからREST API経由でCortex Agentsを呼び出す
  2. 計画:質問内容を理解し、「構造化か/非構造化か」を判断。必要に応じてタスクを分割
  3. ツール選択と実行:計画に基づき以下のツールを使い分け処理を実行
    • Cortex Analyst:SQLを自動生成し構造化データをクエリ
    • Cortex Search:PDFやチャットログなどの非構造データをベクトル検索
  4. 反映:得られた結果を評価し、必要であれば追質問や要約を行い最終回答を生成

このように、単なる「ツール呼び出し」ではなく、質問に応じて複数のステップを踏みながら動作するのが、Cortex Agentsの大きな特長です。

今回の記事では、このCortex Agentsがどこまで複雑な問い合わせに対応できるのか、実際のシナリオを通して検証していきます。

2.環境準備

今回の検証のために、以下4つのテーブルを準備しました。

テーブル名 主なカラム例 用途(どのツールで使用するか) データタイプ
product_orders order_id, product_id,user_id,price, order_date Cortex Analyst:売上集計など 構造化データ
customer_profiles age, region, gender Cortex Analyst:属性条件に使用 構造化データ
support_chat_logs user_id,message, timestamp Cortex Search:顧客とのやり取り履歴 非構造化データ
faq_articles question, answer Cortex Search:ナレッジ検索 非構造化データ

問い合わせインターフェースはStreamlitを使い、Cortex Agentsと連携する構成です。
Streamlit内でCortex Agentsに渡すRequest Bodyは以下のとおりです。

payload = {
    "model": "claude-4-sonnet",
    "response_instruction": "",
    "messages": [
        {
            "role": "user",
            "content": [
                {"type": "text", "text": query}
            ]
        }
    ],
    "tools": [
        {"tool_spec": {"type": "cortex_analyst_text_to_sql", "name": "analyst1"}},
        {"tool_spec": {"type": "cortex_analyst_text_to_sql", "name": "analyst2"}},
        {"tool_spec": {"type": "cortex_search", "name": "search_chat"}},
        {"tool_spec": {"type": "cortex_search", "name": "search_faq"}}
    ],
    "tool_resources": {
        "analyst1": {"semantic_model_file": CUSTOMER_PROFILES_SEMANTIC_MODELS},
        "analyst2": {"semantic_model_file": PRODUCT_ORDERS_SEMANTIC_MODELS},
        "search_chat": {
            "name": CHAT_SEARCH_SERVICE,
            "max_results": limit,
            "id_column": "conversation_id"
        },
        "search_faq": {
            "name": FAQ_SEARCH_SERVICE,
            "max_results": limit,
            "id_column": "faq_id"
        }
    },
    "tool_choice": {"type": "auto"}
}

 

3.検証シナリオ

Cortex Agentsの出力精度やツール選択の挙動を確認するため、以下3つのシナリオを用意しました。

難易度 実行するクエリ 期待されるツール選択 評価ポイント
Lv.1 単一ツール - 基礎 ①「user_0の性別を教えて」
②「返品手続きの方法を教えて」
1️⃣ Cortex Analyst(customer_profiles)
2️⃣ Cortex Search(faq_articles)
ツール選択の正確性、生成SQLや検索結果の精度
Lv.2 テーブルまたぎ(構造/非構造) ①「user_0の性別と購入商品を教えて」
②「パスワードを忘れた場合はどうすればいいですか?」
1️⃣ Cortex Analyst(product_orders, customer_profiles)
2️⃣ Cortex Search(search_chat, faq_articles)
複数テーブルを統合した出力の可否
Lv.3 複合ツール(構造+非構造) 「product_0 を購入したユーザーと、そのユーザーの問い合わせ内容を一覧にしてください」 1️⃣ Cortex Analyst(product_orders)でproduct_0の購入ユーザを特定
2️⃣ Cortex Search(support_chat_logs)で購入ユーザの問い合わせを検索
3️⃣ LLMで要約
構造データ検索→非構造データ検索→要約の一連処理

それでは検証に入っていきましょう!

検証_Lv.1 単一ツール

💬 クエリ

  • ①「user_0の性別を教えて」
  • ②「返品手続きの方法を教えて」

✅ 結果

  • Cortex Analyst が選択され、user_0の性別を回答できています。

以下はレスポンスの一部で、定義したcortex_analyst_text_to_sql(analyst1)のToolが呼び出されていることが分かります。

{
  "event": "message.delta",
  "data": {
    "delta": {
      "content": [
        {
          "type": "tool_use",
          "tool_use": {
            "name": "analyst1",
            "type": "cortex_analyst_text_to_sql",
            "input": {
              "query": "user_0の性別を教えて"
              // 以下省略
            }
          }
        },

    // 以下省略(cortex_analyst_text_to_sql の結果(生成SQL・解釈内容など))
}    
  • ② Cortex Search を選択し、返品に関する FAQ が回答に引用されました。

以下はレスポンスの一部で、定義したsearch_chatなどのCortex SearchのToolが呼び出されていることが分かります。

{
  "event": "message.delta",
  "data": {
    "delta": {
      "content": [
        {
          "type": "tool_use",
          "tool_use": {
            "name": "cortex_search",
            "type": "cortex_search",
            "input": {
              "query": "返品手続きの方法を教えて",
              "indexName": "search_chat"
              // 以下省略
            }
          }
        },
        {
          "type": "tool_use",
          "tool_use": {
            "name": "cortex_search",
            "type": "cortex_search",
            "input": {
              "query": "返品手続きの方法を教えて",
              "indexName": "search_faq"
              // 以下省略
            }
          }
        },
        {
          "type": "tool_use",
          "tool_use": {
            "name": "cortex_search",
            "type": "cortex_search",
            "input": {
              "query": "返品手続きの方法を教えて",
              "indexName": "product_feedback"
              // 以下省略
            }
          }
        },
        {
          "type": "tool_results",
          "tool_results": {
      ・・・省略
          }
        }
      ]
    }
  }
}


🧐 考察

  • 質問内容に応じて構造化データ/非構造化データに最適なツールが選択されており、基本的なツール選択精度は高いと言えます。
  • 特に非構造データの検索では、返品に関する質問に対して以下の3つの検索ツールを順に実行し、結果を統合して回答を生成していると考えられます。
    • search_chat(チャットログ)
    • search_faq(FAQ)
    • product_feedback(レビュー・声)

検証_Lv.2 ツールはテーブルを跨げるか(構造-構造,非構造-非構造)

💬 クエリ例(構造化データのテーブルを跨いだ質問)

  • 「user0の性別と購入商品を教えて」
    ※ user_0 の性別は customer_profiles、購入商品は product_orders に格納されている

✅ 結果
回答できない。

実際のレスポンスを確認すると、構造化データへの問い合わせであるにもかかわらず、Cortex Analystではなくcortex_search が選択されていました。

{
  "status": 200,
  "content": [
    {
      "event": "message.delta",
      "data": {
        "id": "msg_001",
        "object": "message.delta",
        "delta": {
          "content": [
            {
              "index": 0,
              "type": "tool_use",
              "tool_use": {
                "tool_use_id": "tooluse_c264753fbbc847b0a79bee",
                "name": "cortex_search",
                "type": "cortex_search",
                "input": {
                  "columns": ["conversation_id"],
           ・・・・



対応1:指示プロンプトを変更

"response_instruction": """
ユーザー属性に関する質問は必ずanalyst1を使用し、
購入履歴に関する質問は必ずanalyst2を使用してください。
FAQ/チャット検索ではなく、まずSQLを用いた構造化データの取得を行い、
その結果をまとめて返答してください。
また、回答する際は、語尾に!をつけてください
"""

回答文の語尾に「!」が付いていたため、プロンプト自体は反映されていることが分かりました。しかし、テーブルを跨いだ検索そのものは依然として難しい結果となりました。


対応2:セマンティックモデルを1つに統合
これまではテーブルごとにセマンティックモデルを分割し、別々のツールとして渡していました。

  • product_orders用のセマンティックモデル
  • customer_profiles用のセマンティックモデル

これらを統合し、1つのsemantic_model.ymlとしてCortex Agentsに渡すよう変更しました。


name: "product_orders_and_profile"

tables:
  # ── CUSTOMER_PROFILES ──
  - name: CUSTOMER_PROFILES
    base_table:
      database: CORTEXAGENT
      schema: CUSTOMERSUPPORT
      table: CUSTOMER_PROFILES
    dimensions:
   ・・・省略


  # ── PRODUCT_ORDERS ──
  - name: PRODUCT_ORDERS
    base_table:
      database: CORTEXAGENT
      schema: CUSTOMERSUPPORT
      table: PRODUCT_ORDERS
    dimensions:
      - name: ORDER_ID
        expr: ORDER_ID
        data_type: TEXT
        is_primary_key: true
   ・・・省略

relationships:
  - name: user_to_orders
    left_table: CUSTOMER_PROFILES
    right_table: PRODUCT_ORDERS
    join_type: inner
    relationship_type: one_to_many
    relationship_columns:
      - left_column: USER_ID
        right_column: USER_ID

結果、テーブルを跨いだ問い合わせに対応可能となりました!


💬 クエリ例(非構造化データのテーブルを跨いだ質問)
「パスワードを忘れた場合はどうすればいいですか?」

関連レコードは以下2テーブルに分散しています

  • search_chat(チャットログ)

    ('conv_6', 'user_1', 'agent_0', CURRENT_TIMESTAMP,
    'Q: アプリにログインできず、パスワードをリセットしても確認メールが届きません。どうすればいいですか?
    A: 迷惑メールフォルダをご確認ください。届いていない場合は再送リクエストを行ってください。'),

  • search_faq(FAQ)

    ('faq_4', 'アカウント',
    'パスワードを忘れた場合はどうすればいいですか?',
    'ログイン画面の「パスワードをお忘れですか?」リンクから登録メールアドレスを入力し、届いたメールの案内に従って再設定してください。'),

✅ 結果
2つのテーブルから関連情報を抽出し、正しく回答できました。

🧐 考察

  • 構造化/非構造データを跨いだ検索は可能。
  • ただし、テーブルごとにセマンティックモデルを分割すると、テーブル跨ぎの質問に対応できない場合がある。

検証_Lv.3 複合ツール(構造+非構造)

💬 クエリ例
「product_0 を購入したユーザーと、そのユーザーの問い合わせ内容を一覧してください」

この質問に答えるためには、構造化データ(購入履歴)と非構造化データ(問い合わせ内容)の両方を扱う必要があります。

  • product_orders

    ('order_0', 'user_0', 'product_0', 2, 45.20, '2025-07-03'),
    ('order_1', 'user_1', 'product_1', 1, 23.99, '2025-06-27'),
    ('order_2', 'user_2', 'product_2', 3, 88.50, '2025-07-01'),
    ('order_3', 'user_3', 'product_0', 1, 32.00, '2025-07-02'),
    ('order_4', 'user_4', 'product_1', 2, 60.00, '2025-06-30'),
    ('order_5', 'user_0', 'product_2', 1, 99.99, '2025-06-18'),
    ('order_6', 'user_1', 'product_0', 3, 75.40, '2025-06-22'),
    ('order_7', 'user_2', 'product_1', 1, 15.80, '2025-07-04'),
    ('order_8', 'user_3', 'product_2', 2, 66.66, '2025-07-05'),
    ('order_9', 'user_4', 'product_0', 1, 54.32, '2025-07-06');

  • search_chat(チャットログ)

    ('conv_4', 'user_4', 'agent_1', CURRENT_TIMESTAMP,
    'Q: user_4からの質問。まだ発送前であれば注文をキャンセルしたいのですが、間に合いますか?
    A: 発送準備前であればキャンセル可能です。詳細はマイページからお手続きください。'),

期待する出力

product_0を購入したユーザは、user0,1,3,4です。
user4から「まだ発送前であれば注文をキャンセルしたいのですが、間に合いますか」という質問が来ています

✅ 結果
回答は得られませんでした。
Cortex AgentsがCortex Analystを使用せず、Cortex Searchだけを選択していることが確認できます。

{
  "type": "tool_use",
  "tool_use": {
    "name": "cortex_search",
    "type": "cortex_search",
    "input": {
      "columns": ["conversation_id"],
      "indexName": "search_chat"
    }
  }
}


対応1:入力プロンプトを変更
質問を分割して明示的に流れを指示しました。

  • 入力プロンプト1:

product_0 を購入したユーザを教えて。その後に、そのユーザーの問い合わせ内容を一覧してください

  • 入力プロンプト2:

まずAnalystを使ってproduct_0購入ユーザーを取得し、次にSearch を使って問い合わせ内容を調べてください

  • 入力プロンプト3:
    明示的に、使用するツールを指定する

まずanalyst1ツールを使用してproduct_0を購入したユーザーを取得し、
次にsearch_chatツールを使用してそのユーザーの問い合わせ内容を調べてください。

✅ 結果

  • 「Analyst ツールや Search ツールにアクセスできない」という趣旨の回答となり、期待する結果は得られませんでした。
  • ログを見ると依然として Cortex Searchのみが選択されており、構造→非構造という多段階処理が実行されていません。

対応2:Request bodyのパラメータを変更してみる

Cortex Agentsに渡すRequest Bodyでは、モデルやツール選択に関わるパラメータtool_choiceを設定できます。これは "auto"(デフォルトで自動選択)、"required"(必ずいずれかのツールを利用)、"tool"(特定ツールを指定)の3種類があります。

今回はデフォルトの "auto" から "required" に変更し、必ずツールが利用されるようにした上で、対応1のプロンプトを再実行しました。

✅ 結果
期待する結果は得られず、ツール選択の挙動には変化がありませんでした。
参考: Cortex Agents REST API


対応3:Agentに渡す指示プロンプトを変更して試してみる

    payload = {
        "response_instruction": """
      次のルールに従って必ず回答してください:
        1. 購入履歴やユーザー属性に関する質問では、必ず Analyst ツール(analyst1)を最初に使用してSQLクエリを生成し、構造データを取得してください。
        2. 次に、そのユーザーIDや購入履歴に紐づく問い合わせ内容・レビュー・チャットなどの非構造データを調べる場合は、Search ツール(search_chat, search_faq, product_feedback)を使用して取得してください。
        3. 必ず **Analyst → Search → 結果統合** の順序で処理してください。
        4. 回答は、取得したデータに基づいて統合的にまとめ、最後に必ず「!」をつけて終了してください。
        ### 例:
        質問: 「product_0 を購入したユーザーと、そのユーザーの問い合わせ内容を教えて」
        処理: 
          - Step1: analyst1 で product_0 の購入ユーザーを取得
          - Step2: search_chat と search_faq でユーザーの問い合わせ内容を検索
          - Step3: 両者を組み合わせて結果を要約
        回答: 「product_0 購入者は user_4 です。そのユーザーの問い合わせ内容は〜です!」

        """

✅ 結果
しかし、期待する回答は得られませんでした。
回答文の語尾に「!」が付いていたことから、プロンプト自体は正しく読み込まれていましたが、Cortex Agents は Cortex Analystを使用せず、Cortex Searchのみを選択していたことがログから確認できました。
つまり、プロンプトで処理の流れを具体的に指示しても、構造データと非構造データを跨いだ検索を1回の質問で処理するのは難しいことが分かりました。


🧐 考察

  • Cortex Analystと Cortex Searchの両方を組み合わせるような処理を、Agent が自動的に行うことは現時点では難しいと考えられます。
  • ただし、実際の利用シナリオでは以下のように 複数のチャットに分けて質問する ケースも多いため、必ずしも 1 回の質問で統合的な回答を得る能力が必須とは言えないでしょう。
    • ユーザ:product_0の購入者を教えて
    • Cortex Agents:user_0が購入者です
    • ユーザ:user_0の問い合わせ内容を教えて

まとめ

今回の検証では、Cortex Agentsが持つ「構造化データ×非構造化データ」を横断的に扱う能力を試しました。

  • Lv.1 の基礎的な質問では、構造化データに対するSQL生成やFAQ検索を適切に選択し、意図を理解した回答を返せることを確認できました。
  • Lv.2では、セマンティックモデルを統合することで、テーブルを跨いだ質問にも対応できることが分かりました。
  • Lv.3のような構造・非構造を跨いだ複合質問は、現時点(プレビュー版)では1ターンでの処理が難しい結果となりましたが、Cortex Agentsには複数ステップ実行やツール連携の仕組みが備わっており、今後の進化に大いに期待できると感じています。

一方で、今回の検証を通じて実感したのは、「いくらagentとはいえ、データの構造や関係性を理解していなければ、適切な計画やツール選択は難しい」という点です。実際、構造化データをまたいだ質問に対応させるには、セマンティックモデルの整備やリレーションの定義が不可欠でした。

特にCortex Agentsは、現状こちらから明示的に制御できるパラメータが限られており、「賢さ」を引き出すには事前にどれだけデータを整備・設計できるかがカギとなると考えます

総じて、Cortex Agentsは実用的に動作しており、今後のアップデートによってより柔軟で高度なエージェント挙動が可能になることを期待しています。

NTT DATA TECH
NTT DATA TECH
設定によりコメント欄が無効化されています