🔗

Claude Codeエージェント実践 Day 26|SQL 7本パイプラインを端から端まで通す — モックから本番コードへ

に公開

TL;DR

  • dashboard_generator.py が v2 で止まっていたことに気づき、v3/v4 の SQL 3本 + HTML セクションを一括マージした
  • BigQuery → Python → HTML → Chrome の全工程を通し実行し、v4 ダッシュボードが実データで表示されることを確認した
  • AIが速く作れる快感で設計上の役割分担を忘れていた。本来は分析エージェント経由の設計なのに、人間が直接改良し続けた反省

今日のゴール

Day 22〜25 で段階的に積み上げてきたダッシュボードの設計(SQL 7本・HTMLセクション追加)を、実際に動く dashboard_generator.py に一本化する。BigQuery → Python → HTML 出力 → ブラウザ表示の端から端まで通して、v4 ダッシュボードの完成形をレポートする。

前提条件

  • Day 25 の v4 ダッシュボード設計(SQL 7本)が完了していること
  • BigQuery に analytics データセット(sales, customers, products, budget)が存在すること(テスト用ダミーデータ)
  • Python 3.12 + bq CLI がインストール済みであること

作ったもの

GitHub: akira-cloudjob-public/reporting-agent(Week 4 完了後に公開予定)

v4 ダッシュボード(実データ版)

ダッシュボード v4(実データ)

モックの決め打ち数字が、BigQuery の実データに置き換わった瞬間は気持ちいい。

全体像

Day 22 の v1 は「テーブル3つ × SQL 3本 → セクション4つ」だった。4日間で「テーブル4つ × SQL 7本 → セクション8つ」に成長した。しかしこの全体像が実際にコードとして動くのは、今日が初めてだ。

問題を発見する — v2 止まりのコード

昨日の記事を書き終えて、ふと dashboard_generator.py を開いた。

# v2 の fetch_data() — 4クエリで止まっている
def fetch_data():
    summary = run_bq_query("SELECT SUM(amount)...")        # SQL 1
    by_region = run_bq_query("SELECT region...")            # SQL 2
    monthly_trend = run_bq_query("SELECT FORMAT_DATE...")   # SQL 3
    by_category = run_bq_query("SELECT p.category...")      # SQL 4

    return {
        "summary": summary[0],
        "by_region": by_region,
        "monthly_trend": monthly_trend,
        "by_category": by_category,
    }

v3 と v4 で追加した機能はすべてモック HTML(dashboard-v3-mock.htmldashboard-v4-mock.html)に直接書いていた。本番コードには SQL 5〜7 も、予算比 KPI もドーナツチャートもトップ顧客もない。

普段のバックエンド開発なら、まず設計書を書いて TDD で進めるからこんなことは起きない。しかし今回はエージェントに「こういうセクションを追加して」と依頼して、出てきたモック HTML をブラウザで確認する——というサイクルを繰り返していた。動くものが速く出てくるので満足してしまい、本番コードへの統合を後回しにした結果、4日分の乖離がたまっていた。

v2 → v4 の差分を整理する

マージ前に何を追加するか整理した。

追加内容 変更箇所 由来
SQL 1 改修: products JOIN で粗利を追加 fetch_data() v3
SQL 2 改修: 地域別に原価・粗利を追加 fetch_data() v3
SQL 3 改修: 月次推移に粗利を追加 fetch_data() v3
SQL 4 改修: カテゴリ別に粗利を追加 fetch_data() v3
SQL 5 新規: 予算合計 fetch_data() v3
SQL 6 新規: トップ顧客ランキング fetch_data() v4
SQL 7 新規: 離反顧客検出 fetch_data() v4
KPI カード刷新(予算比・粗利) generate_html() v3
月次推移 2本折れ線 <script> v3
ドーナツチャート新規 <script> v3
地域別テーブルに粗利列 generate_html() v3
顧客ランキングテーブル + CSS generate_html() v4
離反ワーニングカード + CSS generate_html() v4

リストにすると 13項目。多く見えるが、各パーツはモックで動作確認済み。未知の実装はない。

マージ作業 — fetch_data() の統合

作業で一番大きかったのは fetch_data() の更新だ。v2 が返していたデータと v4 が返すデータを並べると、差が明確になる。

# v2 の return
return {
    "generated_at": str(date.today()),
    "period": "先月",
    "summary": summary[0],
    "by_region": by_region,
    "monthly_trend": monthly_trend,
    "by_category": by_category,
}

# v4 の return
return {
    "generated_at": str(date.today()),
    "period": "先月",
    "summary": summary[0],
    "budget": budget[0],          # v3 追加
    "by_region": by_region,
    "monthly_trend": monthly_trend,
    "by_category": by_category,
    "top_customers": top_customers,  # v4 追加
    "churn": churn,                  # v4 追加
}

3つのキーが増えただけに見えるが、裏では SQL のクエリが3本増え、既存4本も products テーブルとの JOIN を追加して粗利を取れるように改修している。

7本のクエリを順に実行すると時間がかかるので、進捗表示を追加した。

def fetch_data():
    print("  [1/7] KPI summary...", end=" ", flush=True)
    summary = run_bq_query(SQL_SUMMARY)
    print("done")

    print("  [2/7] Budget total...", end=" ", flush=True)
    budget = run_bq_query(SQL_BUDGET)
    print("done")
    # ... 以下同様

4本のときは「まとめて待つ」で問題なかったが、7本になると「今どこ?」が気になる。小さな改善だが、デバッグのときに「SQL 7 の離反クエリで止まっている」とすぐ分かるのは助かる。

通しで動かす — 実行ログ

いよいよ、パイプラインを端から端まで動かす。

