返回

为Agent而建:Spark声明式管道的价值

RSS Databricks Blog AI 逐段翻译 发布 2026-10-24 03:00

有效阅读仅保存在当前浏览器,用于「为你」推荐;暂停或清除记录。

DataHot 速览

Databricks 官方博客指出,其 SDP 管道中已有超过 70% 由 AI Agent 创建。文章比较 Apache Spark 的过程式与声明式两种管道编写模型:过程式需运行后才能发现问题,声明式先描述目标数据集,Spark 可在运行前做结构校验。作者用同一 Agent、同一批任务做基准测试,结论是声明式管道更安全、成本更低且更精简。

为什么值得关注:随着 Agent 参与生产数据管道,声明式管道可通过运行前校验降低试错成本和代码评审负担;对使用 Databricks/Spark 构建数据平台的团队有直接参考价值。

本文目录 6 节
  1. 1. 声明式管道可以在运行前进行验证
  2. 2. 声明式管道将样板任务卸载给 Spark
  3. 我们测试的内容
  4. 结果
  5. 我们测量的所有项目,并排对比
  6. 结论

译文

AI 逐段翻译

AI 智能体现在编写着越来越多的生产数据管道(在 Databricks 上,超过 70% 的 SDP 管道现在由智能体创建),这在两个方面提高了风险:(1) 智能体的每次尝试都会消耗计算资源和时间,因此迭代需要运行得廉价且高效;(2) 代码审查成为关键关口,因此代码需要简洁、可读且正确。Apache Spark® 提供两种编程模型来编写管道:过程式和声明式,它们在编写内容、Spark 在运行前能检查什么,以及错误的代价有多大方面有所不同。我们用同一个智能体在相同任务上对两者进行了基准测试,声明式的结果更安全、更便宜、更精简。

过程式管道是告诉 Spark 如何一步步构建每个数据集的代码。判断它是否有效的唯一方法就是运行它。

声明式管道描述你想要的数据集,让 Spark 决定如何构建它们。这类似于你向 LLM 发出提示,由它来弄清楚如何执行(通过使用正确的技能和工具)。用代码最能说明一个简单的拼写错误会如何导致失败:

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")
过程式声明式

1. 声明式管道可以在运行前进行验证

缺陷分为两类。结构性缺陷可以通过阅读管道发现:未解析的列引用、尚不存在的表、不允许的配置更改。静默缺陷只有在运行结束且答案错误时才会在输出中显现。

声明式管道可以在运行前检查结构性缺陷,类似于在 Rust 等类型化语言中数据流可以在编译时被检查。由于声明式管道是一种描述而非一次运行,Spark 可以通过阅读它来回答三类问题:

  • 每个列引用都会根据其读取的数据集的模式进行解析,因此不存在的列会被拒绝,而不是在运行时失败。
  • 数据集之间的每个依赖关系都会与图中的生产者匹配,因此对没有任何声明者的表的引用会在管道启动前被捕获。
  • 图会被检查完整性和顺序,因此由引擎决定何时运行什么,而不是信任模型碰巧编写时的顺序。

2. 声明式管道将样板任务卸载给 Spark

在过程式 PySpark 中,AI 编码智能体编写数据操作,例如过滤无效行和连接表。它还编写代码来按正确顺序运行管道的各个步骤并保存其结果。这些辅助代码在不同管道之间重复了许多相同的样板内容。

在声明式管道中,AI 智能体定义每个数据集以及生成它的查询。Spark 处理执行顺序并保存结果。由于 Spark 处理这些样板内容,智能体编写的代码更少,团队需要审查和维护的内容也更少。

我们测试的内容

我们测试了 22 个数据工程任务。每个任务看起来像一张真实的工单:它描述了一个问题,并指定了管道必须生成的表、列名和数据类型。智能体可以选择任何实现,只要输出符合这些要求。

对于每个任务,我们生成了 12 个不同的输入数据集,包含生产数据中常见的那种混乱值。智能体为每个数据集使用过程式 PySpark 编写了一个新管道,并使用 Spark 声明式管道编写了另一个。这样每种方法产生 264 次构建,总共 528 次:22 个任务 × 12 个数据集 × 2 种方法。所有构建都使用了 Opus 4.8。

我们运行每个管道,并根据所需的表检查其输出。自动评分器不知道结果是哪种方法产生的。声明式管道首先经过 Spark 的试运行。如果构建失败,智能体可以修改它并重试,直到达到固定上限。

