エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

退屈な分析はAIにやらせよう

AI・機械学習チームの氏家 (@mowmow1259)です。 このブログはAI・機械学習チームブログリレー 8日目の記事です。 前日は高田さんによる「BETWEENに気をつけろ! BigQueryの日次集計で罠にハマった話」でした。

最近LLMによるVibe Codingが世間を賑わせています。 エムスリーでも積極的にコーディングエージェントの導入が進んでおり、かくいう私もClaude Code君がいないと生きていけない体にされてしまいました。

コーディングエージェントのおかげで典型的な開発タスクはかなり効率化されてきているものの、面倒なタスクもまだまだ残されています。 分析です。 前日の高田さんの記事にもある通りエムスリーではBigQueryにデータを集約していますが、BigQuery上のデータでぱっと集計したかったりなど、大体どのテーブルを見にいけばいいか想像がつくけど面倒だな。。みたいな場面がよくあります。

そういう場面こそAIの出番! ということで、今回はClaude CodeでBigQuery上で簡単な分析ができるか検証した結果を紹介します。

実際の分析の様子 with Claude Code

さっそくですが、これ用に育てたClaude Code君による分析をお見せします。

ここでは試しに検証用のダミーデータとしてニュース記事のメタデータなどを開発環境に用意し、そのデータに対して「記事数を時系列で分析したい」という大雑把な分析を依頼してみます。

雑に分析を依頼している様子

プロンプトを投げると、仕様の整理のためいくつか質問されるので、それに答えます。 すべてを構造化してコンテキストとして渡せるわけではないので、地味にありがたいですね。

雑に回答する様子

ここが賢いポイントですが、どのテーブルを見にいくか、どこでJOINすればいいかは適宜Claude Code君がbq lsなどを使って調査して判断してくれます。 もちろん判断できない場合もありますが、その場合もClaude Code君から質問してくれるか、あるいはこっちから割り込むか、で教えてあげます。

頑張ってクエリを構築してくれているClaude Code君

そうこうしているうちに、分析できるnotebookができあがります。

出来上がったnotebook

。。。結構いい感じじゃないでしょうか?

後述する仕組みで一度やった簡単な分析なら手放しでやってくれますし、2、3テーブルのJOINくらいなら質問に答えてればうまくクエリを構築してくれます。 人間はそれを眺めつつ妥当性のチェックだけして結果を見るだけです。

設定のコツ

ここからは、実際にClaude Codeをどう設定しているかをみていきます。 実際に開発環境でいくつも分析をさせてみた結果、いくつか肝になった工夫があるので、それを紹介していきます。

いきなりクエリ・コードを書かせない

一番ハマったのがここでした。 Claude Codeは典型的な開発タスクでは比較的うまく計画を立ててタスクを実行してくれますが、分析タスクの計画はあまりうまく立てられず、無邪気にクエリを書いては意味不明なデータを使って分析を進めてしまいます。

- まずコードを書くのではなく、ユーザーに仕様の深掘りをしてください
- 仕様がわかったら、必要なデータの洗い出して、データを取得するための方法について検討してください
    - それでもわからない場合、ユーザーに手掛かりがないか聞いてください
    - それでもわからない場合、自分で調べてください
      - JOINするキーがわからないなど、不明点があれば、サンプルデータとともにユーザーに聞いてください
        - 新しいデータはユーザーも不安なので、スキーマやデータのサンプルを適宜提示してください
      - 追記した後、そのデータを参照してデータの取得方法を検討してください
    - 各データについて少量のデータを取得して、データの特徴を把握してください
- データの取り方がわかったら、最終的に必要なクエリやダウンロードコマンドを構築してください

上記のように、まずは仕様の深掘りやデータの洗い出しからさせ、データの取得方法が定まってからクエリやコードを書かせるように徹底させることで、迷走を防ぐことができます。

データの探し方を教えておく

必要なデータの取得方法がわからない場合のデータの探し方をコンテキストとして教えておきます。

