dbt + DuckDB で学ぶ Spotify 式 Context Layer - 正確なKPI集計と自由なデータ探索を両立する Text-to-SQL 設計論
自然言語での分析(DWHへの問い合わせ)を実現する場合、必要なコンテキストを用意せずにスキーマやテーブル定義のみをプロンプトとして渡しただけのText-to-SQLでは、現場特有の業務ルールを反映できず誤集計が多発します。
本記事では、Spotify社内AI「Vedder」[^1] の設計思想を参考に、DuckDB + dbt-duckdb + Gemini 3.7 Flash を用いて、4つの検証パターン(素のDDL、Context Layer、Semantic Layer、および両者を統合したハイブリッド構成)の精度を実測した結果を比較します。
目次
- この記事のまとめ
- 検証環境と前提条件
- 1. データ構造と検証シナリオ(ERD)
- 2. 課題:マスタにフラグが存在してもLLMが誤る理由
- 3. Spotify社内AI「Vedder」の設計思想
- 4. 統合ハイブリッドの要:AI Router の仕組みと実装選択肢
- 5. dbtリポジトリでの定義ファイル構成
- 6. 実践検証:4パターンの精度実測と挙動比較
- 7. なぜ Semantic Layer だと計算ミスが起きないのか?
- 8. まとめとデータ組織向け導入ロードマップ
- 参考文献
この記事のまとめ
- コンテキスト無しでの限界:
マスタにフラグが存在しても、LLMは「ポッドキャスト除外」や「30秒未満スキップ除外」等の暗黙ルールを認識できず誤集計が発生(実測結果にてポッドキャストホストが1位に混入)。 - 3つの単体パターンの特性:
Pattern A (素のDDL): 業務ルールを解釈できず全滅。Pattern B (Context Layer): 業務ルールを注入して動的SQL生成。柔軟だが比率計算で推測に頼るリスクあり。Pattern C (Semantic Layer): LLMにSQLを書かせず MetricFlow経由で決定的なSQLを生成し実行。比率計算ミスの発生を防げる。ただし柔軟性を求めらる非定型集計は不向き。
- 結論(Pattern D:Routerを用いた統合的な活用):
定型KPIは Semantic Layer、非定型探索は Context Layer へ自動ルーティングする AI Router により、全シナリオで高精度な正解とガバナンスを両立。
検証環境と前提条件
本検証は、ローカルPC上で DuckDB + dbt-duckdb + Gemini API の最小構成で実測を行っています。
- データエンジン: DuckDB (v1.4+) + dbt-duckdb (v1.10+)
ローカル上でスタースキーマ(マート層)およびセマンティック定義を構築・クエリ実行。 - 推論モデル (LLM): Google Gemini 3.7 Flash API
ユーザーの質問に対するSQL動的生成(Text-to-SQL)および意図判定(AI Router)を担当。 - 検証データセット: Spotify模擬ログ(全2,500件)
音楽・ポッドキャスト混在ログ、無料/有料プラン、30秒未満スキップ、ロイヤリティ許諾フラグ等を含むオリジナル(ダミー)検証データ。 - 検証スクリプト: Pythonスクリプト
同一の質問セットに対して4つのアプローチ(素のDDL / Context / Semantic / ハイブリッド)を順次実行し、実際の生成SQLと集計結果を測定。
1. データ構造と検証シナリオ(ERD)
本検証のテーブル設計です。生トランザクション層(raw_*)と集計マート層(fct_*)を分離しています。

2. 課題:マスタにフラグが存在してもLLMが誤る理由
対話型分析エージェントをリリースした場合、多くのエンドユーザーは「content_type = 'music' かつ play_duration_sec >= 30 で絞り込んで」とは指示せず、「再生数TOP5は?」などと質問します。
テーブル定義のみを渡した場合(Pattern A)、Gemini 3.7 Flashは以下の誤ったSQLを生成しました。

DuckDBでの実行結果

