Créer manuellement des modèles dbt est un processus fastidieux qui peut prendre des heures. Si aucune transformation majeure n'est requise, il ne s'agit pas de la partie la plus stimulante du travail des Data Engineers.
Imaginez pouvoir automatiser ce processus dans son intégralité. Dans ce guide pratique, je vous montre précisément comment GitLab Duo Agent Platform peut générer des modèles dbt complets en quelques minutes seulement, avec une structure, des tests et de la documentation.
→ Essayez GitLab Ultimate et GitLab Duo Enterprise gratuitement.
Ce que nous construisons
Notre équipe marketing souhaite gérer et optimiser efficacement ses investissements publicitaires. Reddit étant l'une des plateformes publicitaires utilisées, nous extrayons donc les données de l'API Reddit Ads vers notre plateforme de données d'entreprise Snowflake.
GitLab possède trois couches de stockage :
-
Couche
raw: premier emplacement pour les données non traitées issues de sources externes, elles ne sont pas encore prêtes pour une utilisation métier. -
Couche
prep: première couche de transformation avec les modèles sources, les données ne sont toujours pas prêtes pour une utilisation générale. -
Couche
prod: données finales transformées prêtes pour l'utilisation métier et les rapports Tableau.

Dans ce guide, les données sont déjà dans la couche raw grâce à notre solution d'extraction Fivetran, et nous allons générer les modèles dbt qui gèrent les données de la couche prep jusqu'à la couche prod.
Sans avoir à écrire une seule ligne de code dbt nous-mêmes, nous aurons à la fin de ce guide :
-
Des modèles sources dans la couche
prep -
Des modèles workspace dans la couche
prod -
Des configurations dbt complètes pour les 13 tables (soit 112 colonnes) du jeu de données Reddit Ads
-
Des requêtes de test pour valider les résultats
Le processus complet prendra moins de 10 minutes, comparé aux heures habituellement nécessaires du processus manuel.
Voici les étapes à suivre :
1. Préparer la structure des données
Avant que GitLab Duo ne puisse générer nos modèles, il doit comprendre la structure complète des tables. La clé est d'exécuter une requête sur le schéma d'informations de Snowflake, car nous étudions actuellement comment connecter GitLab Duo via Model Context Protocol (MCP) à notre instance Snowflake :
SELECT
table_name,
column_name,
data_type,
is_nullable,
CASE
WHEN is_nullable = 'NO' THEN 'PRIMARY_KEY'
ELSE NULL
END as key_type
FROM raw.information_schema.columns
WHERE table_schema = 'REDDIT_ADS'
ORDER BY table_name, ordinal_position;
Cette requête contient :
-
Tous les noms de tables et colonnes
-
Les types de données pour une structure de modèle appropriée
-
Les contraintes nullables
-
L'identification des clés primaires (colonnes non-nullables dans ce jeu de données)
Conseil de pro : dans le jeu de données Reddit Ads, toutes les colonnes non-nullables servent de clés primaires, il s'agit là d'un modèle récurrent. Nous avons validé ce modèle en vérifiant des tables comme ad_group, qui possèdent deux colonnes non-nullables (account_id et id) toutes deux marquées comme clés primaires. L'exécution de cette requête a renvoyé 112 lignes de métadonnées que j'ai exportées dans un fichier CSV pour la génération de modèles. Bien que cette étape manuelle fonctionne bien aujourd'hui, nous étudions une intégration directe de GitLab Duo avec notre plateforme de données via MCP pour automatiser entièrement ce processus.
2. Configurer GitLab Duo
Il existe deux façons d'interagir avec GitLab Duo :
-
La fonction chat de l'interface web
-
Le plugin Visual Studio Code
Nous avons choisi le plugin VS Code, car nous pouvons exécuter les modèles dbt localement pour les tester.
3. Entrer le prompt « magique »
Voici le prompt exact que nous avons utilisé pour générer tout le code dbt :
Create dbt models for all the tables in the file structure.csv.
I want to have the source models created, with a filter that dedupes the data based on the primary key. Create these in a new folder reddit_ads.
I want to have workspace models created and store these in the workspace_marketing schema.
Take this MR as example: [I've referenced to previous source implementation]. Here is the same done for Source A, but now it needs to be done for Reddit Ads.
Please check the dbt style guide when creating the code: https://handbook.gitlab.com/handbook/enterprise-data/platform/dbt-guide/
Les éléments essentiels suivants ont garanti l'efficacité du prompt :
-
Des spécifications claires pour les modèles sources et workspace
-
Un exemple de référence d'une merge request similaire précédente
-
Une référence au guide de style pour garantir la qualité et la cohérence du code
-
Un ciblage spécifique du schéma pour une organisation correcte
4. Le processus de GitLab Duo
Après avoir soumis le prompt, GitLab Duo s'est mis au travail. Le processus de génération complet a pris quelques minutes, durant lesquelles GitLab Duo a :
-
Lu et analysé le fichier CSV d'intrant.
-
Examiné les structures des tables à partir des métadonnées.
-
Référencé notre guide de style dbt pour les normes de codage.
-
Pris en compte la merge request similaire pour proposer une structure correcte.
-
Généré les modèles sources pour les 13 tables.
-
Créé les modèles workspace pour les 13 tables.
-
Généré les fichiers dbt complémentaires :
- Configuration
sources.yml - Fichiers
schema.ymlavec tests et documentation - Mise à jour de
dbt_project.ymlavec les références de schéma
- Configuration
Les résultats
Les résultats sont remarquables :
-
1 fichier modifié : dbt_project.yml (ajout de la configuration du schéma reddit_ads)
-
29 nouveaux fichiers :
- 26 modèles dbt (13 sources + 13 workspaces)
- 3 fichiers YAML
-
Près de 900 lignes de code générées automatiquement
-
Tests de données intégrés, avec des contraintes uniques sur les colonnes de clé primaire
-
Descriptions génériques pour tous les modèles et colonnes
-
Logique de déduplication appropriée dans les modèles sources
-
Structure de code propre et cohérente conformément au guide de style GitLab dbt
transform/snowflake-dbt/
├── dbt_project.yml [MODIFIED]
└── models/
├── sources/
│ └── reddit_ads/
│ ├── reddit_ads_ad_group_source.sql [NEW]
│ ├── reddit_ads_ad_source.sql [NEW]
│ ├── reddit_ads_business_account_source.sql [NEW]
│ ├── reddit_ads_campaign_source.sql [NEW]
│ ├── reddit_ads_custom_audience_history_source.sql [NEW]
│ ├── reddit_ads_geolocation_source.sql [NEW]
│ ├── reddit_ads_interest_source.sql [NEW]
│ ├── reddit_ads_targeting_community_source.sql [NEW]
│ ├── reddit_ads_targeting_custom_audience_source.sql [NEW]
│ ├── reddit_ads_targeting_device_source.sql [NEW]
│ ├── reddit_ads_targeting_geolocation_source.sql [NEW]
│ ├── reddit_ads_targeting_interest_source.sql [NEW]
│ ├── reddit_ads_time_zone_source.sql [NEW]
│ ├── schema.yml [NEW]
│ └── sources.yml [NEW]
└── workspaces/
└── workspace_marketing/
└── reddit_ads/
├── schema.yml [NEW]
├── wk_reddit_ads_ad.sql [NEW]
├── wk_reddit_ads_ad_group.sql [NEW]
├── wk_reddit_ads_business_account.sql [NEW]
├── wk_reddit_ads_campaign.sql [NEW]
├── wk_reddit_ads_custom_audience_history.sql [NEW]
├── wk_reddit_ads_geolocation.sql [NEW]
├── wk_reddit_ads_interest.sql [NEW]
├── wk_reddit_ads_targeting_community.sql [NEW]
├── wk_reddit_ads_targeting_custom_audience.sql [NEW]
├── wk_reddit_ads_targeting_device.sql [NEW]
├── wk_reddit_ads_targeting_geolocation.sql [NEW]
├── wk_reddit_ads_targeting_interest.sql [NEW]
└── wk_reddit_ads_time_zone.sql [NEW]
Exemple de code généré
Voici un exemple de la qualité du code généré. Pour la table time_zone, GitLab Duo a créé :
Un modèle source de la couche prep
WITH source AS (
SELECT *
FROM {{ source('reddit_ads','time_zone') }}
QUALIFY ROW_NUMBER() OVER (PARTITION BY id ORDER BY _fivetran_synced DESC) = 1
),
renamed AS (
SELECT
id::VARCHAR AS time_zone_id,
code::VARCHAR AS time_zone_code,
dst_offset::NUMBER AS time_zone_dst_offset,
is_dst_active::BOOLEAN AS is_time_zone_dst_active,
name::VARCHAR AS time_zone_name,
offset::NUMBER AS time_zone_offset,
_fivetran_synced::TIMESTAMP AS fivetran_synced_at
FROM source
)
SELECT * FROM renamed
Schema.yml
models:
- name: reddit_ads_time_zone_source
description: Time zone data from Reddit Ads system
columns:
- name: time_zone_id
description: Unique identifier for time zone records
data_tests:
- unique
- not_null
- name: time_zone_code
description: Code for the time zone
- name: time_zone_dst_offset
description: Daylight saving time offset for the time zone
- name: is_time_zone_dst_active
description: Flag indicating if daylight saving time is active
- name: time_zone_name
description: Name of the time zone
- name: time_zone_offset
description: Offset for the time zone
- name: fivetran_synced_at
description: Timestamp when the record was last synced by Fivetran
Source.yml
sources:
- name: reddit_ads
database: RAW
schema: reddit_ads
loaded_at_field: _fivetran_synced
loader: fivetran
description: Reddit Ads data
quoting:
database: true
schema: false
identifier: false
tables:
- name: time_zone
Modèle workspace
WITH source AS (
SELECT *
FROM {{ ref('reddit_ads_time_zone_source') }}
)
SELECT * FROM source
5. Valider la qualité
Une fois que le code semblait correct, nous avons effectué un push vers la merge request et exécuté le pipeline de test CI pour tester le code et valider les résultats. Nous avons demandé à GitLab Duo de créer une requête de validation :
Create a test query to test the row counts between the raw layer and the workspace layer. Keep in mind that we do deduplication, so we can compare both using distinct on the primary keys.
L'IA a généré une requête de validation complète qui :
-
Compare le nombres de lignes entre les couches
rawet workspace. -
Prend en compte la logique de déduplication.
-
Teste les 13 tables.
-
Calcule les pourcentages de rétention de données.
Requête SQL de test générée
-- Reddit Ads Row Count Validation Test
-- Compares distinct counts between RAW layer and WORKSPACE_MARKETING layer
-- Accounts for deduplication logic in source models
WITH raw_counts AS (
-- Single primary key tables
SELECT 'ad' AS table_name, COUNT(DISTINCT id) AS raw_count
FROM RAW.REDDIT_ADS.AD
UNION ALL
SELECT 'business_account' AS table_name, COUNT(DISTINCT id) AS raw_count
FROM RAW.REDDIT_ADS.BUSINESS_ACCOUNT
UNION ALL
SELECT 'campaign' AS table_name, COUNT(DISTINCT id) AS raw_count
FROM RAW.REDDIT_ADS.CAMPAIGN
UNION ALL
SELECT 'custom_audience_history' AS table_name, COUNT(DISTINCT id) AS raw_count
FROM RAW.REDDIT_ADS.CUSTOM_AUDIENCE_HISTORY
UNION ALL
SELECT 'geolocation' AS table_name, COUNT(DISTINCT id) AS raw_count
FROM RAW.REDDIT_ADS.GEOLOCATION
UNION ALL
SELECT 'interest' AS table_name, COUNT(DISTINCT id) AS raw_count
FROM RAW.REDDIT_ADS.INTEREST
UNION ALL
SELECT 'time_zone' AS table_name, COUNT(DISTINCT id) AS raw_count
FROM RAW.REDDIT_ADS.TIME_ZONE
-- Composite primary key tables
UNION ALL
SELECT 'ad_group' AS table_name, COUNT(DISTINCT CONCAT(account_id, '|', id)) AS raw_count
FROM RAW.REDDIT_ADS.AD_GROUP
UNION ALL
SELECT 'targeting_community' AS table_name, COUNT(DISTINCT CONCAT(ad_group_id, '|', community_id)) AS raw_count
FROM RAW.REDDIT_ADS.TARGETING_COMMUNITY
UNION ALL
SELECT 'targeting_custom_audience' AS table_name, COUNT(DISTINCT CONCAT(ad_group_id, '|', custom_audience_id)) AS raw_count
FROM RAW.REDDIT_ADS.TARGETING_CUSTOM_AUDIENCE
UNION ALL
SELECT 'targeting_device' AS table_name, COUNT(DISTINCT _fivetran_id) AS raw_count
FROM RAW.REDDIT_ADS.TARGETING_DEVICE
UNION ALL
SELECT 'targeting_geolocation' AS table_name, COUNT(DISTINCT CONCAT(ad_group_id, '|', geolocation_id)) AS raw_count
FROM RAW.REDDIT_ADS.TARGETING_GEOLOCATION
UNION ALL
SELECT 'targeting_interest' AS table_name, COUNT(DISTINCT CONCAT(ad_group_id, '|', interest_id)) AS raw_count
FROM RAW.REDDIT_ADS.TARGETING_INTEREST
),
workspace_counts AS (
-- Workspace layer counts using primary keys from schema.yml
SELECT 'ad' AS table_name, COUNT(DISTINCT ad_id) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_AD
UNION ALL
SELECT 'business_account' AS table_name, COUNT(DISTINCT business_account_id) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_BUSINESS_ACCOUNT
UNION ALL
SELECT 'campaign' AS table_name, COUNT(DISTINCT campaign_id) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_CAMPAIGN
UNION ALL
SELECT 'custom_audience_history' AS table_name, COUNT(DISTINCT custom_audience_id) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_CUSTOM_AUDIENCE_HISTORY
UNION ALL
SELECT 'geolocation' AS table_name, COUNT(DISTINCT geolocation_id) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_GEOLOCATION
UNION ALL
SELECT 'interest' AS table_name, COUNT(DISTINCT interest_id) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_INTEREST
UNION ALL
SELECT 'time_zone' AS table_name, COUNT(DISTINCT time_zone_id) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_TIME_ZONE
-- Composite primary key tables
UNION ALL
SELECT 'ad_group' AS table_name, COUNT(DISTINCT CONCAT(ad_group_account_id, '|', ad_group_id)) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_AD_GROUP
UNION ALL
SELECT 'targeting_community' AS table_name, COUNT(DISTINCT CONCAT(targeting_community_ad_group_id, '|', targeting_community_id)) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_TARGETING_COMMUNITY
UNION ALL
SELECT 'targeting_custom_audience' AS table_name, COUNT(DISTINCT CONCAT(targeting_custom_audience_ad_group_id, '|', targeting_custom_audience_id)) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_TARGETING_CUSTOM_AUDIENCE
UNION ALL
SELECT 'targeting_device' AS table_name, COUNT(DISTINCT targeting_device_fivetran_id) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_TARGETING_DEVICE
UNION ALL
SELECT 'targeting_geolocation' AS table_name, COUNT(DISTINCT CONCAT(targeting_geolocation_ad_group_id, '|', targeting_geolocation_id)) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_TARGETING_GEOLOCATION
UNION ALL
SELECT 'targeting_interest' AS table_name, COUNT(DISTINCT CONCAT(targeting_interest_ad_group_id, '|', targeting_interest_id)) AS workspace_count
FROM REDDIT_DBT_MODEL_GENERATION_PROD.WORKSPACE_MARKETING.WK_REDDIT_ADS_TARGETING_INTEREST
)
-- Final comparison with validation results
SELECT
r.table_name,
r.raw_count,
w.workspace_count,
r.raw_count - w.workspace_count AS count_difference,
CASE
WHEN r.raw_count = w.workspace_count THEN '✅ PASS'
WHEN r.raw_count > w.workspace_count THEN '⚠️ RAW > WORKSPACE (Expected due to deduplication)'
ELSE '❌ FAIL - WORKSPACE > RAW (Unexpected)'
END AS validation_status,
ROUND((w.workspace_count::FLOAT / r.raw_count::FLOAT) * 100, 2) AS data_retention_percentage
FROM raw_counts r
JOIN workspace_counts w ON r.table_name = w.table_name
ORDER BY r.table_name;

L'exécution de cette requête a montré :
-
Aucune différence dans le nombre de lignes après déduplication
-
100% de rétention des données sur toutes les tables
-
La réussite de tous les tests
Bilan : gain de temps considérable
-
Approche traditionnelle : 6-8 heures de codage manuel, tests et débogage
-
Approche avec GitLab Duo : 6-8 minutes de génération et temps de revue
L'efficacité des équipes de développement est bien meilleure (de 6-8 heures à 6-8 minutes), et la qualité du code reste élevée.
Bonnes pratiques
Sur la base de cette expérience, voici nos recommandations clés :
Préparez vos métadonnées
-
Extrayez les structures complètes des tables avec les types de données et les contraintes.
-
Identifiez les clés primaires et les relations en amont.
-
Exportez des fichiers CSV d'intrant propres et bien formatés.
Remarque : en connectant GitLab Duo via MCP à vos (méta)données, vous pourriez éviter cette étape manuelle.
Fournissez un contexte clair
-
Indiquez des merge requests existantes à titre d'exemple si possible.
-
Précisez vos normes de codage et guides de style.
-
Explicitez la structure des dossiers et les conventions de nommage.
Validez minutieusement
-
Créez toujours des requêtes de validation pour l'intégrité des données.
-
Testez localement avant de fusionner.
-
Exécutez votre pipeline CI/CD pour détecter tout problème.
Exploitez l'IA pour les tâches de suivi
-
Générez automatiquement des requêtes de test.
-
Créez des templates de documentation.
-
Construisez des scripts de validation.
Prochaines étapes
Cet article montre comment les outils de développement alimentés par l'IA comme GitLab Duo transforment également les workflows d'ingénierie des données. La capacité de générer des centaines de lignes de code prêtes pour la production en quelques minutes, avec tests complets, documentation et structure appropriée, représente un changement fondamental dans notre approche des tâches répétitives.
En exploitant l'IA pour gérer les aspects répétitifs de la création de modèles dbt, les Data Engineers peuvent se concentrer sur des activités à plus forte valeur ajoutée comme la stratégie de modélisation des données, l'optimisation des performances et l'implémentation de la logique métier.
Prêt à essayer par vous-même ? Commencez avec un petit jeu de données, préparez soigneusement vos métadonnées et observez comment GitLab Duo transforme des heures de travail en seulement quelques minutes.
→ Essayez GitLab Ultimate et GitLab Duo Enterprise gratuitement.
