ミツモア Tech blog

「ミツモア」を運営する株式会社ミツモアの技術ブログです

AI Ready Data Analysis Platform(4/n) - AIエージェントとして覚醒した第二世代text2SQLツール

ミツモア データサイエンティストの増田 @xmasudahiroto です。

ミツモアでは、日々自身の生産性向上に努めるよう全社を挙げて生成AIを日常的に活用しまくっています。データグループでも生成AIを最大限活用し、分析にまつわる業務全てを置き換える活動を行っています。

今回は、前回古田さんが紹介した第一世代text2SQLから大幅に進化した第二世代text2SQLツールについて、アーキテクチャの転換とエージェンティックアプローチの採用について、包括的にお話しします。

AI Ready Data Analysis Platformシリーズ過去の記事

はじめに

データ分析の民主化は、多くの企業が目指す重要な目標です。しかし、SQL作成の難易度や適切なテーブル選択の複雑さが、この目標達成の大きな障壁となっています。

ミツモアでは2023年春に第一世代のtext2SQLツールをリリースしましたが、精度の課題や使い勝手の問題があり、真の意味での民主化には至りませんでした。そこで2024年末から2025年初頭にかけて、完全0からの作り替えを行い、第二世代text2SQLツールを開発しました。

特筆すべき点は、社内利用できるWebアプリケーションとして、VibeコーディングでClaude Codeを使いスクラッチ開発したことです。私自身、TypeScriptはあまり経験がありませんが、Claude Codeの支援により、モダンなReact + TypeScriptのフロントエンドから、Python FastAPIのバックエンド、Dockerベースのインフラまで、動作する完全なシステムを構築することができました。

第一世代の課題

技術的な限界

第一世代のtext2SQLツールは、Slackをインターフェースとし、固定されたワークフローで動作するシステムでした。具体的には、下記の流れでした。

  1. ユーザーの質問テキストをベクトル化する
  2. RAGで関連テーブルを検索する
  3. 検索で得られたテーブルから使用するカラムを選ぶ
  4. クエリを作成してdry runで検証する
  5. 最後に微修正を加える

しかし、このアプローチには以下のような課題がありました。

精度の限界

第一世代の最も大きな課題は、テーブル選択の精度不足でした。Embeddingベースの単純なRAGアプローチでは、複雑なクエリや文脈の深い理解が困難でした。特に問題となったのは類似テーブルの誤選択です。例えば、requestsテーブルとproduct_requestsテーブルのように名前が似ているテーブルが存在する場合、ベクトル検索だけではビジネス要件に最適なテーブルを選択できませんでした。

さらに、ログデータのようにプロダクトコードが頻繁に変わる部分では、ドキュメントの更新が追いつかず、結果として古い情報に基づいた誤ったクエリが生成される問題もありました。

逐次処理による制約

第一世代はエージェント的な判断ができないという根本的な制約を抱えていました。あらかじめ定義された固定ワークフローに従って処理するため、状況に応じた柔軟な対応ができなかったのです。

例えば、「このクエリをBIツールに登録してダッシュボードに追加する」といった複雑なタスクには対応できませんでした。また、一度の試行で適切なクエリを生成できなかった場合も、試行錯誤して別のアプローチを試すことができませんでした。

UXの問題

Slackベースのインターフェースには、技術的な制約による使いづらさがありました。Slackは1投稿あたり3000文字が上限であるため、長いSQLコードは途中で途切れて表示され、スレッドが長くなると過去のやり取りを追うのが困難になります。生成されたコードをコピー&ペーストする際にも、余計な空白や改行が混入するなどの問題がありました。

データ基盤の複雑性

これらの技術的課題に加えて、ミツモアのデータ基盤特有の複雑さも、第一世代の精度向上を困難にしていました。

ミツモアのBigQueryには約1000のテーブルが存在しており、個人向けサービスとビジネス向けサービスという複数プロダクトのデータが混在しています。さらに厄介なのは、微妙に異なる指標が多数存在するという点です。例えば、「クロスセルを含む売上」と「通常の売上」、「初回購入ユーザー」と「リピート購入ユーザー」など、似ているが重要な違いがある指標がたくさんあります。

