はじめに
DMO(Data Management Office)でデータプラットフォームセクションを担当しています髙橋です。
dbt開発の定型作業を効率化するツールを作成しました。「このSQLをdbtのモデルにして」と指示するだけでモデル作成から関連ファイル生成、Lintチェックまで完了しますし、「このモデルの差分をチェックして」でレグレッションテストも実行できます。
この記事では、ツールの機能紹介と、実装で工夫した点を共有します。
なぜ作ったか
私たちのチームではdbtを使ってデータ変換パイプラインを構築しています。複雑な依存関係を持った大量のモデルを運用しており、依存関係が複雑なほどレグレッションテストは重要ですが、その分手間もかかります。
一方で、ビジネスの要求に素早く応えることも求められます。弊社の行動規範「早いもの勝ち、速いもの価値」にあるように、スピードは重要な価値です。
定型作業を効率化して、本質的なSQLロジックの開発に集中したい。そう考えていましたが、日々の開発で次のような手間がありました。
モデル作成時のルールが多い
私たちのプロジェクトでは様々なルールを定めています。
- ディレクトリ構成: レイヤー分離、モデルごとに関連ファイルを配置
- 命名規則: テーブル・カラムの命名パターン、日本語→英語の変換リストを参照
- SQL規約: CTE構成、sqlfluffルールなど
- テスト: PKのユニーク制約、非null制約など
そのため、SQLを書いた後にschema.ymlやdescription.mdを作成し、sqlfluffでLintをかけて…という作業が毎回発生します。
レグレッションテストが煩雑
モデルを変更したとき、本番環境(prod)と個人開発環境(personal)でデータに差分がないか確認する必要があります。
私たちはdbt-audit-helperとdeferを使っています。
dbt deferは、開発者が編集したモデルだけをビルドできる機能です。上流の親モデルは本番環境のものを参照するため、個人開発環境で全モデルをビルドする必要がありません。dbtの公式ブログでも、大規模プロジェクトでの開発効率化に推奨されている手法です。
# 本番環境のartifactを生成(manifest.jsonとcatalog.jsonが生成される) dbt docs generate --target-path target-base/ -t prod # deferを使って個人開発環境でビルド(上流は本番を参照) dbt run -s my_model --defer --state target-base
dbt-audit-helperは、2つのクエリ結果を比較して差分を検出するマクロ群です。compare_and_classify_query_resultsマクロを使うと、追加・削除・変更されたレコードを分類できます。
{% set old_query %}
select pk_id, week_ver, column_a, column_b
from prod_db.intermediate.int_example_model
{% endset %}
{% set new_query %}
select pk_id, week_ver, column_a, column_b
from dev_db.intermediate.int_example_model
{% endset %}
{{ audit_helper.compare_and_classify_query_results(
old_query,
new_query,
primary_key_columns=['pk_id', 'week_ver'],
columns=['column_a', 'column_b']
) }}
これらを組み合わせて本番環境と個人開発環境を比較していますが、次のように手順が多いです。
- 個人開発環境でモデルを実行
- dbt-audit-helperのマクロを使った比較用のSQLを作成
- dbt runで比較結果のテーブルを生成
- Snowflakeの画面で結果を確認
- 差分をPRに貼り付け(差分が多い場合はサマリ用SQLを別途作成)
比較用のSQLは毎回書く必要がありますし、結果の確認はSnowflakeのUIで行います。差分が多ければサマリ用のSQLを別途書いて、その結果をPRに貼っていました。
解決したかったこと
モデル作成では、規約を意識せずとも自然と規約に沿ったコードが出てきてほしい。レグレッションテストでは、自然言語で指示するだけで比較から結果出力まで完了させたい。
これらが実現できれば、開発者は本質的なSQLロジックの設計に集中できます。
何を作ったか
dbt開発の定型作業を効率化するツールをClaudeのAgent Skillsで作りました。
モデル作成の効率化
「このSQLをdbtモデルに変換して」と指示すると、対話的にモデルを生成します。