ユーザーがデータソースに心当たりがある場合はユーザーから情報を与えた方が早いので、わからない場合、ユーザーに手掛かりがないか聞いてくださいという指示を与えておきます。 人間というドメイン知識の塊を使わない手はありません。 完全放置はできなくなってしまいますが、迷走されてやり直すよりはるかにマシです。 この際のプロンプトはhogeみたいな名前だった気がするみたいな抽象度でもよしなにbq lsコマンドなどで探索してくれるので、自分で検索してテーブルを見に行くよりも早い場合が多いです。

ただ、必ずしもユーザーに心当たりがあるわけではないので、自律的にデータを探す方法も与えておきます。

#### データセットもわからない場合
`gcloud data-catalog search ${QUERY} --include-project-ids ${project_name}`でqueryに関連するスキーマを検索できます

...

特にdata-catalogはテーブルやカラムの説明からデータソースを検索できるので、大抵のテーブルは頑張って探してきてくれます。

これを書いていて思いましたが、ここはMCPを使っても良いかもしれません。 例えばBigQueryはいくつかMCPサーバーが実装されているようです。

github.com

テーブルの情報をコンテキストとして蓄積させる

2番目にハマったのがここでした。 LLMでのクエリ構築を試みた方はわかると思うんですが、とにかくJOINが鬼門です。 マスタテーブルとJOINするといってもテーブルやカラムのメタデータからJOINの条件を特定するのは結構難しいタスクです(やってみて改めて実感しましたが、しばしば人間も難しいです)。 うまくbq queryでデータの中身を見つつ特定してくれる場合もありますが、成功率は高くありません。

そこで、あらかじめJOIN条件をはじめとしたテーブル情報を用意しておき、データ探索前に読み込ませておくことにしました。

- まずコードを書くのではなく、ユーザーに仕様の深掘りをしてください
    - `.claude/domain.md``.claude/table_info.md``.claude/join_info.md`も参照してください
- 仕様がわかったら、必要なデータの洗い出してデータの取得方法について検討してください
    - `.claude/table_info.md`を参照して、必要なテーブルとカラムを書き出してください
    - JOINするキーは`.claude/join_info.md`を参照してください

また、これらのデータをアップデートし続けるのも面倒なので、新しいデータソースが使われた場合には自分で追記していってもらっています。 こうすることで、同じような分析をする場合に、過去の情報を見つつかなり効率的にクエリを構築してくれます*1

## CLAUDE.mdへの追記
- 新しく得たドメイン知識は`.claude/domain.md`に追記してください
- 新たなデータソースの取得時`.claude/table_info.md``.claude/join_info.md`に情報を追記してください
   - `.claude/table_info.md`にはテーブルの情報を追記してください
   - `.claude/join_info.md`にはテーブル同士のJOIN情報を追記してください
   - 形式はそれぞれのファイルの中身に倣ってください

.claude/table_info.md

テーブル概要などを格納したMarkdownです。 Claude Code君はgcloud data-catalog searchなどを叩いて試行錯誤してくれますが、無駄な試行錯誤がかなり減ります。

## dataset.table

**概要**: サンプルテーブル

### カラム一覧

| カラム名 | データ型 | モード | 説明 |
|----------|----------|--------|------|
| id | INTEGER | REQUIRED | ID |

既存のSQLクエリからテーブルの一覧を取得し、メタデータをMarkdownに落としてもらうところもClaude Codeにやってもらいました。

.claude/join_info.md

JOIN条件を格納したMarkdownです。 次のような形式でテーブル間のJOIN条件を羅列しています。

dataset_name.table_name.column_name = dataset_name.table_name.column_name