また、前述のrequestsproduct_requestsのような類似したテーブル名も多く、単純なベクトル検索では適切なテーブルを選択できませんでした。

これらの課題を解決するため、アーキテクチャから根本的に見直した第二世代の開発を決断しました。

第二世代で何を作ったのか

第二世代では、Slackベースのインターフェースを廃止し、独立したWebアプリケーションとして再設計しました。

以下の表は、第一世代と第二世代の主な違いをまとめたものです。

項目 第一世代 第二世代
アーキテクチャ 固定ワークフロー(RAG) エージェンティック
情報検索手法 Embedding + ベクトル検索 Grep + 直接コード検索
インターフェース Slack 独立Webアプリ
柔軟性 固定フロー(試行錯誤不可) 状況に応じた判断が可能
複雑タスク対応 不可 可能(BIツール連携など)
コード表示 途切れる、コピーしづらい Markdownで適切に表示
開発基盤 独自実装 Claude Code SDK + MCP

技術スタック

第二世代では、モダンなWebアプリケーション開発のベストプラクティスに従った技術スタックを採用しました。

フロントエンドには、TypeScript + React 18 + Vite + Tailwind CSSを使用しています。Claude Codeを使用してVibe Codingで作成しました。

バックエンドは、Python 3.11以上とFastAPIで構築しました。AIエージェント部分としてはClaude Code SDKを採用しました。

インフラには、GCPのCloud Runを採用しています。認証部分は、Google Cloud IAP(Identity-Aware Proxy)により実装しています。これにより、社内のGoogleアカウントと連携した安全な認証基盤を、最小限の実装コストで構築できました。

エージェンティックアプローチへの転換

第二世代の最大の特徴は、RAGベースの逐次処理から、エージェンティックなアプローチへの転換です。

RAGの廃止とツールベースアプローチ

第一世代のEmbedding + RAGを完全に廃止し、ツールベースのエージェンティックアプローチに変更しました。この変更は、text2SQLの精度向上において重要でした。

新しいアプローチでは、エージェントは以下の3つの主要な情報源に直接アクセスします。

まず、プロダクトコードの直接検索です。エージェントはgrepツールを使って、DBのスキーマ定義やクエリパターンをプロダクトコードから直接検索できます。これにより、ドキュメントの更新を待たずに、実際に動作しているビジネスロジックとデータ構造を正確に理解できるようになりました。例えば新規のABテストがリリースされたときも、プロダクトのコードをみて、バケット分割のロジックに従った検証クエリを、都度ドキュメントの整備せずとも作成できます。

次に、dbtコードベースの検索です。ミツモアではデータの加工をdbtを活用しておこなっています。dbtモデルの定義やメタデータ、サンプルクエリを直接参照することで、テーブルの用途や適切な使い方を理解します。データ連携の情報をプロンプトに渡して置くことで、プロダクトのDBと、データ基盤上のDBで、対応関係を追えるようにしています。

最後に、BigQueryのMCPを拡張する形で、INFORMATION_SCHEMAに対する直接クエリを行うツールも作成しエージェントに提供しています。

このようにエージェントが多角的にテーブル検索を行えるようにしたことで、RAGなしで、十分な精度でテーブル選択ができるようになりました。

エージェンティックアプローチの優位性

RAGとの最大の違いは、情報取得のタイミングと戦略の柔軟性にあります。

RAGでは、ユーザーの質問を受け取った時点で、あらかじめ関連すると思われる情報をまとめて取得します。しかし、これでは必要のない情報まで取得してしまい、コンテキストウィンドウを圧迫してしまいます。

一方、エージェンティックアプローチでは、エージェントが必要に応じて能動的にツールを使って情報を探索します。これにより、必要な情報だけを取得でき、コンテキスト長を大幅に節約できます。また、複数の情報源を組み合わせた高度な推論が可能になり、ユーザーの質問に応じて柔軟に検索戦略を変更できます。

メタデータの整備

エージェントのLLMモデルがいくら精度が高くても、検索するための高品質なメタデータがなければ意味がありません。これに対し、データグループ全体でメタデータ整備に取り組んできました。

