📊

データ抽出から可視化まで担う AI 分析アシスタントの試作

に公開
2026/03/01

概要

冬休みの自由研究で AI 分析アシスタントを試作したので、日記の代わりに記事を書きます。
こんな感じで、自然言語で分析内容を指定すると、データの抽出と可視化をやってくれます。
ちなみに利用しているデータは theLook eCommerce という BigQuery の public dataset です。

コードは GitHub に置いてあります。

https://github.com/kitta65/poc-ai-analyzer

構成

  • 画面は streamlit 製
  • データ抽出は Cube の GraphQL API を叩く
  • 可視化方法は Veta-Lite で指定する
  • AI の呼び出しは Pydantic AI を介して行う

以下、それぞれについてもう少し詳しい構成や選定理由を書きます。

Streamlit

データに関するアプリケーションを試作するならこれでしょ、という安定感がありますよね。
久しぶりに公式ドキュメントを見たら LLM を利用したチャットアプリのチュートリアルが追加されていたので、基本的にはそれを真似て実装しています。

Cube

Semantic Layer を実装するためのツールです。
少し前から AI x Semantic Layer の実験をしてみたかったので採用しました。
AI に SQL を生成させてデータを取得するよりも、Semantic Layer 経由でデータを取得させる方が簡単だと期待しています。

また Cube の REST API ではなく GraphQL API を採用したのは、dimension や measure の名前も AI に正確に理解させたいからです。以下のような GraphQL の schema だけ与えれば、AI は dimension や measure 名を正確に理解して API を叩けるはずです。

# 抜粋
type UsersMembers {
  count: Float
  count_male: Float
  count_female: Float
  ratio_male: Float
  ratio_female: Float
  email: String
  gender: String
  first_name: String
  last_name: String
  full_name: String
  count_order: Float
}

type Result {
  users(where: UsersWhereInput, orderBy: UsersOrderByInput): UsersMembers!
}

type Query {
  cube(where: RootWhereInput, limit: Int, offset: Int, timezone: String, renewQuery: Boolean, ungrouped: Boolean, orderBy: RootOrderByInput): [Result!]!
}

一方で、REST API からデータ抽出する場合は openspec.yml を参考に API を叩くことになりますが、これだけでは dimension や measure の名前が分かりません。meta データ用の API を叩いたりして追加の情報と組み合わせる必要があり、難易度が一段上がってしまう印象です。

Vega-Lite

Python の有名な可視化ツールの一つに Altair があります。Vega-Lite はそのベースにもなっている可視化の仕様です。JSON 形式で指定できるので AI で生成しやすいと考えました。

JSON Schema が公開されているので、そこから Pydantic のコードを自動生成できると期待したのですがうまくいかず[1]、結局以下のように手作業で実装しています。手作業で実装したものは Vega-Lite の仕様のごく一部ですが、これでもシンプルなグラフなら記述できます。

https://github.com/kitta65/poc-ai-analyzer/blob/32084dc6b5d906bc26f8d3ac452a4d4905d945bb/app/agents/vegalite.py#L9-L28

ちなみに streamlit で Vega-Lite に基づくグラフを表示するするのは st.vega_lite_chart を実行するだけなのでとても簡単です。

Pydantic AI

streamlit を使うと決めたので、Python の AI フレームワークを探していたら最初に見つりました。validation の分野で信頼されている Pydantic チーム製というのも心強く、即採用です。

ちなみに今回は Agent を三つに分けて実装しています。

  • ルーティング Agent
    • ユーザーの要望を理解し、他の Agent に指示を出します
    • ユーザーの要望が曖昧な場合は、詳細を特定するために質問を返します
    • そもそも分析が不可能な場合は拒否します(Cube の Model 定義を instruction として与えることで、そこに記述がないものは拒否させます)
    • ユーザーとの会話履歴の管理も担います
  • GraphQL Query 生成 Agent
    • ルーティング Agent の指示に基づいて、Cube の GraphQL API を叩くための GraphQL Query を生成します
    • instructions として GraphQL の Schema を与えることで、誤った Query を返さないように validation もできるようになっています
  • Vega-Lite の JSON 生成 Agent
    • ルーティング Agent の指示に基づいて Vega-Lite の JSON を生成します
    • instruction として、実際に Cube から取得したデータを数行与えることで、精度向上を期待しています

所感

Good

  • AI に生成させる部分を GraphQL Query と Vega-Lite の JSON に限定したことで、最低限の指示でも AI が働いてくれている気がする

Bad

  • データ抽出処理と可視化処理で Agent を分けたことにより、そこで文脈が途切れている気がする(例えばデータ抽出時は細かく group by されたデータを持ってくるが、結局は可視化処理でまとまるから無駄、みたいなケースがちらほら)

もうちょい工夫すれば Bad であげたポイントも多少改善できそうな気がしますが、今回は飽きたのでここまでです。

脚注
  1. 試行錯誤した PR ↩︎

Discussion