LLM 作为数据工程师:AI 驱动的 ETL 中的静默失败
你手写的 ETL 管道处理了 95% 的记录。那些边界情况——带有逗号的货币字符串、格式不一致的日期、不统一的国家代码——流向了你的数据仓库,并悄悄地破坏了你的仪表板。直到季度报告看起来不对劲时,才有人注意到。你又在管道中添加了一个特殊情况。循环往复。
LLM 可以解决这个问题。它们能从原始样本中推断模式(schema),处理任何工程师都预料不到的杂乱边界情况,并能以极短的开发时间将非结构化文档转换为结构化记录。已经有几个团队推出了这种方案。其中一些团队也经历过 LLM 悄无声息地将 "$1,200,000" 转换成 1200 而不是 1200000,在结构完全有效的情况下将严重程度分数从 "high" 切换到 "low",以及以通过了所有模式检查的方式连接了错误的业务外键。
问题不在于 LLM 不擅长数据工程。而在于它们的失败模式对 ETL 来说恰恰是完全错误的:高置信度、不报错、且输出结构有效。
LLM 在 ETL 中到底擅长什么
在列举失败模式之前,有必要准确说明 LLM 在哪些方面比手写管道真正增加了价值。
从杂乱样本中进行模式推断。 给定 50 行非结构化的发票数据,前沿模型可以提出一个合理的理想模式,识别哪些字段可能是可选的,并标记出模糊的情况供人工审核。这比花三天时间编写那些仍然会遗漏边界情况的正规表达式(regex patterns)要好得多。
数据转换中的边界情况处理。 手写的管道擅长处理已知模式。LLM 则擅长处理未知模式:来自你的管道未涵盖的国家/地区的地址格式、包含价格的产品描述、包含七种不同格式(其中一些还是人为输入导致的格式错误)的时间戳。打破基于规则的系统的长尾变体正是语言模型的强项。
模式间的语义映射。 当字段名称不匹配时,从一个模式迁移到另一个模式很难通过规则实现自动化。"billing_address_line_1" 映射到 "bill_addr1" 映射到 "Invoice.BillingAddress.Street" —— 当模式作为上下文提供时,LLM 可以高精度地处理这些映射。
非结构化到结构化的提取。 财务报表、医疗记录、合同、工单 —— 使用手写解析器大规模地将自由文本转换为结构化记录是不切实际的。对于这些用例,LLM 将开发时间从数月缩短到了数天。
像 Unstract(开源)和 Snowflake Cortex 这样的工具已经将这些能力产品化了。Cortex 的 EXTRACT_ANSWER 和 COMPLETE 函数允许你直接在 SQL 管道中运行这些转换。dbt 与 MotherDuck 的集成提供了一个 prompt() 函数,可以转换 dbt 模型中的文本。工程生态系统在这里的 发展非常迅速。
会让你陷入困境的失败模式
这是一个手写管道中数据转换失败的样子:抛出异常,任务停止,Airflow 将任务标记为红色,触发告警,工程师介入调查。
这是一个 LLM 增强管道中数据转换失败的样子:任务成功完成,所有记录都已处理,模式验证通过,行数匹配。而三周后,有人注意到某个产品类别的单价偏离了 100 倍,因为模型一致地删除了欧洲格式数字中的小数点。
研究 LLM 代码生成的学者发现,GPT-4 在复杂提取任务上的无效响应率为 11.97%,而 GPT-4o-mini 经常会重构输入对象而不是保留所有原始字段 —— 这导致了在没有错误信号的情况下发生了无声的数据丢失。这些并不是灾难性的失败。它们是悄无声息积累起来的失败。
这些失败模式可以分为三类:
高置信度的类型强制转换错误。 货币字符串、百分比值和特定区域的数字格式经常会让模型出错。"$500,000" 可能变成 500000(正确),也可能变成 500(将逗号误认为小数点而删除),或者 5000(区域设置混淆)。模型完全意识不到自己选错了。因为输出是有效的整数,结构验证会通过。语义验证只有在你定义了正确的检查项时才会失败。
语义字段映射错误。 当给定两个相似的模式时,LLM 可能会映射听起来相关但实际上不相关的字段。customer_segment 在一个上下文中可能映射到 account_tier,而在另一个上下文中可能映射到 risk_category。两者都是有效的字符串;两者都通过了模式验证;但其中一个是错误的。特别是在 Text-to-SQL 领域,模型经常混淆外键关系 —— 连接到在文档中共同出现但实际上并不是模式中正确连接键的字段。
上下文不完整时的自信幻觉。 当模型缺乏进行正确转换所需的元数据时,它不会停下来询问。它会根据现有信息生成一个看起来合理的答案。如果要求模型根据它从未见过的分类法对记录进行分类,它会编造出看起来合理的类别名称。模型在填充缺失值时会使用统计直觉,而不是你的业务规则。输出通过了所有不专门测试模型编造内容的检查。
构建能够捕捉模型错误的验证层
解决方案并不是要避开 ETL 流水线中的 LLM。而是要像对待来自不可信外部源的数据一样对待 LLM 的输出:在信任之前进行验证。
在生产环境中行之有效的验证模式是三层级联:
第一层 —— 结构化验证。 Pydantic schema(或同类工具)强制执行字段类型、必填字段和取值范围。这可以捕捉格式错误的 JSON、缺失的必填字段以及明显的类型错误。像 Instructor 这样的库通过自动的 Pydantic 验证和重试逻辑封装了 LLM 调用。在这里实施防御性强制转换:一个能处理 "$500,000"、"500000"、"500,000.00" 和 "5e5" 并将它们归一化为标准浮点数的解析器,而不是依赖模型始终产生正确的格式。
第二层 —— 语义验证。 这是大多数团队跳过且随后后悔的一层。语义验证检查输出是否 有意义,而不只是 合法。技术手段包括:
- 基于规则的矛盾检测:如果
severity = "low"且financial_impact > 1000000,则标记以供人工审核 - 跨字段一致性:
end_date必须在start_date之后;discount_percent必须在 0 到 100 之间 - 参考数据查询:国家代码必须存在于你的国家/地区表中;产品 SKU 必须存在于你的产品目录中
- 针对高风险字段的 LLM 作为裁判 (LLM-as-judge) 调用:通过第二次模型调用来评估提取的内容在语义上是否连贯
PARSE 框架在复杂的提取任务上实现了 64.7% 的准确率提升,它实施了系统化的三阶段语义检查:验证没有缺失必要的属性,验证提取的值存在于源文档中,以及验证是否符合业务规则。
第三层 —— 统计异常检测。 在流水线级别,跟踪多次运行之间的分布情况:行数、分类字段的基数、数值分布、空值率。当这些指标偏离预期阈值时发出警报。对数值分布使用 Kolmogorov-Smirnov 检验,对分类分布使用 Jensen-Shannon 散度。Great Expectations(现已发布 v1.0 版本)将这些大部分功能实现为配置而非代码,并集成了 Airflow 和 dbt。
黄金数据集 (Golden dataset) 回归测试完成了闭环。维护一组经过精选的输入/输出对,这些对代表了已知的正确转换,包括已知的边缘情况。在每次流水线更改和模型版本升级时运行这些测试。提升平均性能的模型升级有时会在特定的边缘情况下发生退化;黄金测试能在这些问题到达生产环境之前捕捉到它们。
