Nous avons comparé 528 pipelines de données créés par des agents : la création déclarative s'est avérée plus économique, plus rapide et plus légère que le code procédural.
par Lisa Cao et Sudhanva Huruli
Les agents d'IA rédigent désormais une part croissante des pipelines de données de production (plus de 70 % des pipelines SDP sur Databricks sont maintenant créés par des agents), ce qui augmente les enjeux dans deux domaines : (1) chaque tentative d'un agent consomme du temps de calcul et des ressources, les itérations doivent donc être peu coûteuses et efficaces à exécuter ; et (2) la révision du code devient un point de contrôle critique, le code doit donc être concis, lisible et correct. Apache Spark® propose deux modèles de programmation pour concevoir vos pipelines, procédural et déclaratif, et ils diffèrent par ce que vous écrivez, par ce que Spark peut vérifier avant l'exécution, et par le coût d'une erreur. Nous avons évalué les deux approches avec le même agent sur les mêmes tâches, et l'approche déclarative s'est avérée plus sûre, moins coûteuse et plus légère.
Un pipeline procédural est un code qui indique à Spark comment construire chaque jeu de données, étape par étape. La seule façon de savoir s'il fonctionne est de l'exécuter.
Un pipeline déclaratif décrit les jeux de données souhaités et laisse à Spark le soin de décider comment les construire. C'est similaire à lorsque vous formulez une requête auprès d'un LLM, qui détermine ensuite comment procéder (en utilisant les compétences et outils appropriés). Cela s'illustre parfaitement dans le code pour voir comment une simple faute de frappe provoque un échec :
| Procédural | Déclaratif |
bronze = spark.read.parquet(RAW)
bronze.write.saveAsTable("bronze")
silver =
bronze.withColumnRenamed("revenue",
"revenues") # typo
silver.write.saveAsTable("silver")
gold =
spark.read.table("silver").groupBy("revenue")
.sum("revenue")
gold.write.saveAsTable("gold")
# runtime error
| @dp.materialized_view(name="gold")
def gold():
return
spark.read.table("silver").groupBy("revenue")
.sum("revenue") |
Les bugs se présentent sous deux formes. Les bogues structurels que vous pouvez détecter en lisant le pipeline : une référence de colonne non résolue, une table qui n'existe pas encore, une modification de configuration non autorisée. Les bugs silencieux n'apparaissent dans la sortie qu'une fois l'exécution terminée et le résultat erroné.
Un pipeline déclaratif peut être vérifié pour détecter les bogues structurels avant son exécution, de la même manière que le flux de données dans un langage typé comme Rust peut être vérifié au moment de la compilation. Parce qu'un pipeline déclaratif est une description plutôt qu'une exécution, Spark peut répondre à trois types de questions en le lisant :
En PySpark procédural, l'agent de codage IA écrit les opérations de données, telles que le filtrage des lignes non valides et la jointure de tables. Il écrit également le code pour exécuter les étapes du pipeline dans le bon ordre et enregistrer leurs résultats. Ce code de support répète en grande partie le même canevas d'un pipeline à l'autre.
Dans les pipelines déclaratifs, l'agent IA définit chaque jeu de données et la requête qui le produit. Spark gère l'ordre d'exécution et enregistre les résultats. Grâce à Spark qui prend en charge ces tâches répétitives, l'agent écrit moins de code, et l'équipe a moins d'éléments à relire et à maintenir.
Nous avons testé 22 tâches d'ingénierie des données. Chaque tâche ressemblait à un ticket réel : elle décrivait un problème et spécifiait la table, les noms de colonnes et les types de données que le pipeline devait produire. L'agent pouvait choisir n'importe quelle implémentation tant que la sortie correspondait à ces exigences.
Pour chaque tâche, nous avons généré 12 jeux de données d'entrée différents contenant les types de valeurs désordonnées que l'on trouve dans les données de production. L'agent a écrit un nouveau pipeline pour chaque jeu de données en utilisant PySpark procédural, et un autre en utilisant les pipelines déclaratifs Spark. Cela a produit 264 builds par approche et 528 au total : 22 tâches × 12 jeux de données × 2 approches. Tous les builds ont utilisé Opus 4.8.
Nous avons exécuté chaque pipeline et comparé sa sortie avec la table requise. L'évaluateur automatisé ignorait quelle approche avait produit le résultat. Les pipelines déclaratifs ont d'abord fait l'objet d'une exécution à blanc par Spark. Si un build échouait, l'agent pouvait le réviser et réessayer, jusqu'à une limite fixe.
Vous pouvez relancer l'ensemble vous-même depuis le répertoire public : la configuration, les invites, les jeux de données, l'évaluateur et les résultats associés à chaque chiffre.
Les deux approches ont mené à bien la quasi-totalité des tâches, avec 255 sur 264 terminées de manière procédurale et 258 sur 264 de manière déclarative, ce qui signifie que l'une ou l'autre permet d'obtenir un pipeline fonctionnel. Ce qui change, c'est tout le reste : le moment où les erreurs sont apparues, la quantité de code nécessaire pour les corriger et la cohérence du résultat. Nous présentons ci-dessous les trois avantages des pipelines déclaratifs, suivis de deux mises en garde.
1. La validation préalable a rendu les pipelines déclaratifs environ 34 fois plus rapides
Les erreurs d'un pipeline font surface avant l'exécution, pendant l'exécution ou pas du tout. Les pipelines procédurales n'en ont bloqué aucune avant l'exécution, car ils ne possèdent pas de phase pré-exécution. Pour trouver une erreur structurelle, Spark a dû exécuter le pipeline sur un cluster jusqu'à ce qu'il atteigne l'étape défectueuse.
Parmi les builds mesurés, les exécutions procédurales ont consommé 596 secondes d'exécuteurs, contre 17 pour les exécutions déclaratives. La validation par simulation du code déclaratif a détecté les erreurs structurelles en amont et réduit le temps de calcul par 34.

