LLM時代のアナリティクス実務:データ整形とプロンプト設計の最適化術

データや思考のつながりを示す線が描かれた人の頭のシルエット 皆さんこんにちは。SMEアナリティクス部でデータ分析を行っているみみずくです。

ChatGPTやGeminiなどのLLM(大規模言語モデル)は、アナリティクス領域でも着実に存在感を増しています。 特に「自然言語の指示でSQLクエリを出力する」「分析レポートを要約する」といった用途では、すでに実用の域に入っていると言ってよいでしょう。 ただし、その使いこなしにはコツがあります。例えば、LLMを実業務で使えるようにするには、プロンプト(入力)とデータ整形(前処理)の工夫が8割と言われるほど、事前の準備が大切です。

本記事では、SMEでのアナリティクス業務で得られた知見をもとに、データを扱う現場で使えるLLM導入のノウハウを紹介します。

まず「何をLLMに任せるか」を決める

LLMを使うとき、最初の失敗パターンは「全部やらせようとすること」です。

昨今のLLMアプリは多様なタスクに対応し、あたかも万能であるかのような印象を与えます。 しかし、どれほど高性能でも、漠然とした指示ではユーザーの意図を正確に汲み取ることはできません。 全体の道筋や目的を設計するのは人間の役割であり、その上で個々のタスクをLLMに委ねていくことが、効果的な活用の鍵となります。

現実的には、以下のようにタスクを分割して設計すると安定します。

タスク LLMに任せる部分 ルールベースで処理すべき部分
SQL生成 集計意図・対象テーブルの特定 カラム選択・JOIN条件
レポート文生成 トーン・文体の調整 数値の検証・閾値判断
インサイト抽出 概要の要約 指標の定義

LLMは「意図の翻訳」には強いですが、「一貫性と精度」には弱い傾向にあります。

したがって、(ルールベースの)コードで処理する領域をあらかじめ決めた上で、LLMにタスクを渡すことが重要です。

データをLLMが理解できる言葉に整える

LLMに分析データを扱わせるときによくある失敗は「モデルがカラムの中身を誤解する」ことです。 特にデータウェアハウスでは、

  • media_playback_logs
  • content_id
  • region_code

のような略称+英語+アンダースコア構造が多く、モデルが中身を誤解する原因となっています。

解決策:スキーマ辞書を自然言語で生成する

SnowflakeのINFORMATION_SCHEMA.COLUMNSやAWS Glue Catalogから自動でデータカタログを抽出し、自然言語で以下のような「テーブル定義ドキュメント」を作ります。

{
  "table": "media_playback_logs",
  "columns": {
    "content_id": "コンテンツを一意に識別するID。",
    "play_count": "再生回数。単位は回。",
    "region_code": "地域コード。例: JP, US。",
    "recorded_at": "記録日時。YYYY-MM-DD形式。"
  },
  "metrics": {
    "daily_views": "日次の総再生数。",
    "week_over_week_growth": "前週比成長率。"
  }
}

このドキュメントをLLMプロンプトに渡すだけで、「region_codeって何?」などという曖昧さがほぼ解消されます。

必要であれば、型(string型?int型?date型?)も与えてやると、LLMが計算式を立てる際に迷わずに済むでしょう。


LLMプロンプト設計の基本:抽象+制約のハイブリッド

LLMは抽象的な指示には強いですが、曖昧なまま実行すると想定と異なる結果を出力することがあります。 特にSQL生成やレポート生成では、「構造を固定しつつ、内容を柔軟に」するのがコツです。

例:SQL自動生成用プロンプト

You are an experienced data analyst.
Given the database schema and the user’s question, generate a valid SQL query for analytics.

Rules:
- Always include an aggregation by "recorded_at" (daily granularity)
- Limit the output to 10 rows
- Use only the columns defined in the provided schema
- Do not invent table or column names
- Prefer descriptive aliases for readability

Schema:
{schema_json}

User Question:
{user_question}

ここで重要なのは、禁止事項を明示することです。 「推測するな」「スキーマ外を使うな」だけでもエラー率は大幅に減少します。

出力されたデータから要約文を生成させる場合にも同様のことが言えます。

例:要約生成プロンプト

Summarize the following KPI changes in plain Japanese.
Be concise, factual, and avoid speculation.

Data:
| Metric | Value | Change vs Last Week |
|--------|--------|--------------------|
| Page Views | 1,250,000 | +8% |
| Active Users | 180,000 | +2% |

Expected Output:
- 今週のページビュー数は先週比で8%増加。
- アクティブユーザー数はわずかに増加(+2%)。

