Abbiamo testato 528 pipeline di dati create da agenti: la creazione dichiarativa si è dimostrata più economica, veloce e leggera rispetto al codice procedurale.
di Lisa Cao e Sudhanva Huruli
Gli agenti di intelligenza artificiale scrivono ora una quota crescente di data pipeline di produzione (oltre il 70% delle pipeline SDP su Databricks viene ora creato da agenti), il che aumenta la posta in gioco in due aree: (1) ogni tentativo effettuato da un agente costa risorse di calcolo e tempo, quindi le iterazioni devono essere economiche ed efficienti da eseguire; e (2) la revisione del codice diventa un passaggio critico, quindi il codice deve essere sintetico, leggibile e corretto. Apache Spark® offre due modelli di programmazione per creare le tue pipeline, procedurale e dichiarativo, e differiscono in ciò che scrivi, in ciò che Spark può controllare prima dell'esecuzione e nel costo di un errore. Abbiamo eseguito dei benchmark su entrambi con lo stesso agente sugli stessi job, e l'approccio dichiarativo si è rivelato più sicuro, economico e snello.
Una pipeline procedurale è un codice che spiega a Spark come costruire ogni dataset, passo dopo passo. L'unico modo per sapere se funziona è eseguirla.
Una pipeline dichiarativa descrive i dataset desiderati e lascia a Spark il compito di decidere come Eseguire la costruzione. Questo è simile a quando fai un prompt a un LLM e questo capisce come farlo (usando le giuste competenze e strumenti). Questo è illustrato al meglio nel codice per vedere come un semplice errore di battitura causerà un errore:
| Procedurale | Dichiarativo |
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") |
I bug si presentano in due forme. Quelli strutturali che puoi individuare leggendo la pipeline: un riferimento di colonna irrisolto, una tabella che non esiste ancora, una modifica di configurazione non consentita. Quelli silenziosi compaiono nell'output solo al termine dell'esecuzione e con un risultato errato.
Una pipeline dichiarativa può essere controllata per individuare bug strutturali prima dell'esecuzione, in modo simile a come il flusso di dati in un linguaggio tipizzato come Rust può essere controllato in fase di compilazione. Poiché una pipeline dichiarativa è una descrizione piuttosto che un'esecuzione, Spark può rispondere a tre tipi di domande leggendola:
In PySpark procedurale, l'agente di coding IA scrive le operazioni sui dati, come il filtraggio delle righe non valide e il join delle tabelle. Scrive anche il codice per eseguire i passaggi della pipeline nell'ordine corretto e salvarne i risultati. Questo codice di supporto ripete gran parte dello stesso boilerplate tra le pipeline.
Nelle pipeline dichiarative, l'agente IA definisce ogni dataset e la query che lo produce. Spark gestisce l'ordine di esecuzione e salva i risultati. Con Spark che gestisce quel boilerplate, l'agente scrive meno codice e il team ha meno da rivedere e mantenere.
Abbiamo testato 22 attività di data engineering. Ciascuna attività assomigliava a un ticket reale: descriveva un problema e specificava la tabella, i nomi delle colonne e i tipi di dati che la pipeline doveva produrre. L'agente poteva scegliere qualsiasi implementazione purché l'output corrispondesse a tali requisiti.
Per ciascuna attività, abbiamo generato 12 dataset di input differenti con i tipi di valori disordinati che si trovano nei dati di produzione. L'agente ha scritto una nuova pipeline per ogni dataset utilizzando PySpark procedurale e un'altra utilizzando Spark Declarative Pipelines. Ciò ha prodotto 264 build per approccio e 528 in totale: 22 attività × 12 dataset × 2 approcci. Tutte le build hanno utilizzato Opus 4.8.
Abbiamo eseguito ogni pipeline e controllato il suo output rispetto alla tabella richiesta. Il valutatore automatizzato non sapeva quale approccio avesse prodotto il risultato. Le pipeline dichiarative sono state prima sottoposte al dry run di Spark. Se una build falliva, l'agente poteva correggerla e riprovare, fino a un limite fisso.
Puoi rieseguire l'intero processo da solo dal repository pubblico: la configurazione, i prompt, i dataset, il valutatore e i risultati alla base di ogni numero.
Entrambi i metodi hanno completato quasi tutte le attività, con 255 su 264 completate in modo procedurale e 258 su 264 completate in modo dichiarativo, quindi entrambi ti portano a una pipeline funzionante. Ciò che differisce è tutto ciò che sta intorno: quando sono emersi gli errori, quanto codice ci è voluto per risolverli e quanto è stato coerente l'output. Di seguito esaminiamo i tre vantaggi delle pipeline dichiarative, seguiti da due avvertenze.
1. La convalida prima dell'esecuzione ha reso le pipeline dichiarative circa 34 volte più veloci
Gli errori di una pipeline emergono prima dell'esecuzione, durante un'esecuzione o per niente. Le pipeline procedurali non ne hanno bloccato alcuno prima dell'esecuzione perché non hanno una fase di pre-esecuzione. Per trovare un errore strutturale, Spark ha dovuto eseguire la pipeline su un cluster fino a raggiungere il passaggio interrotto.
Tra le build che abbiamo misurato, le esecuzioni procedurali hanno utilizzato 596 executor-secondi, rispetto ai 17 delle esecuzioni dichiarative. La convalida dry-run del codice dichiarativo ha intercettato tempestivamente gli errori strutturali e ha ridotto il calcolo di 34 volte.