実際にはこれを作るのも大変じゃん、と思うところですが、こちらも実は大体のデータは既存コードのSQLからClaude Codeに作らせています。 **/*.sqlのJOIN条件を列挙して。ただし、サブクエリやエイリアスはオリジナルのデータセット、テーブルまで解析した上で列挙してくらい言っておけば、それなりに使えるデータが手に入りました。 あとは分析のたびにClaude Code君に追記していってもらえば良いです。

.claude/domain.md

サービス名や略称など、社内のドメイン知識を記入しておきます。 ここを充実させておくと、最初のプロンプトが雑でもよしなに分析してくれるようになりました。

使ってみて

試しにCLAUDE.mdを育ててみましたが、うまく使えそうな出来になってきました。 「集計自体は簡単で、あとはやるだけなんだけど面倒だなぁ」くらいの分析なら問題なくやってくれる印象です。

ただ、本番運用するには改善していきたいモヤっとポイントもいくつかあります。

意図せず巨大なデータへクエリを投げてしまう可能性がある

データの探索で割とカジュアルにbq queryを連打するので、巨大なパーティションテーブルやシャーディングテーブルを使っている場合、知らず知らずのうちに巨大データにクエリを連打してとんでもない金額になる可能性もあります。

カジュアルにSELECT * FROM logs_*とかやろうとして慌てて止めることもありました。 次の指示でいくらか緩和されましたが、完全ではありません。

`bq query`で少量のデータで中身を確認しましょう。ただし、巨大なデータの場合、_TABLE_SUFFIXでの絞り込みや、partition tableの場合はpartitionの絞り込みを忘れないでください

ただ、エムスリーではクエリされたら困るほどの巨大なパーティションテーブルには大体パーティションキーでの絞り込みを必須にしていますし、今の所致命的な問題にはなっていません。 また、同じような問題意識でMCPサーバーを作っている方もいるようです。 プロンプトで調整していくと言うよりは、仕組みで解決していきたいところですね。

zenn.dev

集計結果の妥当性

Claude Code君は毎回それっぽいクエリは書いてくれるんですが、その妥当性の判断は(少なくともこの記事の通り実践した場合は)まだまだ人間がする必要がありそうですし、初手で間違ったクエリを出してくることもまぁまぁあります。 例えばユーザーIDでユニークなテーブルの想定で分析を進めて、実はユニークでなかった、みたいなことも起こります。 人間がチェックするのでもいいですが、本当はClaude Code君にもう少し頑張ってもらいたいところです。

各データについて少量のデータを取得して、データの特徴を把握してください

試行錯誤の末、このプロンプトでいくらか成功率は上がったものの、まだまだ調整の余地はありそうです。

暴走してしまう

ここまで説明してきましたが、やっぱり暴走してしまう時も稀にあります。 全く違うカラムで変にJOINできちゃったりすると、それで正しいと思って突っ走った挙句、矛盾に気づいたが軌道修正できずbq showを繰り返す、なんてこともありました。

与えるコンテキストの調整ももちろん必要ですが、LLMフレンドリーにインフラ側を変えていくのもありかなとも感じます。 単純にはテーブル概要などのメタデータの整備ですが、LLM用に非正規化させたテーブルやビューを整備するのも手かもしれません。

まとめ

今回は、BigQueryの分析用のClaude Codeの設定を検証してみました。 BigQuery用に書きましたが、他のデータソースでも応用が効く内容になっていると思います。 今回はサンプルデータで検証していきましたが、本番環境での利用のためにservice accountによる制御や分析基盤などを整えて、業務効率化もどんどん実施していきたいです。

We are hiring !!

エムスリーでは、最先端の技術を使いながら、日々の仕事を効率化していくエンジニアを募集しています。 少しでも興味を持っていただけたら、次のリンクからカジュアル面談にご応募ください!

エンジニア採用ページはこちら

jobs.m3.com

カジュアル面談もお気軽にどうぞ

jobs.m3.com

インターンも常時募集しています

open.talentio.com

*1:実際には自動で追記してくれるかどうかは五分五分で、@CLAUDE.mdに追記して、のようにプロンプトを入れてあげる必要がある場合もあります