2. Le code des pipelines déclaratifs représentait la moitié de la taille des pipelines procéduraux
Parmi les builds terminés, les pipelines déclaratifs étaient environ deux fois plus petits, avec une médiane de 64 lignes contre 131 pour les pipelines procéduraux.
Les implémentations procédurales présentaient également une plus grande variabilité. Pour la même tâche, certaines utilisaient des transformations Spark tandis que d'autres chargeaient les données en mémoire et les traitaient ligne par ligne. Les deux ont validé les données de test, mais la version en mémoire peut échouer lorsque le volume de données augmente. Sur l'ensemble du benchmark, 19 builds procéduraux ont eu recours à ce raccourci. Aucun build déclaratif ne l'a fait.
Un code plus court et plus cohérent offre à l'équipe moins d'éléments à examiner et un modèle unique à maintenir.

3. En matière d'erreurs logiques, les deux approches se valent
Ce sont les deux avantages. Lors de l'exécution des tests, nous avons également identifié deux réserves.
Premièrement, une exécution à blanc ne peut détecter que les erreurs structurelles. Elle ne peut pas repérer une erreur silencieuse : un pipeline qui s'exécute proprement et renvoie un résultat erroné, ce qui représente le type d'erreur le plus dangereux. Sur ce point, les deux approches étaient à égalité : leurs taux d'erreurs silencieuses présentaient un écart d'environ 15 % l'une par rapport à l'autre, une différence trop faible pour être significative. L'approche déclarative permet de détecter facilement les erreurs structurelles, mais elle ne résout rien en ce qui concerne la logique, qui nécessite toujours des tests et une révision.
4. L'approche déclarative investit davantage au début pour économiser davantage par la suite
L'approche déclarative investit davantage à un endroit précis. L'agent itère sur l'exécution à blanc, effectuant des essais jusqu'à ce que le pipeline soit correct, ce qui l'amène à concentrer sa réflexion en amont sous forme de jetons plutôt que de découvrir des problèmes sur un cluster par la suite. Les jetons représentent une dépense fixe et unique, payée lors de la rédaction du pipeline ; le montant ne varie pas en fonction du volume de vos données ni de la fréquence d'exécution du pipeline. Le calcul de cluster gaspillé est l'exact opposé : il se reproduit à chaque exécution incorrecte et augmente avec les données, de sorte que plus vous traitez d'informations, plus un mauvais build coûte cher. Payer un coût fixe au départ pour en éviter un qui ne cesse de croître s'avère d'autant plus judicieux que vos pipelines et vos volumes de données grandissent.
L'ensemble complet des différences mesurées est présenté ci-dessous.
| Dimension | PySpark procédural | Déclaratif (SDP) |
| Ce que produit l'agent | Du code qui s'exécute | Une description qui est vérifiée |
| Erreurs structurelles | Apparaissent en cours d'exécution, après des écritures partielles, ou jamais ; aucune n'est arrêtée avant la sortie | Détectées lors de l'exécution à blanc ; 55 sur 264 arrêtées avant toute sortie |
| Coût | Temps de cluster : ~34x plus élevé (jusqu'à ~521 secondes d'exécuteur sur une exécution échouée) Jetons LLM : de référence | Temps de cluster : de référence (~0,5 seconde d'exécuteur sur une exécution échouée) Jetons LLM : ~2,3x (build médian ≈ 0,50 $ contre 0,26 $, tarifs publics Opus 4.8) |
| Taille du code | de référence | Lignes de code : ~51 % en moins (médiane) Taille AST : ~44 % plus petite |
| Bugs silencieux (exécutés proprement, mauvais résultat) | 73 sur 264 (27,7 %) | 85 sur 264 (32,2 %) |
À l'échelle de la production, l'approche déclarative s'impose. Elle coûte environ 2,3 fois plus cher en tokens LLM, mais en contrepartie, elle ne gaspille jamais de temps de cluster sur un pipeline qui n'allait de toute façon pas fonctionner. À l'échelle de la production, l'approche déclarative s'avère avantageuse en troquant des coûts de tokens LLM légèrement plus élevés contre la prévention garantie du gaspillage de temps de cluster sur des pipelines défaillants. Cela devient de plus en plus rentable à mesure que les volumes de données augmentent, car le gaspillage de calcul croît proportionnellement tandis que les coûts de tokens restent constants.
Si vous êtes en train d'évaluer des agents pour le travail de pipeline, accordez autant d'importance à la manière dont l'agent écrit qu'au choix de l'agent. Un meilleur agent fait moins d'erreurs ; un pipeline déclaratif rend les erreurs peu coûteuses et les détecte avant qu'elles n'aient d'impact financier.
Le répertoire documente la conception, les données et la provenance complète. Pour démarrer avec vos agents en utilisant Spark Declarative Pipelines, consultez le guide de programmation officiel et utilisez la compétence SDP avec PySpark.
Dois-je faire confiance à l'agent IA pour que cela fonctionne ?
Non, et ne pas avoir à le faire est tout l'intérêt. L'agent déclaratif se contente d'écrire du code de pipeline déclaratif — une description des tables qu'il souhaite — et Spark vérifie lui-même cette description avant toute exécution. Le vérificateur fait partie de la plateforme : vous faites confiance à l'évaluation du pipeline par Spark, et non au modèle. L'agent n'exécute jamais de code et ne lit jamais vos données lui-même.
Cela concerne-t-il uniquement Spark Declarative Pipelines, ou est-ce plus général ?
Cela s'applique plus largement aux approches déclaratives : partout où vous pouvez séparer "voici ce que je veux" de "maintenant, va le construire", afin que la première partie puisse être vérifiée de manière indépendante. On retrouve la même structure en SQL, dans les outils d'infrastructure en tant que code et dans les API privilégiant les schémas. Spark Declarative Pipelines est celle que nous avons testée, mais le raisonnement reste valable pour tout outil conçu de cette façon.
L'agent déclaratif utilise 2,3 fois plus de tokens. N'est-ce pas un problème résolutoire ?
Pas pour des tailles de pipeline réalistes. Le facteur 2,3 représente environ 0,50 $ en tokens par construction déclarative médiane, contre 0,26 $ pour la procédurale, aux tarifs publics d'Opus 4.8. Une exécution procédurale ayant échoué a consommé environ 521 executor-seconds, tandis qu'une exécution déclarative rejetée a coûté environ une demi-seconde. Par conséquent, éviter quelques exécitations infructueuses compense largement les tokens supplémentaires, et l'écart ne fait que se creuser à mesure que les volumes de données augmentent. Les prix des tokens fluctuent également selon le service de modèle utilisé, tandis que les coûts de calcul sont plus stables et plus faciles à budgétiser.
(Cet article de blog a été traduit à l'aide d'outils basés sur l'intelligence artificielle) Article original
Abonnez-vous à notre blog et recevez les derniers articles directement dans votre boîte mail.