2. Il codice della pipeline dichiarativa era la metà delle dimensioni delle pipeline procedurali
Tra le build completate, le pipeline dichiarative erano circa della metà delle dimensioni, con una mediana di 64 righe rispetto alle 131 delle pipeline procedurali.
Anche le implementazioni procedurali variavano maggiormente. Per lo stesso job, alcune utilizzavano trasformazioni Spark, mentre altre caricavano i dati in memoria ed li elaboravano una riga alla volta. Entrambe hanno superato i test sui dati, ma la versione in-memory può fallire quando i dati crescono. In tutto il benchmark, 19 build procedurali hanno utilizzato questa scorciatoia. Nessuna delle build dichiarative lo ha fatto.
Un codice più corto e coerente offre a un team meno lavoro di revisione e un unico modello da mantenere.

3. Sugli errori di logica, i due approcci si equivalgono
Questi sono i due vantaggi. Durante l'esecuzione dei test, abbiamo anche identificato due avvertenze.
Innanzitutto, un dry run può cogliere solo errori strutturali. Non può individuare un errore silenzioso: una pipeline che viene eseguita correttamente e restituisce il risultato sbagliato, che è il tipo più pericoloso. A questo proposito, i due approcci sono alla pari: i loro tassi di errori silenziosi rientravano all'incirca nel 15% l'uno dell'altro, un divario troppo piccolo per rappresentare una differenza reale. L'approccio dichiarativo rende gli errori strutturali facili ed economici da intercettare; non fa nulla per la logica, che richiede comunque test e revisione.
4. L'approccio dichiarativo spende di più in anticipo per risparmiare di più in seguito
L'approccio dichiarativo spende di più in un punto. L'agente esegue iterazioni sul dry run, riprovando finché la pipeline non è solida, quindi effettua gran parte del suo ragionamento in token in anticipo anziché scoprire problemi su un cluster in un secondo momento. I token rappresentano una spesa fissa, una tantum, pagata mentre la pipeline viene scritta; l'importo non cambia in base alle dimensioni dei dati o alla frequenza di esecuzione della pipeline. Il calcolo sprecato del cluster è l'opposto: si ripete a ogni esecuzione errata e cresce con i dati, quindi più elabori, più una build errata costa. Pagare un costo fisso in anticipo per evitarne uno che continua a crescere appare sempre più conveniente man mano che le pipeline e i dati crescono.
L'insieme completo delle differenze misurate è mostrato di seguito.
| Dimensione | PySpark procedurale | Dichiarativo (SDP) |
| Cosa produce l'agente | Codice che viene eseguito | Una descrizione che viene controllata |
| Errori strutturali | Emergono a metà esecuzione, dopo scritture parziali o mai; nessuno viene bloccato prima dell'output | Intercettati al dry run; 55 su 264 bloccati prima di qualsiasi output |
| Costo | Tempo del cluster: ~34x superiore (fino a ~521 executor-secondi su un'esecuzione fallita) Token LLM: baseline | Tempo del cluster: baseline (~0,5 executor-secondi su un'esecuzione fallita) Token LLM: ~2,3x (build mediana ≈ $0,50 contro $0,26, tariffe di listino Opus 4.8) |
| Dimensioni del codice | baseline | Righe di codice: ~51% in meno (mediana) Dimensioni AST: ~44% inferiori |
| Bug silenziosi (eseguiti correttamente, risposta errata) | 73 su 264 (27,7%) | 85 su 264 (32,2%) |
Su scala di produzione, l'approccio dichiarativo risulta vincente. Costa circa 2,3 volte di più in token LLM, ma in cambio non spreca mai tempo di cluster su una pipeline destinata a fallire. Su scala di produzione, l'approccio dichiarativo si dimostra vantaggioso poiché scambia costi leggermente superiori dei token LLM con la prevenzione garantita di tempo di cluster sprecato su pipeline difettose. Questo diventa sempre più conveniente man mano che i volumi di dati crescono, poiché lo spreco di risorse di calcolo aumenta in modo proporzionale mentre i costi dei token rimangono costanti.
Se stai valutando agenti per la gestione delle pipeline, considera il modo in cui l'agente scrive con la stessa attenzione con cui scegli l'agente. Un agente migliore commette meno errori; una pipeline dichiarativa rende gli errori economici e li intercetta prima che abbiano un costo.
Il repository documenta la progettazione, i dati e la provenienza completa. Per iniziare a usare i tuoi agenti con Spark Declarative Pipelines, fai riferimento alla guida di programmazione ufficiale e usa la SDP skill con PySpark.
Devo fidarmi dell'agente di intelligenza artificiale affinché funzioni?
No, e il punto è proprio non doverlo fare. L'agente dichiarativo scrive solo codice di pipeline dichiarativo — una descrizione delle tabelle che desidera — ed è Spark stesso a verificare tale descrizione prima dell'esecuzione. Il sistema di controllo fa parte della piattaforma: ti fidi della valutazione di Spark sulla pipeline, non del modello. L'agente non esegue mai codice né legge direttamente i tuoi dati.
Questo riguarda solo Spark Declarative Pipelines o si applica in modo più ampio?
Si applica in modo più ampio agli approcci dichiarativi: ovunque tu possa separare "ecco cosa voglio" da "ora vai a costruirlo", in modo che la prima parte possa essere verificata autonomamente. Ritrovi la stessa struttura in SQL, negli strumenti di infrastructure-as-code e nelle API schema-first. Spark Declarative Pipelines è quello che abbiamo utilizzato per i nostri benchmark, ma il ragionamento vale per qualsiasi strumento progettato in questo modo.
L'agente dichiarativo usa 2,3 volte i token. Non è un problema insormontabile?
Non con dimensioni di pipeline realistiche. Il fattore 2,3 corrisponde a circa 0,50$ in token per una build dichiarativa mediana, rispetto a 0,26$ per quella procedurale, secondo le tariffe di listino di Opus 4.8. Una singola esecuzione procedurale fallita ha bruciato circa 521 executor-seconds, mentre una dichiarativa rifiutata è costata circa mezzo secondo: evitare quindi pochi tentativi falliti compensa ampiamente i token extra, e il divario non fa che aumentare con la crescita dei volumi di dati. I prezzi dei token variano inoltre a seconda del servizio di modelli utilizzato, mentre i costi di calcolo sono più stabili e facili da pianificare.
(Questo post sul blog è stato tradotto utilizzando strumenti basati sull'intelligenza artificiale) Post originale
Iscriviti al nostro blog e ricevi gli ultimi articoli direttamente nella tua casella di posta.