Built for Agents: The Case for Spark Declarative Pipelines
TL;DR · AI 摘要
Built for Agents: The Case for Spark Declarative Pipelines Databricks Blog Skip to main content Engineering October 23,...
核心要点
- 主题聚焦:Built for Agents: The Case for Spark Declarative
- 来源:Databricks,建议结合原文判断细节。
- AI 分析暂不可用,本条为保底评分与摘要。
为代理而生:Spark 声明式管道的必要性 | Databricks 博客
跳转到主要内容
工程
2026年10月23日
为代理而生:Spark 声明式管道的必要性
我们对528个由代理构建的数据管道进行了基准测试——声明式编写方式在成本、速度和效率上都优于过程式代码。
作者:Lisa Cao 和 Sudhanva Huruli
摘要
- 过程式管道消耗了大约34倍的计算时间,主要是因为结构无效的声明式管道中的错误可以通过低成本的“干运行”检测到,而无需完全执行。
- 对于相同的管道,声明式管道的代码量减少了51%,因此需要阅读和审查的内容大幅减少。
- 综合来看,这些效率优势使声明式框架(如SDP)成为自主代理构建生产级管道时的明确架构选择。
如今,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") # 拼写错误
silver.write.saveAsTable("silver")
gold =
spark.read.table("silver").groupBy("revenue")
.sum("revenue")
gold.write.saveAsTable("gold")
# 运行时错误@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 的 dry run 验证。如果构建失败,代理可以在固定次数内修改后重新尝试。
你可以从公共仓库重新运行整个测试:包括设置、提示词、数据集、评分系统和所有数字背后的结果。
结果
两种方式几乎都能完成所有任务,其中过程式方法完成了 264 次中的 255 次,声明式方法完成了 264 次中的 258 次。因此,任一方式都能构建出可用的管道。差异在于其他方面:错误出现的时机、修复所需代码量以及输出一致性。下面我们将介绍声明式管道的三大优势,然后说明两个注意事项。
- 预执行验证使声明式管道耗时减少约 34 倍
管道的错误可能在执行前、执行过程中或完全不显现。过程式管道由于没有预执行阶段,执行前无法发现任何错误。要发现结构性错误,Spark 必须在集群上运行管道直到遇到故障步骤。
在我们测量的构建中,过程式运行消耗了 596 个执行器秒,而声明式运行仅消耗 17 个执行器秒。声明式代码的 dry run 验证能提前发现结构性错误,计算资源消耗减少了 34 倍。
- 声明式管道代码量仅为过程式管道的一半
在完成的构建中,声明式管道的代码量约为过程式管道的一半,中位数为 64 行,而过程式管道为 131 行。
过程式实现的代码差异也更大。对于相同任务,一些使用 Spark 转换操作,另一些则将数据加载到内存中逐行处理。两者在测试数据上都能通过,但内存处理方式在数据量增大时可能失败。在基准测试中,有 19 个过程式构建使用了这种快捷方式,而声明式构建中没有使用。
更短且更一致的代码减少了团队需要审查的内容,也只需维护一种模式。
- 关于逻辑错误,两者表现相当
以上是两个优势。在运行测试时,我们也发现了两个需要注意的地方。
首先,干运行只能发现结构性错误。它无法发现静默错误:一种流水线运行顺畅但返回错误答案的更危险类型。在这一点上,两者表现相当:它们的静默错误率彼此之间差距在15%以内,这种差距不足以构成真正的差异。声明式方法使结构性错误更容易被发现;但它对逻辑错误无能为力,逻辑错误仍然需要测试和人工审查。
- 声明式方法前期投入更多以换取后期节省
声明式方法在某个方面投入更多。代理会反复迭代干运行,直到流水线稳定,因此它会在前期消耗更多token进行思考,而不是在集群上后期发现问题。这些token是固定的一次性支出,在编写流水线时支付;支出金额不会因数据量大小或流水线运行频率而改变。浪费的集群计算资源则相反:每次运行失败都会重复发生,并随数据量增长而增加,因此处理的数据越多,失败构建的成本越高。前期支付固定成本以避免持续增长的成本,随着流水线和数据规模扩大,这种策略的优势会愈发明显。
#### 我们并排测量的所有指标
下方展示了所有测量差异的完整列表。
维度
过程式 PySpark
声明式(SDP)
代理生成内容
可运行的代码
一个被检查的描述
结构性错误
在部分写入后或运行中途或从未出现;没有在输出前被阻止的错误
在干运行时被发现;264个中有55个在任何输出前被阻止
成本
集群时间:失败运行时高约34倍(最高达约521个执行者秒)
LLM token:基准值
集群时间:基准值(失败运行时约0.5个执行者秒)
LLM token:高约2.3倍(中位数构建约0.50美元 vs 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配合。
常见问题
我必须信任AI代理才能让这工作吗?
不需要,这正是关键所在。声明式代理只生成声明式流水线代码——它想要的表的描述——而Spark本身会在任何运行前检查这个描述。检查器是平台的一部分:你信任的是Spark对流水线的评估,而不是模型。代理本身不会运行代码或读取你的数据。
这仅适用于 Spark 声明式管道,还是更广泛地适用于其他场景?
它更广泛地适用于声明式方法:在任何可以将“我想要什么”与“现在去构建它”分离的地方,前者可以独立进行验证。你可以在 SQL 本身、基础设施即代码工具以及基于模式的 API 中看到相同的模式。我们测试的是 Spark 声明式管道,但这种推理方式适用于所有采用类似构建方式的工具。
声明式代理使用的 token 数量是 2.3 倍。这不会成为阻碍因素吗?
在真实规模的流水线场景中不会。以 Opus 4.8 的计费标准计算,声明式构建的 token 成本约为 0.5 美元,而过程式构建仅需 0.26 美元。一次失败的过程式运行会消耗约 521 个执行器秒,而被拒绝的声明式构建仅消耗约 0.5 秒——避免几次失败运行就能抵消大量额外 token 成本,且随着数据量增长,两者差距会进一步扩大。token 价格会根据使用的模型服务波动,而计算成本则更稳定且更容易规划。
相关标签:
数据工程与开源
订阅最新文章
订阅我们的博客,获取最新文章直接发送到你的邮箱。
立即订阅
查看所有博客文章
slice-start id="_gatsby-scripts-1"
slice-end id="_gatsby-scripts-1"