第4部分. 环境:Qwen Code, dbt, DuckDB
环境应当是本地的、可复现的,并且足够小,使学生能够看清 SDD 循环,而不是与基础设施作斗争。因此在教学路线中使用 Python、DuckDB、dbt-core 和 dbt-duckdb。
最低要求
- Python 3.11+;
venv;- 带
bash的 shell; - Qwen Code CLI 或兼容的代理工具;
- 对本地仓库的访问权限。
检查:
python3 --version
python3 -m venv /tmp/sdd-data-check
. /tmp/sdd-data-check/bin/activate
pip --version
示例安装
cd book3/examples/bank-lakehouse
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
bash smoke_all.sh
完整的 smoke 运行应生成 raw/seeds,执行 dbt parse 和 dbt build。如果未安装 dbt,备用模式仅检查结构。这是部分检查,而不是教材已就绪的证明。
为什么选择 DuckDB
DuckDB 能够在没有外部服务的情况下展示 SQL、类型、聚合、dbt 测试和本地存储。这使错误的代价更低。如果 revoked_at 为空且类型转换失败,学生会在 source/staging 契约中看到问题,而不是在集群设置中。
DuckDB 不能替代生产环境。它替代的是第一个教学环境。在本地理解了粒度、PII 策略和契约之后,同样的模式可以迁移到 Trino、Spark、Databricks 或 Snowflake。
代理设置
示例中包含 AGENTS.md 和 .qwen/commands/sdd/。在修改任何模型之前,代理必须阅读:
AGENTS.md;specs/mission.md;specs/tech-stack.md;- 所需的 ODCS/ODPS;
- 所需的模型规范;
- 验证事实。
不要以「修复 dbt」开始。要以「将错误与契约对比,并指出违反了哪条事实」开始。
为读者拆解
本书中的本地环境有意保持简约。这并不是要假装生产环境很简单。相反:采用小规模栈是为了把教学错误与基础设施噪声区分开。当 dbt build 在空日期上失败时,读者应当看到 staging 和契约中的问题,而不是去排查集群、密钥、权限、目录和网络策略。
DuckDB 之所以有用,正是因为它像是一个实验室。它与分析引擎足够相似,可以展示类型、聚合、物化和测试。同时它又足够贴近,学生可以删除数据库、重新构建数据,并再次得到相同的结果。这种可复现性比「真正的」平台的感觉更重要。如果第一个教学环境无法在本地复现,那么迁移到 Iceberg 或 Spark 只会增加随机差异的新原因。
独立的 venv 也是纪律的一部分。它划定了示例的边界:这里有工具版本,这里有安装命令,这里有检查命令。当依赖版本被更新时,应当通过 smoke 运行来验证,而不是依赖「latest」这一名称。对于教材来说这尤其重要:读者复制命令,如果命令出错,他不仅不再信任环境,也不再信任流程。
最后,环境确立了对代理的正确态度。当 dbt 无法运行时,代理不应收到「修复一切」的命令。首先要弄清是哪条边界被破坏:依赖未安装、原始数据缺失、staging 对空值的处理有误、契约与模型不匹配。环境越小,就越容易学会这种诊断方法。
实践
在两种模式下运行 smoke_all.sh:不激活 venv 时,以及在安装依赖之后。记录哪种模式是部分的、哪种是完整的,以及哪些输出行能证明 dbt build 成功。
最少产出
学完本章后,你应当具备:
- 本地安装的环境;
- 成功运行或被如实记录的
smoke_all.sh; - 理解哪种检查模式是完整的、哪种是部分的;
- 关于 specs、models、tests 和评审产物所在位置的笔记。
典型错误
忽略备用的 smoke 运行。「结构和数据生成检查已通过」并不意味着 dbt 模型是正确的。这仅检查示例可以被打开并生成 raw 文件。
思考题
- 为什么在第一遍时本地 DuckDB 比生产集群更有用?
- 部分 smoke 与完整 smoke 的区别是什么?
- 在修改 mart 之前,代理应阅读哪些文件?