ツールは主キー、レイヤー(intermediate/dwh/mart_lookerなど)、タグ、モデル名を確認してきます。プロジェクトのルール(ディレクトリ構成、命名規則、SQL規約など)はガイドに組み込んであるので、回答に応じて次のファイルをまとめて生成します。
- プロジェクトルールに沿ったSQLファイル
- schema.yml(テスト定義、カラム説明)
- description.md(モデルの詳細説明)
最後にsqlfluffでLintチェックも行います。
レグレッションテストの効率化
「このモデルのXXカラムをYYの条件で比較して」と指示すると、dbt-audit-helperを使って比較します。差分が多い場合はサマリを返し、詳細はGoogle Sheetsにエクスポートします。
以下はサマリとGoogle Sheetsエクスポートの例です。PRに貼り付けやすいMarkdown形式で返ってきます。
| FACT_NAME | PROD_SUM | PERSONAL_SUM | DIFFERENCE | |-----------|----------|--------------|------------| | カテゴリA | 215 | 216 | -1 | | カテゴリB | 103 | 111 | -8 | | カテゴリC | 1236 | 1237 | -1 | | 合計 | 1554 | 1564 | -10 | personalの方が各項目で増えています。 詳細: https://docs.google.com/spreadsheets/d/xxx
どうやったか
Agent Skillsの採用
このツールはAgent Skillsとして実装しています。
Agent Skillsの良いところは、Progressive Disclosureの仕組みがある点です。Progressive Disclosureは「必要なときに必要な情報だけを表示する」という考え方です。Agent Skillsでは次のように段階的な読み込みが行われます。
- 起動時: スキルのメタデータ(名前と説明)だけがシステムプロンプトに読み込まれる
- スキル呼び出し時: ユーザーの要求に関連すると判断されたら、詳細な指示(SKILL.md)を読み込む
- 必要に応じて: さらに詳細なガイドやリファレンスファイルを読み込む
この仕組みにより、スキルに含められる情報量は事実上無制限です。数十のリファレンスファイルを用意しても、実際に使われるファイルだけがコンテキストを消費します。
また、Claude CodeのAskUserQuestion機能が非常に便利でした。これはAIエージェントが処理を一時停止してユーザーに入力を求めるためのツールです。
モデル生成時にレイヤーやモデル名をユーザーに選択肢から選ばせたり、自由記述で入力させることができます。一方的にAIが処理を進めるのではなく、対話的にパラメータを収集できるため、「このSQLをdbtモデルにして」という曖昧な指示でも、必要な情報を順番に確認しながら進められます。
ガイドとツールの構成
用途ごとにガイドとツールを用意しました。
ガイド(Markdownファイル)
- モデル生成フロー: SQLからdbtモデルを作成する手順。先述の
AskUserQuestionを使い、レイヤー選択→モデル名確認→PK指定といった対話的なフローを定義している - レグレッションテストフロー: prod/personal比較の手順
- 開発標準ガイド: チームの命名規則やディレクトリ構成
ツール(Pythonで実装)
- モデル情報の取得(テスト定義、カラム、PK、依存関係など)
- データプロファイリング(dbt-profiler連携、カラムのDISTINCT値取得)
- レグレッションテスト(dbt-audit-helper実行、サマライズ、スプレッドシート出力)
manifest.jsonベースの探索
dbtのmanifest.jsonをパースしてローカルで情報を参照する方式にしました。manifest.jsonにはモデルの定義、カラム情報、テスト定義、依存関係がすべて含まれています。
Snowflakeのメタデータからはテーブル構造は取得できますが、dbtの依存関係やテスト定義は取得できません。dbtの情報を使うことで、これらも把握できます。
dbt-profilerによるカラムプロファイリング
データの概要を把握するために、dbt-profilerも活用しています。
dbt-profilerは、各カラムに対して次のような統計情報を取得できます。
- not_null_proportion: NULLでない値の割合
- distinct_proportion: ユニークな値の割合
- min/max: 最小値・最大値(数値、日付型)
- avg: 平均値(数値型)
「このカラムにはどんな値が入っているか」「NULLはどのくらいあるか」といった確認が、SQLを書かずに自然言語で指示するだけで可能になります。
カーディナリティの取得: 特定のカラムにどんな値が入っているか確認したいケースも多いです。「このカラムのDISTINCT値を見せて」と指示すると、SnowflakeにSELECT DISTINCTを実行してユニーク値の一覧を返します。カテゴリ型のカラムでどんな値が使われているか、想定外の値が混入していないかなどの確認に使えます。
dbt-audit-helperとの統合
前述のdbt-audit-helperを使ったレグレッションテストで、手動で行っていた作業を効率化しました。
比較SQLの自動生成: manifest.jsonからPK情報を自動取得し、比較SQLを生成します。私たちのプロジェクトではdbt_constraintsのprimary_keyテストを定義しているため、テスト定義を解析することでPKを特定できます。絞り込み条件や比較軸はプロンプトで指定します。
結果の自動サマライズ: 指定した軸(例:週バージョン、カテゴリなど)ごとにprod/personalのレコード数を集計し、差分を算出します。PRに貼り付けやすいMarkdown形式で返します。
大量データのエクスポート: 結果が1,000件を超える場合は、サマリを返しつつ詳細データをGoogle Sheetsに自動エクスポートします。スプレッドシートのURLが返ってくるので、詳細な確認も容易です。
他のAIエージェントへの対応
ここまでの実装でClaude CodeのAgent Skillsとして動作するツールができました。後日、Cursorなど他のAIエージェントを使うメンバーからも同じ機能が欲しいという要望があり、MCPサーバーとしても提供することにしました。
ただし、MCPの仕様は統一されていても、エージェントごとの実装には差異がありました。たとえばGitHub CopilotはMCPのresourcesに非対応で、CursorやCopilotはinstructionsを読み込まないといった問題がありました。対策として、resourcesで提供していたガイドをtoolに変更し、instructionsに書いていた情報は各ツールの説明文に埋め込むことで対応しました。
Jinjaテンプレートで二重管理を解消
Agent SkillsとMCPの両方に対応したことで、説明文の二重管理が課題になりました。仕様変更時に片方だけ更新して、もう片方を更新し忘れるリスクがあります。
そこで、共通部分をJinjaテンプレート化しました。
{% if mode == "cli" -%}
→ [model-generation-guide.md](model-generation-guide.md) を読む
{%- else -%}
→ `get_model_generation_guide` ツールでガイドを取得
{%- endif %}
Agent Skillsではファイルパスを、MCPではツール呼び出しを出力します。ビルド時に各形式へ展開することで、修正箇所を1箇所に集約できました。ツールのロジック部分もAgent SkillsとMCPで共通のPythonモジュールを使っています。
使ってみて
チームメンバーに使ってもらったところ、好評でした。モデルのカラム変更時にschema.ymlの更新やsqlfluffのチェックを自動でやってくれて助かる、という声がありました。レグレッションテストも、以前は比較SQLを書いてSnowflakeで結果を確認して…という作業に数十分かかることもありましたが、今は「このモデルを比較して」と指示するだけで完了します。
今後の展望
現在は対話的にツールを使う形ですが、将来的にはより自動化を進めたいと考えています。
課題管理ツールから自動でモデルを作成・修正し、レグレッションテストを実行してPull Requestまで生成する。
そんな完全自動化ワークフローの実現を目指しています。
まとめ
dbt開発の定型作業を効率化するツールをClaude CodeのAgent Skillsで作りました。モデル作成では規約に沿ったファイル生成とLintチェックまで、レグレッションテストでは比較からサマリ出力まで、自然言語の指示だけで完了できるようになりました。MCPサーバーとしても提供し、CursorやGitHub Copilotでも使えるようにしています。
同じような課題を抱えている方の参考になれば幸いです。