出力を信じすぎない:LLM評価・検証パターン

LLMを分析フローに入れる際に必須なのが、「自動検証レイヤー」です。

例えばSQL生成後、実行前に以下のようにチェックを入れることで事故を防げます。

import sqlparse

def validate_sql(query: str, allowed_tables: list[str]) -> bool:
    parsed = sqlparse.parse(query)[0]
    tokens = [t.value.lower() for t in parsed.tokens if not t.is_whitespace]
    for t in tokens:
        if t.startswith("drop") or t.startswith("delete"):
            return False
        if "join" in t and "on" not in query.lower():
            return False
    for table in allowed_tables:
        if table.lower() in query.lower():
            return True
    return False

上のスクリプトは、sqlparseライブラリを使ってLLM生成SQLの安全性を確認する簡易バリデータです。

この関数では、SQLを実際に実行する前に次の3点をチェックしています。

  1. 危険操作の防止

    DROPDELETE といったデータ破壊系コマンドを検出した場合、即座にブロックします。

    LLMが誤って本番DBを操作しないための最低限の安全策です。

  2. JOIN構文の妥当性確認

    JOINが含まれているのにON句が存在しない場合は不正と判断します。

    自然言語→SQL変換で頻出する単純なミスを防げます。

  3. 許可テーブルのホワイトリスト確認

    許可リストに含まれたテーブル名しかクエリで使えないよう制限します。

    これにより、LLMが推測で別スキーマのテーブルを呼び出すリスクを回避します。

LLMが生成したクエリをそのまま実行せず、構文やフォーマットの検証工程を挟むという設計姿勢が肝要です。

また、レポート生成では事前に期待フォーマットを与えておく(例:JSON出力)ことで、後続処理の安全性を担保できます。


エラーログの検証:もはや“ググる”時代は終わった

LLMが生成したSQLクエリやコードを実運用に組み込むと、必ずと言っていいほどエラーが発生します。 それはどんなにプロンプトを洗練させても、実データや環境依存の要素までは想定しきれないからです。

従来であれば、開発者はこれらのエラーメッセージをコピーして検索し、Stack OverflowやQiitaで原因を探していました。 しかしLLMが日々コードを書き、クエリを生成する時代においては、「エラーを解析し、修正版を提案する」のも同じLLMに任せるのが自然な流れです。 吐き出されたエラーログをそのままLLMに再投入することで、人間が手動でコードを修正しなくとも、修正版のSQLやスクリプトを自動生成できます。

さらに、同一のコンテクスト(対話履歴)を維持したセッション内でこれを繰り返すことで、モデルは過去の入出力を参照しながらより精密な修正を行えるようになります。 学習しているのはモデル本体ではなく、会話の中で構築される一時的な作業記憶です。 つまり、エラーと修正の履歴が「対話の文脈」として積み上がっていくことで、LLMが「現場に適応していく」ように振る舞うのです。


プロンプトを「属人化」させない仕組み

現場では、担当者ごとにプロンプトがバラバラになりがちです。

そこで有効なのが「プロンプト辞書」または「プロンプトテンプレート管理」です。

  • Gitで管理(YAMLやJSON形式)
  • 各プロンプトにメタデータを付与
name: weekly_digest
purpose: Generate a concise weekly KPI summary for a team chat or report
input_type: table_json
output_type: markdown
model: <preferred_llm_model>   # 例: "general-purpose-llm"
version: 1
controls:
  max_tokens: 800
  temperature: 0.2
  style: "neutral, factual, concise"
routing:
  trigger: "scheduled"         # "scheduled" | "manual" | "event"
  schedule_cron: "0 9 * * MON" # 毎週月曜 09:00(任意)
  notify_channels:
    - "team-analytics"         # 社内チャットのチャンネル名など
audit:
  log_level: "info"
  redact_pii: true

これにより、プロンプトの品質を均一化でき、属人化した状態から脱却できます。プロンプト設計も、チームで管理する資産となり得るのです。


まとめ

実務でLLMを扱うと、「SQLを書けるAI」ではなく「文脈を理解させるAI」という発想が重要だと感じます。

つまり、AIが理解できる文脈をどう整形するかが分析DXの本質です。

  • カラム名・指標の意味を自然言語化する
  • 禁止事項・期待フォーマットを明示する
  • 出力を自動検証する仕組みを持つ
  • プロンプトをチーム資産として管理する

これらを地道に整えるだけで、生成AIは単なるおもちゃから業務レベルの共働者になります。

LLMは賢い分析者そのものではなく、文脈を媒介するインターフェース。それをどう設計するかこそが、これからのアナリティクス組織の差になるでしょう。