Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

LLMによるKPI分析検証

こんにちは。id:skozawa です。

この記事は Gunosy Tech Blog Festa の 10 日目の記事です。

今回はLLMを使ってデータ分析業務を効率化する検証について紹介します。

背景

Gunosyでは日々、KPIを見て事業状況の確認や異常検知などを行なっています。 BIツールとしてQuickSuiteやRedashを利用してKPIの確認や深掘りなどをしていますが、 QuickSuiteには100以上のグラフがあり、これらを人の目で日々確認するのは大変です。 また、異常が見られた場合には要因を調査するため、様々な軸で数値変化を確認し要因を絞っていくことになり、非常に手間がかかる作業になります。 そこでこれらの分析業務をLLMを活用して楽にできないか検証することにしました。

LLMによるデータ分析

対象範囲

データ分析業務を大まかに分解すると、「目的・仮説設定」、「データ取得」、「データ分析」、「分析レポート生成」という4つの工程になります。

今回は「目的・仮説設定」はKPIの傾向分析・異常検知、「データ取得」は予め取得できているものとし、「データ分析」、および、「分析レポート生成」をLLMを活用して効率化する対象とします。 なお、「データ取得」についてはSQLクエリの自動生成を検証中ですので、以下の記事もご覧ください。

tech.gunosy.io

データの概要

業務では売上、DAU、ユーザーのアクティビティなど、様々な指標をみますが、 実際のデータを使った分析は公開できないため、今回はLLMにサンプルデータを作成してもらって例を示したいと思います。

以下はLLMに生成してもらった日次のユーザーごとの記事のインプレッションに関するデータの抜粋です。

日付 ユーザーID os osバージョン 性別 年代 初回起動日 記事impression
2025-12-22 10294 iOS 7.2 女性 20代 2023-05-12 42
2025-12-22 49201 Android 14.0 男性 40代 2025-11-30 15
2025-12-22 33108 iOS 16.6 男性 30代 2024-01-15 28

LLMによるKPI分析

KPI分析フロー

KPIの傾向分析や異常検知には長期間のデータが必要になります。 全てのデータをLLMに渡して分析してもらえるとよいのですが、LLMには入力トークン数の制約があるため、全てのrawデータを入力するとトークン数オーバーでエラーになってしまいます。 理想的には分析軸もLLMに任せて分析してもらえると良いのですが入力長の限界があるため、 今回は分析する軸については予め人手で決めて、分析軸ごとにデータを集約してからLLMに入力し、 軸ごとに分析を行い、最後に各軸の分析結果をまとめて最終のレポートを生成する形にします。

軸ごとのKPI分析

データを分析軸ごとに集約して生成AIにインプットして分析結果を生成します。 今回はLLMモデルにはGemini 3.5 Flashを利用しました。

以下はOS別にKPIを分析するためのコードになります。

from google import genai
from google.genai import types
import pathlib

prompt = """
あなたは分析のプロフェッショナルなデータアナリストです。
日次集計データ(OS別)をもとに、ユーザー行動の変化・異常を分析してください。

【出力フォーマット要件】
- レポート全体をMarkdown形式で出力してください。
- 見出し、表、箇条書きを活用し、要点・根拠・推奨アクションを分かりやすくまとめてください。

【分析時の注意点】
- 季節性の変化か、問題がありそうな変化かを見抜く。
- 変化があった場合、その要因や背景についても仮説を立てて考察
"""

client = genai.Client(api_key=GEMINI_API_KEY)
csv_path = "os.csv"

os_df = df[["date", "os", "impressions"]].groupby(["date", "os"]).mean()
os_df.to_csv(csv_path, index=False, float_format="%2.2f")
filepath = pathlib.Path(csv_path)

res = _client.models.generate_content(
    model="gemini-3-flash-preview",
    contents=[
        types.Part.from_bytes(
            data=filepath.read_bytes(),
            mime_type='text/csv',
        ),
        prompt,
    ],
)

以下のようなレポートを生成してくれます。 これを各分析軸ごとに生成します。

ご提示いただいた365日分(1年分と想定)のインプレッションデータに基づき、データアナリストとして分析レポートを作成しました。

---

# インプレッションデータ分析レポート