誤集計の要因
- 概念と物理の乖離: ポッドキャスト配信者も
raw_artistsに存在するため区別ができない。 - 暗黙ルールの欠如: 「30秒未満のスキップを除外する」という音楽業界の標準ルールはDDLの型からは推測不能。
- フラグ文脈の欠如: ロイヤリティ計算フラグ(
is_rcn)の適用条件をLLMが判断できない。
3. Spotify社内AI「Vedder」の設計思想
Spotifyのエンジニアリングチームが公開したブログ記事[^1] では、70,000超ものデータセットを抱える同社が直面した課題と、なぜ「Context Layer」が必要だったのかが率直に語られています。
1. なぜDDLだけでは破綻するのか?(公式ブログより引用)
*"To solve this problem, we started developing an AI data assistant, but with over 70,000 datasets at Spotify, amounting to petabytes of data, no single individual can claim knowledge of everything. Just putting all schemas into an LLM doesn't work at this scale...
Schemas do not convey all the information. If a column has the INT64 type, then it doesn't say anything about how those less than 100 are legacy test data and how they differ from actual data in terms of definitions or what is meant by 'active user.' ... We needed something in between. A layer that captures what actually matters about a slice of the warehouse, owned by people who own and understand the domain."*
---- Spotify Engineering Blog (2026-06-10) [^1]
2. 過去クエリログの87.5%はノイズだった(公式ブログより引用)
「データサイエンティストが過去に書いたクエリ履歴をLLMに学習させればスケールするのでは?」というアプローチに対し、Spotifyは実際に検証を行いました。
*"During our curation phase, we provided the questions and SQL for actual queries issued against the domain by the data scientists in our data warehouse, and we asked the cluster curators to pick which ones were good examples.
They accepted only 12.5% of the proposed pairs.
The other 87.5% were ad-hoc exploration, debugging sessions, one-off answers no one would ask again, queries that used the wrong table, or queries that were technically correct but taught the wrong pattern. Query history is rich. Most of it is noise. And the signal doesn't label itself."*
---- Spotify Engineering Blog (2026-06-10) [^1]
3. Vedderの主要アーキテクチャ
- 3つのUI: Slack Bot(スレッド質問用)、MCPサーバー(IDE/エージェント用)、専用Web UI(対話探索用)。
- ReActループ: 質問受領 ➔ 関連クラスタ選択 ➔ SQL生成 ➔ ウェアハウス実行 ➔ 回答作成。
- 3層クラスタ:
Datasets: スキーマ、代表値サンプル、パーティション情報。Pairs: ドメイン専門家が承認した12.5%の正統Q&Aお手本ペア。Docs: Gotchas(落とし穴)、用語集、推奨/非推奨カラムの指示。
4. 統合ハイブリッドの要:AI Router の仕組みと実装選択肢
定型KPIのガバナンスと非定型探索の柔軟性を両立するため、手前に AI Router を配置します。

1. フォールバック設計
質問が定義済みメトリクスに直接合致しない場合は、自動的に Context Layer(動的SQL)へ安全にフォールバック します。
2. 本検証(ローカル)での実装:LightweightContextEngine
本検証では、Spotify の社内AI「Vedder」の思想をローカル環境で再現するため、Python クラス LightweightContextEngine を実装しました。
- メタデータの自動抽出: dbt の
schema.yml(meta.business_rules/meta.anti_patterns)やdocsを解析し、ユーザーの質問キーワードに関連するテーブルや業務ルールを動的に検索・抽出します。 - インテリジェントなルーティング:
- 質問が
semantic_models.ymlで定義された定型KPIに合致する場合 ➔ Semantic Layer(確定クエリ) を直接実行。 - 定義外の集計やアドホック探索の場合 ➔ 抽出した業務コンテキストをプロンプトに注入し、Gemini 3.7 Flash に動的SQLを生成 させます。
- 質問が
3. 実務導入での選択肢:dbt-wizard の活用
本検証のようなルーティングやコンテキスト注入を実務の dbt プロジェクトへ導入する場合、ゼロからスクリプトを自作する代わりに dbt-wizard [^10] のようなツールの活用が有効です。
- dbt 定義のダイレクト活用: dbt の
manifest.jsonや YAML 定義(schema.yml/semantic_models.yml)を直接読み込み、dbt で管理されているメタデータやビジネスルールをそのまま LLM のコンテキストとして活用できます。 - 運用保守の効率化: モデル定義やルールの更新が即座に Text-to-SQL の挙動に反映されるため、手動のプロンプトメンテナンスを不要にし、安全でガバナンスの効いたデータ探索環境を構築できます。
4. 主要クラウドDWHにおけるルーターの選択肢
その他にも主要なDWHにおける実現方法は調べた限りでは以下の通りです。
このあたりは進化のスピードがとても速いので、最新の情報は公式ドキュメントをご確認ください。

