Date de la publication : 27 octobre 2025

Lecture : 12 min

Comment GitLab Duo Agent Platform révolutionne le DataOps

Découvrez comment transformer des heures de codage manuel en quelques minutes avec ce guide complet de création de modèles dbt.

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 :

  1. 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.

  2. 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.

  3. Couche prod : données finales transformées prêtes pour l'utilisation métier et les rapports Tableau.

Schéma des couches de stockage

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 :

  1. La fonction chat de l'interface web

  2. 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 :

  1. Lu et analysé le fichier CSV d'intrant.

  2. Examiné les structures des tables à partir des métadonnées.

  3. Référencé notre guide de style dbt pour les normes de codage.

  4. Pris en compte la merge request similaire pour proposer une structure correcte.

  5. Généré les modèles sources pour les 13 tables.

  6. Créé les modèles workspace pour les 13 tables.

  7. Généré les fichiers dbt complémentaires :

    • Configuration sources.yml
    • Fichiers schema.yml avec tests et documentation
    • Mise à jour de dbt_project.yml avec les références de schéma

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 raw et 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;

Tableau des résultats de la requête

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.

Pour aller plus loin

Votre avis nous intéresse

Cet article de blog vous a plu ou vous avez des questions ou des commentaires ? Partagez vos réflexions en créant un sujet dans le forum de la communauté GitLab.
Share your feedback

Plus de 50 % des entreprises du classement Fortune 100 font confiance à GitLab

Commencez à livrer des logiciels de meilleurs qualité plus rapidement

Découvrez comment la plateforme DevSecOps intelligente

peut aider votre équipe.