dbtのdescription整備には、チーム総出で取り組みました。約1000のテーブルと数千のカラムに対して、ビジネス的な意味や使用上の注意点を記載しています。この作業は地道ですが、エージェントの精度向上に直結する重要な投資でした。

Table Tag Systemは、古田さんが整理したTier分類システムです。テーブルを重要度や用途によって分類し、エージェントが優先的に参照すべきテーブルを判断できるようにしています。例えば、Tier 1は最も重要で信頼性の高いテーブル、Tier 3は一時的な分析用テーブル、といった具合です。

サンプルクエリの作成も行っています。「先月の売上を集計する」といったビジネス要件に対して、実際にどのテーブルをどう結合すべきかを示すサンプルクエリを蓄積しています。エージェントはこれらのサンプルを参考に、新しいクエリを生成できます。

MCP(Model Context Protocol)によるツール提供

エージェンティックアプローチを実現するため、MCP(Model Context Protocol)を活用して、エージェントに様々なツールを提供しています。

統合したMCPサーバー

第二世代では、3つの主要なMCPサーバーを統合しています。

BigQuery MCPサーバーは、公開されているOSSをforkして、ミツモアの環境に合わせてカスタマイズしました。クエリ実行、dry run、テーブル・カラム検索といった基本機能に加えて、テーブル検索ツールや、DDL文を持つクエリの拒否、極端に費用のかかるクエリが実行されないようにするなど、微修正をしています。これにより、エージェントが自動でクエリを実行しても問題ない環境を作っています。

Redash MCPサーバーも、同様にOSSをベースに構築しました。エージェントはこのサーバーを通じて、Redashのクエリを取得、作成、更新、アーカイブできます。こちらは現状ほぼOSSの状態のままですが、今後はタグ付け機能や権限管理などの面で、拡張していく予定です。

Serena MCPサーバーは、プロダクトコードの検索と解析に特化したツールです。ファイル検索、シンボル検索、パターン検索など、開発者がIDEで行うような操作をエージェントが実行できます。Serenaを使うとコンテキストの量が減り費用が削減できるので、コードを検索する際の費用削減の意味合いで使用しています。

Claude Code SDKの利点

エージェント部分にはClaude Code SDKを使用しています。ファイル検索やファイル編集といった基本的なツールが標準で提供されており、shellコマンドもホワイトリストで制御できるため、高機能で安全なエージェントを短期間で作成することができました。MCPによる拡張ももちろんできます。また、ローカル環境で常日頃私が使っていた感覚から、Claude Codeベースでtext2SQLを作れば精度が良いものができると、確度高く思っていたから採用しました。

WebアプリケーションとしてのUI/UX

Slackベースから独立したWebアプリケーションに移行したことで、ユーザー体験が向上しました。

リアルタイムストリーミングは、第二世代の重要な特徴です。Server-Sent Events (SSE)を使用することで、エージェントの思考過程をリアルタイムで可視化しています。ユーザーは「今どのテーブルを探しているのか」「どのツールを使っているのか」を逐一確認できるため、安心感があります。

適切なコード表示も大きな改善点です。Markdownレンダリングにより、SQLクエリやコードがシンタックスハイライト付きで見やすく表示されます。Slackでは途切れていた長いクエリも、きれいに整形されて表示されるため、コピー&ペーストも簡単です。

セッション管理により、複数の分析タスクを並行して進められます。会話の継続や、新規チャットの開始が直感的に操作でき、過去の会話履歴も簡単に参照できます。

中断機能も実装しました。エージェントが予想外に長時間実行している場合、ユーザーはいつでも処理を中断できます。これにより、コスト管理と使い勝手の両方を実現しています。

インフラとセキュリティ

最短でのGCPデプロイ

プロダクトとしての価値を早期に検証するため、最短経路でのデプロイを目指しました。

認証にはGoogle Cloud IAP(Identity-Aware Proxy)を採用しました。IAPを使うことで、独自の認証基盤を構築することなく、社内のGoogleアカウントと連携した安全なアクセス制御が実現できます。これにより、セキュリティを担保しながら、開発期間を大幅に短縮できました。

デプロイ先にはGoogle Cloud Runを選択しました。Dockerコンテナをそのままデプロイでき、自動スケーリングにも対応しているため、インフラ管理の負荷が最小限で済みます。

