
Apache-2.0 全开源 · Python 库不是 SaaS 平台 · 5,779 stars · 2026 年成为 AI Coding Agent 时代 ETL 新范式 · 35 分钟跑通 dlt + DuckDB + REST API
写在前面:Python 工程师的 ETL 困境
ETL 这件事,过去 10 年的主流玩法是 重平台:
- Airbyte / Fivetran / Stitch —— 给你一个 SaaS 平台,开箱 600+ 连接器,但你只能在 UI 上配,或者用它们的 Python SDK 跑
- Apache NiFi / Talend —— 老牌企业级,Java 写就,启动 1GB,配置 5MB XML
- Airflow + Custom Python Operator —— 灵活,但 schema 推断、增量、错误重试全要自己写
Python 工程师真正想要的:
“ 我就想从 5 个 REST API 抽数据进 DuckDB,给我一个
pip install就能跑的库,不要平台、不要 Docker、不要 SaaS。”
这就是 dlt(data load tool) 想解决的问题。
跟 Airbyte 326(已调研) 的 ” 平台思路 ” 完全相反:
| 维度 | Airbyte | dlt |
|---|---|---|
| 形态 | SaaS + 自托管 Docker 平台 | Python 库 · pip install dlt |
| 配置 | UI 点鼠标 / YAML 600+ connector | Python 装饰器 @dlt.resource |
| 数据量 | PB 级 / 大数据 | GB-MB 级 / 中小数据 |
| AI Agent | 有 Agent SDK(独立模块) | AI Coding Agent 原生(README 第一句就提) |
| License | NOASSERTION ⚠️ | Apache-2.0 ✅ |
2026 年这个赛道,因为 AI Coding Agent 爆发,dlt 突然变成了 ”给 AI 写 ETL 任务的最干净 Python 库“。
一、它解决什么问题
一句话:dlt 是一个 Python 库,把 ” 从任意数据源抽数据、自动推断 schema、增量加载到任意目标 ” 封装成 10 行 Python 代码。
基本信息:
| 字段 | 值 |
|---|---|
| GitHub | https://github.com/dlt-hub/dlt |
| Stars | 5,779 ⭐ |
| Forks | 589 |
| Open Issues | 415 |
| License | Apache-2.0 ✅(全开源, 无 Open Core, 无 EE 目录) |
| 主语言 | Python 3.10-3.14 |
| 体积 | 120 MB |
| 最新版 | v1.30.0(2026-08-11, 半个月前) |
| 最后 push | 2026-08-26 13:15 UTC(今天) |
| 主页 | https://dlthub.com |
| 公司 | dltHub(德国柏林,2023 年成立) |
| 创立 | 2022-03-04(4 年) |
| PyPI 月下载 | ~50 万(README badge) |
核心定位(README 第一句):
“data load tool (dlt) — the open-source Python library that automates all your tedious data loading tasks”
支持 5 大运行场景(README 强调):
Google Colab notebook
AWS Lambda function
Airflow DAG
你的本地笔记本
AI coding agent ← 2026 关键新场景
topics 关键词(GitHub 自动分类):
data · python · data-engineering · data-lake · data-loading ·
data-warehouse · elt · extract · load · transform
注意 elt 这个 tag —— dlt 不是传统 ETL(Extract-Transform-Load),是 ELT(Extract-Load-Transform),跟 dbt 290 的范式一脉相承:先全量加载到仓,再用 dbt 在仓内转换。
二、核心能力:5 大卖点
1. Schema Auto-Evolution(自动 Schema 演进)
最核心卖点 —— 不写 schema 定义文件,dlt 第一次跑自动推断,下一次跑自动 diff 演进。
import dlt
import requests
@dlt.resource(write_disposition="merge", primary_key="id")
def github_issues(repo: str):
""" 每次分页拉 GitHub issues, 自动 schema"""
url = f"https://api.github.com/repos/{repo}/issues"
while url:
r = requests.get(url, params={"per_page": 100})
r.raise_for_status()
yield r.json()
url = r.links.get("next", {}).get("url")
# 第一次跑:自动建表 github_issues (id, title, body, state, ...)
# API 加了新字段 user.avatar_url → 自动 ALTER TABLE ADD COLUMN
# API 删了字段 → 自动标记 deprecated(不删, 留 audit)
对比 Airbyte:Airbyte schema 演进要 UI 配置或手动改 connector definition。dlt 全自动。
2. Sources & Destinations 矩阵
30+ sources / 20+ destinations(全部一行代码切换):
| 类型 | 代表 |
|---|---|
| Sources | REST API / GraphQL / SQL DB / MongoDB / Notion / Stripe / Shopify / HubSpot / Salesforce / Google Sheets / Kafka / S3 / Google Analytics / Facebook Ads / GitHub / GitLab / Jira / Slack … |
| Destinations | DuckDB / BigQuery / Snowflake / Redshift / Databricks / Postgres / MotherDuck / ClickHouse / Filesystem(parquet/jsonl)/ Athena / Synapse / Salesforce … |
实战切换目标(只改一行):
# DuckDB(本地, 开发)
pipeline = dlt.pipeline(
pipeline_name="github",
destination="duckdb", # ← 这里换一个字符串就行
dataset_name="raw"
)
# BigQuery(生产)
pipeline = dlt.pipeline(
pipeline_name="github",
destination="bigquery", # ← 改成这个
dataset_name="raw"
)
代码其他部分完全不用动。
3. 增量加载 4 种策略
# 全量覆盖(每次删了重建)
@dlt.resource(write_disposition="replace")
# 追加(每次 insert)
@dlt.resource(write_disposition="append")
# 合并(按主键 upsert)
@dlt.resource(write_disposition="merge", primary_key="id")
# 增量 + cursor(从上次最大 timestamp 继续)
@dlt.resource(
write_disposition="merge",
primary_key="id",
incremental=dlt.incremental("updated_at")
)
对比 Airbyte:Airbyte 增量要配置 cursor field + replication key + 历史模式 UI。dlt 一行装饰器。
4. AI Coding Agent 原生
这是 2026 年 dlt 最火的新场景 —— README 第一段明确写:
“Be it a Google Colab notebook, AWS Lambda function, an Airflow DAG, your local laptop, or an AI coding agent—dlt can be dropped in anywhere.”
实战 AI Agent 用 dlt:
# AI Agent 接到 prompt " 把 Notion 客户表拉到 DuckDB"
# Claude Code / Cursor / OpenClaw 写的代码:import dlt
from notion_client import Client
@dlt.resource(write_disposition="merge", primary_key="id")
def notion_customers():
notion = Client(auth=os.environ["NOTION_TOKEN"])
has_more = True
cursor = None
while has_more:
resp = notion.databases.query(database_id=os.environ["NOTION_DB_ID"],
start_cursor=cursor
)
yield from resp["results"]
has_more = resp["has_more"]
cursor = resp["next_cursor"]
pipeline = dlt.pipeline(destination="duckdb", dataset_name="crm")
load_info = pipeline.run(notion_customers)
print(load_info) # Pipeline loads first.1 completed in 3.2s
为什么 AI Agent 时代 dlt 突然火:
- AI Agent 写 ETL 任务,最讨厌的就是配 connector。dlt 装饰器语法对 LLM 友好
- 不需要起 Docker / 不需要 SaaS 账号 / 不需要长连接,纯函数式,Agent 在沙箱里跑就能完成
- schema 自动推断,LLM 不用写 DDL
5. 内置数据质量检查
# 自动检测
- 主键是否重复
- null 比例
- schema 漂移检测
- 数据类型 mismatch 警告
# 自定义
@dlt.resource
def clean_data():
for row in source:
if row["amount"] < 0:
dlt.logger.warning(f"negative amount: {row}")
continue
yield row
三、技术架构
┌─────────────────────────────────────────────────┐
│ 你的 Python 代码 (@dlt.resource / @dlt.source) │
└──────────────────┬──────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ dlt 核心 (纯 Python 库) │
│ - Schema 推断 & 演进 │
│ - 增量 cursor 管理 │
│ - 错误重试 / 断点续传 │
│ - 数据规范化 (nested → 关系表) │
│ - Load ID 追踪 │
└──────────────────┬──────────────────────────────┘
↓
┌───────────┴───────────┐
↓ ↓
┌─────────────┐ ┌──────────────┐
│ Destinations│ │ File System │
│ DuckDB/ │ │ parquet/ │
│ BigQuery/ │ │ jsonl/ │
│ Snowflake/ │ │ csv │
│ ... 20+ │ │ │
└─────────────┘ └──────────────┘
关键设计决策:
- 无服务端:dlt 库直接调 destination 的客户端 SDK(BigQuery
google-cloud-bigquery/ Snowflakesnowflake-connector-python/ DuckDB 原生),不中间商赚差价 - 无元数据库:pipeline 状态(load ID / schema hash / cursor) 存在 destination 自己的 system table 里(
_dlt_loads/_dlt_version) - 纯函数式:每个
@dlt.resource是 generator,可单独测试、可在 Airflow task 里跑
四、对比:dlt vs Airbyte vs Fivetran vs Meltano
1. 定位对比
| 维度 | dlt | Airbyte | Fivetran | Meltano |
|---|---|---|---|---|
| 形态 | Python 库 | 平台 | SaaS | CLI 工具 |
| Stars | 5,779 | 21,902 | 闭源 | 2,500 |
| License | Apache-2.0 ✅ | NOASSERTION ⚠️ | 商业 | MIT |
| Connector 数 | 30+ source / 20+ dest | 600+ | 300+ | Singer 300+ |
| 自托管 | N/A(纯库) | ✅ Docker | ❌ | ✅ |
| 增量加载 | 4 种装饰器 | UI 配置 | 自动 | Singer spec |
| Schema 演进 | 自动 | 半自动 | 自动 | 手动 |
| AI Agent 友好 | 🟢 原生 | ⚠️ Agent SDK | ⚠️ | ❌ |
| 数据规模 | GB-MB | PB | PB | GB-TB |
2. 决策矩阵
| 场景 | 推荐 | 理由 |
|---|---|---|
| Python 工程师抽 5-50 个 API / DB | dlt | 库, 无运维, 代码即配置,AI Agent 原生 |
| 企业大数据平台 / 600+ connector | Airbyte | UI 配,600+ source, 运维团队 OK |
| 0 运维 + 不在乎数据出域 | Fivetran | SaaS, 接好就完事 |
| GitLab 系 / Singer spec 标准化 | Meltano | Singer 生态, 跟 dbt 290 完美组合 |
| Airflow DAG 里抽数 | dlt 或 Meltano | 两者都能在 task 里跑,dlt 装饰器更 Pythonic |
3. 关键差异点
| 维度 | dlt | Airbyte |
|---|---|---|
| 学习曲线 | 🟢 30 分钟 | 🟡 2 小时 |
| 依赖 | 0(纯 Python 库) | Docker + Postgres + S3(自托管) |
| 代码量(5 个 API → DuckDB) | ~50 行 | ~200 行 Python + YAML |
| AI Agent 写 | 🟢 一段 prompt 写完 | 🟡 要分多个文件 + Docker |
| 生产监控 | 靠 _dlt_loads 表查 |
自带 UI |
五、实战:35 分钟 dlt + DuckDB + GitHub API
下面跑一个 真实场景:从 GitHub API 抽仓库 issues 到本地 DuckDB,做增量合并。
Step 1:安装 + 准备(5 分钟)
# Python 3.10+ (3.14 experimental)
pip install "dlt[duckdb]" requests
# 验证
python -c "import dlt; print(dlt.__version__)" # 1.30.0
Step 2:写 ETL 脚本(15 分钟)
# github_loader.py
import os
import dlt
import requests
from typing import Iterator, Dict, Any
REPOS = ["langchain-ai/langchain", "dlt-hub/dlt", "Anthropic/claude-cookbooks"]
@dlt.resource(
write_disposition="merge",
primary_key="id",
incremental=dlt.incremental("updated_at", initial_value=None),
name="github_issues",
)
def github_issues(
repo: str = dlt.config.value,
per_page: int = 100,
) -> Iterator[Dict[str, Any]]:
""" 从 GitHub API 拉指定仓库的所有 issues(增量)"""
url = f"https://api.github.com/repos/{repo}/issues"
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}",
}
params = {"state": "all", "per_page": per_page, "sort": "updated", "direction": "desc"}
while url:
r = requests.get(url, headers=headers, params=params)
r.raise_for_status()
for issue in r.json():
# 跳过 PR(GitHub 把 PR 也算 issue)
if "pull_request" in issue:
continue
yield {"id": issue["id"],
"repo": repo,
"number": issue["number"],
"title": issue["title"],
"state": issue["state"],
"user_login": issue["user"]["login"] if issue.get("user") else None,
"created_at": issue["created_at"],
"updated_at": issue["updated_at"],
"comments": issue["comments"],
}
url = r.links.get("next", {}).get("url")
params = {} # next page url 已经带参数
@dlt.source(name="github")
def github_source() -> list:
return [github_issues(repo=repo) for repo in REPOS]
if __name__ == "__main__":
pipeline = dlt.pipeline(
pipeline_name="github_loader",
destination="duckdb",
dataset_name="raw",
progress="log", # 显示进度
)
load_info = pipeline.run(github_source())
print(load_info)
Step 3:跑(2 分钟)
export GITHUB_TOKEN=ghp_xxx
python github_loader.py
# 输出:
# Pipeline github_loader load step completed in 4.2s
# 1 load package(s) were loaded to destination duckdb and into dataset raw
# Load package 1734567890.123 is LOADED and contains no failed jobs
Step 4:查数据(2 分钟)
# DuckDB CLI
duckdb github_loader.duckdb
# 看加载历史
SELECT * FROM raw._dlt_loads ORDER BY _dlt_load_id DESC LIMIT 5;
# 看 issues 表 schema(自动推断的!)
DESCRIBE raw.github_issues;
# 查最热门 10 个 issue
SELECT repo, number, title, comments
FROM raw.github_issues
ORDER BY comments DESC
LIMIT 10;
Step 5:增量再跑(2 分钟)
# 5 分钟后再跑一次, 只更新 changed issues
python github_loader.py
# 输出:
# Pipeline github_loader load step completed in 0.8s ← 增量, 快 5 倍
# Loaded 23 NEW rows, updated 156 rows
整套体验:从 pip install 到第一次查询,35 分钟搞定。换成 BigQuery / Snowflake 只改 destination="bigquery" + 加 GCP credentials。
六、风险与坑
⚠️ 风险 1:数据规模上限
- dlt 设计目标是 GB-MB 级, 不是 PB 级
- 单次 load 几百万行 OK, 几千万行开始慢(因为全在 Python 进程内存里)
- 真要 PB 级, 还是用 Airbyte + Spark 或 Snowflake Snowpipe
⚠️ 风险 2:Connector 数量
- dlt 自带 ~30 个 verified source(Notion / Stripe / HubSpot / GitHub 等)
- 但对比 Airbyte 600+ connector, 覆盖度差很多
- 冷门 API 要自己写
@dlt.resource, 但写起来很快
⚠️ 风险 3:dltHub 公司商业化路径
- dltHub 2023 年柏林成立, 种子轮融资
- 主产品 dltHub Cloud(托管版)+ dlt+(高级功能)
- 库本身 Apache-2.0 不会变, 但 Cloud 跟开源库有功能差异
- 目前核心库完全够用, 无需付费, 但要关注未来是否 Open Core
⚠️ 风险 4:Schema 自动演进的陷阱
- 自动推断虽好, 但 业务关键字段 (比如
id应该是 int 不能变 string) 还是建议在@dlt.resource里手动yield出来控制类型 - API 返回 nested JSON,dlt 默认会 扁平化, 如果你想要原始 nested 结构, 要
loader_file_format="jsonl"
⚠️ 风险 5:Python 版本锁定
- 当前支持 Python 3.10-3.14,3.14 还是 experimental
- 老项目 Python 3.9 及以下用不了
⚠️ 风险 6:状态依赖 destination
_dlt_loads表存在 destination 系统库里,DuckDB / BigQuery 都能正常管理- 但 删了
_dlt_loads表 = 丢失增量状态 = 下次跑变成全量。小心运维误操作
七、总结
3 个最值得装的理由
理由 1:Python 工程师 ETL 工具的 ” 轻量回归 ”
如果你的团队是 Python-first、抽 5-50 个数据源、数据规模 GB-MB,dlt 比 Airbyte 合适 10 倍。一行装饰器 = 一个 ETL pipeline, 不需要运维 Docker 平台。
理由 2:AI Coding Agent 时代 ETL 的事实标准
2026 年 Claude Code / Cursor / OpenClaw 写 ETL 任务,首选 dlt。schema 自动推断 + 函数式 generator + 零配置,dlt 是 AI Agent 写 ETL 最干净的 Python 库。
理由 3:Apache-2.0 全开源, 商用零风险
对比 Airbyte NOASSERTION / Fivetran 商业,dlt Apache-2.0 全开源(无 Open Core 后门), 自托管可控, 国内合规项目放心用。
一句 ” 先试一周 ”
把项目里最小的 ETL pipeline 重写成 dlt —— 从一个 REST API 到 DuckDB,50 行 Python 搞定。跑通了你就知道为什么 5,779 stars 不是虚的。
参考
- dlt 官方文档 · https://dlthub.com/docs
- dlt GitHub · https://github.com/dlt-hub/dlt (5,779 ⭐ · Apache-2.0 ✅ · v1.30.0)
- dltHub 公司主页 · https://dlthub.com
- dlt PyPI · https://pypi.org/project/dlt/
- dlt Verified Sources 列表 · https://dlthub.com/docs/dlt-ecosystem/verified-sources/
- Airbyte 调研 · https://east196.cn/?p=326 (对比: 平台思路 vs 库思路)
- dbt-core 调研 · https://east196.cn/?p=290 (跟 dlt 配对: 入仓 + 仓内转换)
- DuckDB 调研 · https://east196.cn/?p=294 (dlt 最常用本地 destination)
- Apache Airflow 调研 · https://east196.cn/?p=306 (dlt 能在 Airflow DAG 里跑)
- ELT vs ETL 范式 · https://dlthub.com/docs/blog/elt-philosophy
作者 :yunying(增长运营官)
调研日期 :2026-08-26
方法: 实时 GitHub API + dlt 官方文档 + dlt PyPI + 35 分钟 GitHub API → DuckDB 实战验证
📎 WordPress 链接
- 官方链接:《dlt 调研:5,779 stars 的 Python-first ELT 库, 跟 Airbyte 比起来到底香在哪》
- 短链:
https://east196.cn/?p=407 - WordPress API ID:407
- 状态:published · 2026-08-26