## 1. エグゼクティブ・サマリー
本期間におけるインプレッション数は、全体として極めて安定した推移を見せています。
大きな破綻(極端な低迷)は見られませんが、期間中に数回、統計的閾値を超える**ポジティブな異常値(スパイク)**が確認されました。
これらは季節性よりも、特定の外部要因(OSアップデート、特定キャンペーン、あるいはアルゴリズム改修)の影響を強く示唆しています。

---

## 2. 基本統計量と全体傾向
1年間のデータを集計した基本統計は以下の通りです。
...

統合レポート生成

分析軸ごとに生成したレポートを1つのレポートにまとめます。 各レポートをプロンプトに含めて、1つのレポートを生成します。

prompt = """
あなたは分析のプロフェッショナルなデータアナリストです。
複数の分析レポートを1つのレポートにまとめてください。

【出力フォーマット要件】
- レポート全体をMarkdown形式で出力してください。
- 見出し、表、箇条書きを活用し、要点・根拠・推奨アクションを分かりやすくまとめてください。

【出力要件】
- 重要な変化や異常があれば、箇条書きや表で明確に指摘
- このレポートで全てが完結するようにまとめてください
"""

for report in [
    {"title": "OS別レポート", "report": os_report},
    {"title": "OSバージョン別レポート", "report": os_version_report},
    {"title": "デモグラ別レポート", "report": demographic_report},
    {"title": "新規ユーザーレポート", "report": new_user_report}
]:
    prompt += f"""
【{report['title']}】
{report['report']}

"""

res = client.models.generate_content(
    model="gemini-3-flash-preview",
    contents=[prompt],
)

分析結果の精度について

定量的な検証はできていないため、定性的な所感になりますが、

  • 数値変化の検知はある程度できる
    • たまに誤検知や検知漏れなどもありますが、ある程度はできている
    • 複数の指標を渡してもプロンプトで指示すれば検知してもらえる
  • 数値変化の要因特定は現状ではできない
    • 当たり前ですがドメイン知識などを十分に渡しているわけではないため、数値変化の検知はできますが、その要因の特定まではできていません

と言った印象です。また、他の様々なタスクと同様に人によるレビューはまだ必須かなと思います。

分析結果の出力

LLMが出力したMarkdownをそのままSlackなどに通知しても良いですが、ドキュメントとして残しておきたいので、今回はGoogle Docsに保存することにします。 MarkdownをGoogle docs形式にするにはPandocなども使えますが、 今回はpythonでやりたかったため、markgdocというライブラリを使ってみます。 ただし、markgdocはドキュメントを作成する場所を指定できないため、markgdoc.py だけダウンロード(forked_markgdoc.pyとしてコピー)して使うことにしました。

from googleapiclient.discovery import build
from google.oauth2 import service_account
import forked_markgdoc as markgdoc

drive_service = build(
    "drive", "v3",
    credentials=service_account.Credentials.from_service_account_file(
        "credentials.json", scopes=["https://www.googleapis.com/auth/drive"],
    )
)
docs_service = build(
    "docs", "v1",
    credentials=service_account.Credentials.from_service_account_file(
        "credentials.json", scopes=["https://www.googleapis.com/auth/documents"],
    )
)

doc = drive_service.files().create(body={
    "name": "KPIレポート",
    "mimeType": "application/vnd.google-apps.document",
    "parents": [PARENT_ID],  # 出力するフォルダを指定
}, supportsAllDrives=True).execute()

markgdoc.process_markdown_content(docs_service, doc["id"], summary_report)

以下のようなGoogle Docsを作成してくれます。

まとめ

LLMでKPI分析業務を効率化できるか検証をしました。 要因特定までは至っていませんが、数値変化の検知はある程度できているため、 LLMのレポートを起点に分析を開始することで効率化できそうな兆しは見えました。

異常検知だけであれば、LLMを使わなくても一般的な異常検知の手法を使えば事足りるものではありますが、 プロンプトを変えるだけで非エンジニアでも分析が可能になるのは大きな変化だと思います。 現状は数値変化のみのため、今後はドメイン知識を入れたりして要因特定までできるようにしていきたいです。

さて、この記事でリレー形式で行った Gunosy Tech Blog Festa は最後となります。 今年はアドベントカレンダーとは違う形式でお届けする試みをしてみました。 引き続き、Gunosyの技術を世界中の人に最適に届ける取り組みをしていきたいと思います。