你可以从公共仓库自行重新运行整个流程:设置、提示、数据集、评分器,以及每个数字背后的结果。

结果

两种方式几乎完成了所有任务,过程式完成了 264 个中的 255 个,声明式完成了 264 个中的 258 个,因此任何一种都能让你得到可工作的管道。不同的是围绕它的一切:错误何时显现、修复需要多少代码,以及输出有多一致。下面我们介绍声明式管道的三个优势,然后是两个注意事项。

1. 运行前验证使声明式管道的时间减少约 34 倍

管道的错误会在执行前、运行期间或根本不显现。过程式管道在执行前没有发现任何错误,因为它们没有执行前阶段。要发现结构性错误,Spark 必须在集群上运行管道,直到到达出错的那一步。

在我们测量的构建中,过程式运行使用了 596 个执行器秒,而声明式运行仅使用了 17 个。对声明式代码的试运行验证及早捕获了结构性错误,并将计算量减少了 34 倍。

过程式管道

2. 声明式管道代码的规模是过程式管道的一半

在已完成的构建中,声明式管道的规模约为一半,中位数为 64 行,而过程式管道为 131 行。

过程式实现的变化也更大。对于同一任务,有些使用了 Spark 转换,而另一些则将数据加载到内存中并逐行处理。两者在测试数据上都通过了,但内存版本在数据增长时可能会失败。在整个基准测试中,19 次过程式构建使用了这种捷径。声明式构建没有一次这样做。

更短、更一致的代码让团队需要审查的内容更少,只需维护一种模式。

3. 在逻辑错误上,两者水平相当

以上就是两个优势。在运行测试时,我们还发现了两个注意事项。

首先,试运行只能发现结构性错误。它无法发现无声错误:即管道运行正常却返回错误答案,这是更危险的一类。在这一点上,两者不相上下:它们的无声错误率彼此相差约15%以内,差距太小,不构成真正的差异。声明式方法让结构性错误的发现成本很低;它对逻辑毫无帮助,逻辑仍然需要测试和审查。

4. 声明式前期投入更多,后期节省更多

声明式在一处的花费更多。智能体会在试运行上反复迭代,直到管道健全,因此它把更多思考放在前期以 token 形式完成,而不是之后在集群上发现问题。token 是固定的一次性支出,在编写管道时支付;其数量不随你的数据规模或管道运行频率而变化。浪费的集群计算则相反:它会在每一次糟糕的运行中反复出现,并随数据增长而增长,因此你处理的数据越多,一次糟糕构建的代价就越大。前期支付固定成本以避免一项不断增长的成本,只有当你的管道和数据变得更大时,才显得更划算。

我们测量的所有项目,并排对比

完整的测量差异如下所示。

维度过程式 PySpark声明式(SDP)
智能体产出什么能运行的代码会被检查的描述
结构性错误在运行中途、部分写入之后才暴露,或者从不暴露;没有任何一项在输出前被阻止在试运行时被捕获;264 项中有 55 项在任何输出之前被阻止
成本集群时间: 约高 34 倍(一次失败运行最高约 521 执行器秒)LLM token: 基线集群时间: 基线(一次失败运行约 0.5 执行器秒)LLM token:约 2.3 倍(构建中位数约 $0.50 对 $0.26,Opus 4.8 标价)
代码大小基线代码行数:约少 51%(中位数)AST 大小:约小 44%
无声错误(运行正常,答案错误)264 项中有 73 项(27.7%)264 项中有 85 项(32.2%)

结论

在生产规模下,声明式方法胜出。它在 LLM token 上的成本约高 2.3 倍,作为交换,它从不在一个注定无法工作的管道上花费集群时间。在生产规模下,声明式方法通过以略高的 LLM token 成本换取对失败管道浪费集群时间的保证性预防,证明其具有优势。随着数据量扩展,这变得越发具有成本效益,因为计算浪费按比例增长,而 token 成本保持不变。

如果你在评估用于管道工作的智能体,请像认真对待选择哪个智能体一样,认真对待智能体如何编写。更好的智能体犯更少的错误;声明式管道让错误的代价很低,并在它们产生任何代价之前将其捕获。

该仓库记录了设计、数据和完整的来源信息。要使用 Spark 声明式管道开始使用你的智能体,请参阅 官方编程指南 并使用 SDP 技能 配合 PySpark。

这篇内容对你有用吗?

反馈只用于改善内容筛选,不等同于收藏

分享这条资讯
分享海报
保存图片
iOS 也可以长按图片保存