アーキテクチャの詳細

実装面では、いくつかの工夫をしています。

単一Cloud Runインスタンスで、フロントエンドとバックエンドの両方を実行しています。supervisordを使用してプロセスを管理することで、コンテナ内で複数のサービスを安定して起動できます。これにより、デプロイの複雑さやインスタンスの料金を抑えつつ、開発が容易な環境を実現しました。

Slack Bot機能も併設しています。Socket接続を利用してSlackと連携し、Webアプリケーションと並行してSlackからもtext2SQLを呼び出せるようにしています。特に、社内の問い合わせワークフローで受け付けた質問は、まずtext2SQLが自動で解答を試みる仕組みになっており、データグループの負荷軽減に貢献しています。

ロギングとモニタリング

継続的な改善のために、アプリケーションの利用ログを収集しています。第二世代text2SQLツールでは、すべてのユーザーアクティビティを構造化してBigQueryに記録しています。

まだできていませんが、利用ログを分析して、よく使われる質問パターンを特定してプロンプトを最適化したり、エラーが多発するテーブルや指標のメタデータを改善していきたいと考えています。

成果と今後の展望

成果

第二世代text2SQLツールの導入により、期待以上の成果が得られました。

精度の大幅な向上

エージェンティックアプローチへの転換により、テーブル選択精度が劇的に向上しました。これは数値化はしていないのですが、体感としてほぼ全てのユーザーが感じています。

クエリ品質も大きく改善しました。dry runによる事前検証を組み込むことで、構文エラーはほぼゼロになりました。また、プロダクトコードとdbtサンプルクエリを直接参照できるようになったことで、ビジネス文脈の理解が格段に向上し、単に動くだけでなく、ビジネス要件を正確に満たすクエリが生成されるようになりました。

ユーザー体験の改善

Webアプリケーションへの移行により、ユーザー体験が大きく変わりました。

リアルタイムフィードバックにより、エージェントが今何をしているのかが可視化され、ユーザーの不安が軽減されました。また、中断機能により、長時間実行される処理をユーザーが制御できるようになり、コスト管理の面でも安心感が生まれました。

Markdownレンダリングによる見やすいUIも、地味ながら大きな改善でした。Slackでは途切れて表示されていた長いSQLクエリが、シンタックスハイライト付きできれいに表示されるようになり、コピー&ペーストもスムーズになりました。

実際にリリースすると、いままでSQLを書けなかった社員でも、text2SQLを使って積極的にクエリを書くようになった例もあり、全社的なデータの民主化に貢献できたと考えています。定量的な成果として、事業側の社員でSQLを自分で書けない人が、直近一週間のメッセージ送信数が89の場合もあり、とても良く使っていただけています。

今後の展望:既存ツールの最大活用へ

第二世代のシステムを構築して運用する中で、いくつかの現実的な課題も見えてきました。

現状の課題

第二世代の開発を通じて、多くの学びがありました。

Claude Codeを使って自分でWebアプリケーションを構築したことで、素早くプロトタイプを作り、コンセプトを検証できました。しかし、実際に運用してみると、細かいバグや使いにくさ、履歴機能の不足など、プロダクトグレードのUIとしては改善点が多いことも明らかになりました。これらを解消するにはやはり相当な工数が必要です。

また、Claude Code SDKを使うことで高い精度を実現できましたが、Anthropicのモデルを使用する必要があり、コスト面での課題も浮上してきました。ビジネスメンバーの利用が増えるほどコストも増加するため、スケーラビリティの観点から懸念があります。

さらに、精度の数値化ができていないという課題もあります。体感として精度が向上したことは明らかですが、定量的な評価指標を設定できていないため、継続的な改善が難しい状況です。加えて、Redash MCP経由で作成されるクエリが同一アカウントになるため、誰が作成したクエリなのかが分からないという運用上の課題も残っています。

次世代の方向性

これらの経験を踏まえて、今後は既存の成熟したツールやプラットフォームを最大限活用する方向について検討しています。

認証付きリモートMCPサーバーの構築

データチームの本当の強みは、データ基盤への深い理解と運用ノウハウにあると考えています。そこで、今後は使いやすくセキュアで信頼できるMCPサーバーの構築と運用に集中していく方向性を検討しています。