5. dbtリポジトリでの定義ファイル構成

レイヤー別の役割と設定項目

YAML定義コードスニペット
1. models/schema.yml (Context Layer の業務ルール注入)

2. models/semantic_models.yml (Semantic Layer の比率メトリクス定義)

6. 実践検証:4パターンの精度実測と挙動比較
実測合否判定テーブル

* Q4(公式再生率)における比率計算の留意点:
比率計算の Text-to-SQL では、LLM が「行ごとの比率の単純平均(AVG)」を誤用してしまうリスクが一般に存在します。今回の Pattern B(Context Layer)では LLM が正しくSUM(分子) / SUM(分母)を組み立てて *77.02% の完全正解 を導出できましたが、Pattern C(Semantic Layer)では dbt 上でtype: ratioとして除算式が物理的に固定されるため、LLM の推論揺らぎに頼らない 100% 確実な集計がシステムレベルで保証されます。
【実測エビデンス】全検証パターン(Case 1〜Case 4)のターミナル実行ログキャプチャを表示
1. Case 1: 再生数ランキングTOP5

2. Case 2: プラン別アクティブリスナー数

3. Case 3: Adoのロイヤリティ対象再生数

4. Case 4: アーティスト別の公式再生率(比率計算)

7. なぜ Semantic Layer だと計算ミスが起きないのか?
「LLMにSQLを書かせる方式」と「Semantic Layer」の違いは、SQLを組み立てる主体にあります。

MetricFlow が生成する確定SQLの構造

8. まとめとデータ組織向け導入ロードマップ
セマンティック層とコンテキスト層について、これまでは違いがよく理解できていませんでしたが模擬的な実装を通じて理解が深まりました。
SpotifyのVedderでは。エージェントとの対話を重ねることで継続的にコンテキスト層をアップデートする仕組みも存在すると記載がありましたが、自社のデータ基盤でそれをどう実現するかについても考えていく必要がありそうです。

- Step 1: スタースキーマ(マート層)の整備:
「30秒未満のスキップを除外する」といった音楽配信の標準集計ルールや除外フラグをあらかじめ織り込んだクリーンなマートテーブルを構築する。 - Step 2: 最重要KPIの Semantic Layer 化:
経営指標や比率メトリクスなど、数字のブレが許されないKPIをsemantic_models.ymlに固定する。 - Step 3: 業務暗黙知のメタデータ化と AI Router の配備:
現場特有のGotchas(落とし穴)をschema.ymlのmetaに言語化し、AI Routerで自動分岐(+フォールバック)する体制を整える。
参考文献
- [^1]: Spotify Engineering: Encoding Your Domain Expert: The Context Layer Behind Spotify's Data Assistant (2026-06-10) ---- Spotify社内AI「Vedder」のアーキテクチャ、クラスタ構成、過去クエリ採用率の実態
- [^2]: dbt Documentation: Ratio metrics ---- dbt Semantic Layer / MetricFlow の仕様と比率メトリクス定義
- [^3]: DuckDB: Why DuckDB ---- ローカル実行エンジンとしてのDuckDB仕様
- [^4]: dbt-duckdb GitHub Repository ---- dbt-duckdb アダプターの設定とパイプライン構築
- [^5]: Snowflake Documentation: Cortex Analyst Overview ---- SnowflakeにおけるセマンティックモデルからのSQL確定生成機能
- [^6]: Snowflake Documentation: Cortex Search Overview ---- Snowflakeにおける非構造化ドキュメント・業務ルールのベクトル検索機能
- [^7]: Databricks Documentation: What is Databricks Genie? ---- Unity Catalogのメタデータとメトリクスを活用するAI/BIエージェント機能
- [^8]: Google Cloud Documentation: Write queries with Gemini assistance ---- BigQueryにおけるAIアシスタントおよびメタデータ補完機能
- [^9]: Google Cloud Looker Documentation: What is LookML? ---- Lookerにおけるセマンティックモデリング(LookML)の仕様
- [^10]: dbt Labs Documentation: How dbt Wizard works ---- dbtのプロジェクトメタデータやDAG構造を活用するAIエージェントCLI