$ cd outputs/REQ-2026-002/reporting-agent
$ export PYTHONUTF8=1
$ python src/dashboard_generator.py
Fetching data from BigQuery...
  [1/7] KPI summary...      done
  [2/7] Budget total...     done
  [3/7] Monthly trend...    done
  [4/7] By category...      done
  [5/7] By region...        done
  [6/7] Top customers...    done
  [7/7] Churn detection...  done
Generating HTML dashboard v4...
Generated: src/output/dashboard_2026-02-26.html
File size: 24,382 bytes
Self-check passed.

ファイルサイズが v2 の 7,460 bytes から 24,382 bytes に増えた。 3.3倍。これが4日間で積み上げたものの物理的な量だ。CSS、Canvas コード、HTML セクション——すべてが1つのファイルに凝縮されている。

ブラウザで開くと、モックで見慣れたレイアウトが実データで埋まっている。KPI カードの予算達成率、折れ線グラフの売上と粗利の乖離、ドーナツチャートの構成比、顧客ランキング、離反ワーニング——全セクションが揃った。

ハマったところ

モック HTML の変数名と bq の辞書キーのズレ

モック HTML では prev_amount と手書きしていたが、Python の run_bq_query() が返す辞書キーは BigQuery の列名エイリアスそのまま。離反クエリの SQL で prev.total_amount AS prev_amountAS をつけ忘れると、キーが total_amount になって他のクエリの戻り値と衝突する。

# モックでは手書きだったので気づかなかった
amount = ch["prev_amount"]   # SQL の AS エイリアスが正しければ OK
# AS をつけ忘れると → KeyError: 'prev_amount'

モックは「見た目の確認」が目的なので、データ構造の正確さは後回しになる。合流時にこのズレを検出できたのは、通しテストの価値そのものだ。

CSS クラス名の競合

v2 の .bar-fill はカテゴリ別売上の横棒グラフで青系(#4a90d9)に設定していた。v4 で追加したインラインバーも棒の見た目だが、こちらは半透明(rgba(74, 144, 217, 0.15))にしたい。

最初は同じ .bar-fill を使おうとして色が変わってしまった。v4 のインラインバーは .inline-bar として別クラスに分離することで解決。単一 HTML の中で CSS がグローバルスコープなので、命名の衝突は常に気をつける必要がある。

v1 → v4 の進化を振り返る

4日間の累積変化を並べてみる。

指標 v1(Day 22) v2(Day 23) v3(Day 24) v4(Day 25→26)
SQL 本数 3本 4本 5本 7本
HTML サイズ 7.4KB 9.1KB 14KB 24KB
グラフ種類 CSS棒 CSS棒+折れ線 +ドーナツ 同左
表示対象 金額 金額 金額+利益 金額+利益+人
KPI カード 売上・数量・顧客・注文 同左 売上比・粗利・粗利率・顧客 同左

「表示対象」の行が一番重要だと思っている。 v1 は「いくら売れたか」だけだった。v3 で「利益はいくらか」が加わり、v4 で「誰が買い、誰が離れたか」まで見えるようになった。SQL の本数やファイルサイズは結果にすぎない。ダッシュボードが答えられる「問い」が深くなったことが、4日間の本当の成果だ。

学んだこと

「作ること」に没頭すると設計を忘れる

本来のアーキテクチャを振り返る。レポーティングエージェントへの要求は、データ分析エージェントのアウトプットから自動的に流れてくる設計だった。人間が「ドーナツチャートを追加して」「顧客ランキングも入れて」と直接指示するものではない。

ところが Day 23 あたりから、自分がレポーティングエージェントに直接「この機能を足して」と依頼するようになっていた。AI が速く作ってくれるから楽しくなり、「もう少し足そう」「ここも改善しよう」とエスカレートした。気づけば4日間、設計上の役割分担を完全に無視して人間が直接ダッシュボードを改良し続けていた。

普段のバックエンド開発なら設計書と TDD がブレーキになる。しかし AI との開発では「動くものが数分で出てくる」快感がブレーキを外してしまう。本来の目的を忘れて作ることに没頭するリスクは、AI開発ならではの落とし穴だと思う。

通しテストでしか見つからないバグがある

モックでは見つからず、通しテストで初めて発覚する問題がある。SQL のエイリアスと Python の辞書キーのズレ、CSS クラス名の競合——どちらも「実データが流れる一連のパイプライン」でしか再現しない。

モックの世界では、データは手書きの JSON や HTML のハードコードだ。そこでは「型」も「キー名」も自分で決められる。しかし BigQuery から返ってくるデータは SQL が決める。モックは「見た目」を確認するもの。通しテストは「データの流れ」を確認するもの。 両方やって初めて完成と言える。

まとめ

  1. v2 止まりのコードに v3/v4 を合流させ、SQL 7本の完全なパイプラインが動いた。 ファイルサイズ 7.4KB → 24KB は4日間の積み上げの証拠
  2. AIが速く作れるからこそ、設計上の役割分担を忘れやすい。 本来は分析エージェント経由で要求が流れる設計だったのに、人間が直接改良し続けてしまった
  3. ダッシュボードの本当の進化は SQL 本数ではなく「問いの深さ」。 金額 → 利益 → 人へと視点が広がったことが4日間の成果

次回 Day 27 では、4日間で育てたレポーティングエージェントの全体像を振り返り、「道具を作るエージェント」の設計パターンを整理する。


検証環境

項目 バージョン
OS Windows 11 Pro
Shell Git Bash
Python 3.12
Claude Code 1.0.x
BigQuery Standard SQL
ブラウザ Chrome

シリーズを追いかける
著者ページ(Zenn)
GitHub

コメント・質問歓迎です。「モックと本番コードの乖離をどう管理している?」「通しテストのチェックリストが見たい」など、パイプライン開発のアイデアがあればぜひ教えてください。

Discussion