BigQuery、Redash、dbt、GitHubなど、データ基盤全体へのアクセスをMCPプロトコルで提供し、認証・認可を適切に実装することで、社内で安全に利用できるMCP基盤を整備することを考えています。これにより、どのようなエージェントプラットフォームからでも、ミツモアのデータ基盤に安全にアクセスできるようになることを目指しています。

エージェント構築は既存プラットフォームで

エージェント本体は、DifyOpenAI Agent Builderといったノーコード/ローコードプラットフォームで構築することも検討しています。これらのプラットフォームは、UIの完成度が高く、履歴管理やセッション管理といった基本機能が充実しています。また、プロンプトの調整やツールの追加も、コードを書かずに行えます。

現時点では、エージェントをSDKレベルで作る必要があるような高度な機能は実装していません。ノーコードプラットフォームで十分に実現できる範囲に絞ることができれば、UIやエージェントロジックの保守工数を大幅に削減できると考えています。

コスト最適化とモデル選択の柔軟化

オープンソースモデル(Kimi K2やQwen3など)の使用により、モデル料金を大幅に抑制できる可能性があります。精度は若干落ちる可能性がありますが、実用上は十分かもしれず、早くて手頃な価格でビジネス側の利用でもスケール可能になるのではと考えています。

MCPサーバーを分離することで、モデルやプラットフォームの選択が柔軟になり、コストとパフォーマンスのバランスを最適化できるようになることを期待しています。

このような方針で進められれば、text2SQLから派生して、広告運用に特化したエージェントや、事業企画に特化したエージェントも、必要なツールをつなげていくことで、ノーコード/ローコードプラットフォームで構築でき、AIエージェント作成の民主化にもつながるのではと考えています。

まとめ

本記事では、ミツモアの第二世代text2SQLツールについて、エージェンティックアプローチへの転換とClaude Codeを使った開発プロセスを紹介しました。

重要なポイント

第一世代のEmbedding + RAGを廃止し、ツールベースのエージェンティックアプローチに移行したことが、精度向上の最大の要因です。エージェントが必要に応じて情報を探索することで、テーブル選択精度が向上しました。

MCP統合により、BigQuery、Redash、Serenaといったデータ基盤全体に拡張可能な形でアクセスできるようになりました。これにより、単なるクエリ生成だけでなく、BIツールへの登録といった複雑なワークフローも実現可能になっています。

Slackベースから独立したWebアプリケーションへの移行により、UXが大幅に改善しました。リアルタイムストリーミング、適切なコード表示、セッション管理、中断機能といった機能により、ユーザー体験が向上しています。

Claude CodeによるVibe Codingにより、TypeScript未経験の私でも、わずか2週間程度でプロトタイプから本番デプロイまで完了できました。これは、エージェント開発の民主化とも言えます。

実際の成果として、いままでSQLを書けなかった社員でも、text2SQLを使って積極的にクエリを書くようになった例もあり、全社的なデータの民主化に貢献できたと考えています。

データ分析の民主化に向けて

text2SQLツールは、単なる便利ツールではありません。データ分析の民主化という大きな目標に向けた重要なステップです。

SQLを書けないメンバーが自分でデータを取得できるようになり、データグループは単純作業から解放されて、より価値の高い分析に集中できるようになりました。そして、データドリブンな意思決定が全社に広がりつつあります。

第二世代text2SQLツールは、このような目標に大きく近づく成果を上げています。今後は、既存の成熟したプラットフォームを活用し、データチームの強みであるMCPサーバーの開発とデータ品質の向上に集中することで、真の意味でのデータ分析民主化を実現していけるのではと考えています。


ミツモアで一緒に働きませんか?

ミツモアでは、データやAIを活用してデータドリブンな風土のある会社にて一緒に働く仲間を募集中です。

今回紹介したtext2SQLツールのように、最新の生成AI技術を積極的に活用して、データ分析の民主化を推進するプロジェクトに参加できます。

簡単な集計は自動化されたので、より高度な分析を通して、データサイエンティストとして本質的な業務に集中できる環境もあります。

ぜひご応募をお待ちしています!

ミツモア採用ページ: https://corp.meetsmore.com/