
“ai-engineering-from-scratch”这个标题第一眼看上去很像一个 GitHub 仓库的名字但它其实概括了我过去几年里反复在做的一件事把一个 AI 想法从 Notebook 实验变成一套稳定、可维护、能迭代的工程系统。很多人以为 AI 工程的核心是模型算法真正推进之后才发现算法只占很小一块剩下的全是数据、版本、可复现、部署、监控这些不那么性感的工程问题。这篇文章我想用实际做项目的顺序把踩过的坑和沉淀下来的流程整理出来给正准备从零搭建 AI 工程体系的朋友一份可以照着做的参考。适合谁看一类是算法工程师发现模型在离线的时候指标不错一上真实流量就乱套另一类是后端或全栈工程师想转入 AI 方向却被一堆工具选型搞得晕头转向。下面内容会尽量少讲空泛概念多给具体操作和判断依据。毕竟 AI Engineering 这件事光靠“会训练模型”是撑不起来的。1. 先搞清楚“从零开始”到底是从哪个零开始1.1 AI 工程不是“训练模型”的升级版我见过太多团队把“AI 工程化”误解成“把训练脚本写得更规范一点”结果照样在线上出事故。AI Engineering 的核心不是某一个模型有多强而是你用什么方式让模型的能力稳定地转化为产品价值。这里的“稳定”包括三个维度结果可复现、过程可追踪、风险可控制。可复现意味着同一份代码、同一份数据不管跑多少次、在谁的环境里跑结果都应该一样。可追踪意味着每一次实验用了什么数据、什么参数、什么评估集都有记录三个月后还能回答“当时那个 86% 的准确率是怎么来的”。风险可控制则是指模型上线前能预判问题上线后能发现问题坏了能回滚。这三个维度没有一条靠“模型调参”能解决。它们需要的是版本管理意识、数据流水线的严谨设计、实验记录的习惯以及一套线上监控的兜底机制。如果你只想着把准确率从 86% 提到 87%而工程基础是零那 87% 上线后大概率连 80% 都保不住。1.2 从零开始不是“重造轮子”而是“选对轮子”很多人一听到“from scratch”第一反应是一切自己写。我劝你冷静。在 AI 工程领域现成的开源工具已经覆盖了 95% 的通用需求你要做的是根据项目规模选型而不是从零造一套实验管理平台。我自己踩过的最大误区就是早期每个项目都自己写实验记录脚本、自己写模型配置文件解析器结果维护成本比模型训练还高。后来我总结出一个判断标准如果某个工具解决的问题与你业务的核心竞争力无关那就不要自己造直接使用成熟方案。选型时只看三点——社区活跃度、周边生态是否兼容、团队是否真的会用。比如实验追踪用 MLflow 或 TensorBoard数据版本用 DVC部署用 FastAPI Docker这些选择不是因为他多高级而是因为它们已经过大量项目检验遇到问题能搜索到方案。真正的“从零开始”应该是指你从零搭建一套适合自己业务的工程流程而不是从零实现基础设施。2. 先搭骨架项目目录、数据与版本的基础设计2.1 项目目录规划让仓库本身成为流程图一个标准的 AI 工程仓库结构上要能让新人走进来之后不用看文档就能明白数据从哪里来、代码怎么跑、模型产物在哪。我常用的目录结构大概是这样的project_root/ ├── configs/ # 所有实验配置YAML 或 JSON │ ├── baseline.yaml │ └── v2_embedding.yaml ├── data/ │ ├── raw/ # 原始数据不可修改 │ ├── processed/ # 清洗后的特征文件 │ └── external/ # 外部公开数据 ├── src/ │ ├── data_processing/ # 数据清洗、切分、特征工程 │ ├── train/ # 训练入口、损失函数、模型定义 │ ├── evaluate/ # 离线评测脚本 │ └── serve/ # 推理服务、请求校验 ├── notebooks/ # 探索性实验不进生产 ├── models/ # 模型产物配合版本号 ├── reports/ # 实验报表、badcase 分析 └── scripts/ # 运维脚本、数据质检脚本这个结构的好处是强制分离了“一次性探索”和“生产逻辑”。Notebook 只放在 notebooks 目录里业务代码必须在 src 下否则测试、审计、复用都无从谈起。我见过很多团队把探索代码和线上代码混在一起最后每次上线都是“手动提心吊胆”这就是目录混乱的代价。配置文件的组织也很有讲究。我强烈建议所有超参、数据路径、模型输出目录都放到外部 YAML 配置里而不是硬编码在 Python 脚本中。这样每次实验只需要新增一个配置文件而不是改一段代码实验的可追溯性会强很多。2.2 数据版本管理DVC 与数据清单的组合数据不像代码代码有 Git 管着数据文件动辄几个 G直接塞 Git 不现实。我常用 DVC 做数据版本管理核心思路是数据文件存在本地或云存储里DVC 只记录文件的元信息和哈希值再把这些元信息纳入 Git 管理。具体操作上我会先建一个data/raw目录把原始数据放进去然后执行dvc init dvc add data/raw git add data/raw.dvc .gitignore git commit -m track raw dataset version 1之后每次数据更新同样在 Git 里生成新的.dvc文件。这样每一份数据都有了版本号训练时把数据版本号、代码 commit hash、配置文件名放在一起记录任何一个实验报出来都能精确定位到“代码数据配置”的三元组。仅有 DVC 还不够我还会在每个数据目录下维护一个DATASET.md或数据清单文件记录数据来源、业务口径、清洗规则、已知问题。因为 AI 项目里最可怕的不是模型跑崩而是三个月后没人说得清线上那个推荐模型到底吃的是哪一份用户行为数据。2.3 数据集质量检查清单数据质量是 AI 工程的隐形地基但它恰恰是最容易被低估的一环。我给自己定了条规矩任何数据进入训练流程之前必须先跑一遍质检脚本不通过就禁止启动训练。质检脚本至少包含这几项缺失率检查核心字段缺失比例超过阈值直接阻断并告警。分布稳定性检查连续特征均值、分位数和离散特征频次相对于上一个版本不能出现超过设定阈值的跳变。异常值检查比如用户年龄出现 9999、金额出现负数需要标记或过滤。重复样本检查训练集和验证集之间不允许有泄漏样本 ID 重复必须亮红灯。这个清单看起来简单但它救过我很多次。有一次业务方直接替换了上游数据表导致某个关键特征的缺失率从 0.2% 飙到 40%训练出来的模型在验证集上崩得惨不忍睹。如果没有质检脚本阻止训练等到模型上线才发现后果就是真实用户的体验严重受损。3. 模型训练与实验管理让每一次尝试都算数3.1 实验追踪的基础设施先跑通 MLflow 再说开始大规模训练后你会立刻感受到实验记录的压力今天调了学习率明天换了特征组合后天改了一版模型结构三天后再看已经忘了哪个实验对应哪个结果。这时候就需要实验追踪工具。我选择用 MLflow至少在项目早期它最省事。部署方式非常简单本地起一个 tracking server 就够了mlflow server --host 0.0.0.0 --port 5000然后训练脚本里把关键指标和参数通过mlflow.log_param和mlflow.log_metric记下来模型文件用mlflow.log_artifact保存。一组实验跑完在 MLflow 的 UI 里就能看到不同超参对应的指标曲线和模型产物线上部署时也能直接找到记录。注意实验追踪工具的意义不只是“多了一个图表页面”它更大的价值在于强制你规范实验操作。比如团队规定每次训练都必须从同一个入口脚本开始、必须记录 commit hash 和数据版本号这样三个月后有人问“线上这个模型怎么来的”你能直接给出一个可回放的实验 ID。3.2 训练代码的工程化改造从脚本变成框架训练代码工程化的核心是把“可运行的脚本”改造成“可配置、可测试、可扩展的任务”。我一般会把训练流程拆成四个模块数据加载、模型构建、训练循环、评估逻辑。每个模块独立成类或函数用配置文件驱动衔接。以 PyTorch 为例一个规范的训练入口大致长这样def train(config: Dict[str, Any]) - None: dataset create_dataset(config[data]) model create_model(config[model]) optimizer build_optimizer(model, config[optimizer]) trainer Trainer(model, optimizer, config[training]) trainer.fit(dataset.train_loader, dataset.valid_loader) evaluate(model, dataset.test_loader, config[evaluation])这段代码看起来简单但背后体现的是边界清晰数据、模型、训练、评估四个部分互不侵入。这样做的好处是当你需要换一个模型结构时只需要改配置文件和create_model函数而不是把训练循环整个重写。训练回调机制也非常重要。回调可以理解成“训练过程中的钩子”你可以用它实现学习率衰减、早停、梯度裁剪、指标记录等功能。工程化的团队会把这些逻辑统一封装好避免每个实验者在训练循环里加一堆临时逻辑导致代码不可维护。3.3 超参调优从手工到半自动刚起步的项目手工调参就够了因为试错成本低。但一旦模型训练一次需要几小时手工调参的效率就会低到这个大模型不换几次就等项目结束的感觉。这时候就可以引入简单的自动调参工具比如 Optuna 或 Ray Tune。我建议先做“半自动调参”固定几个绝对核心的参数比如学习率、批量大小、优化器用 Optuna 做随机搜索或贝叶斯搜索其他参数暂时保持默认。调参过程一定要和实验追踪配合因为 Optuna 只是生成参数组合真正判断结果好坏、记录训练过程还得靠 MLflow。还有一点经验超参搜索不只是“找一个最大分数”而是要找对噪声鲁棒的区域。即参数在小范围变化时性能不能剧烈波动。一个在特定参数点上很高分、但换个种子就大跌的配置不是好配置。这种稳定性判断需要调参工具和多个随机种子的实验共同支撑。4. 评估与选型离线评测怎么做才不骗人4.1 评估集构造与划分原则模型评估是整个 AI 工程里最容易被骂“自欺欺人”的环节。很多人习惯把数据随机切分成 80% 训练、20% 测试然后跑出准确率就完事。这种做法在真实业务里常常失真因为业务数据的采样不是随机的时间窗口、用户分布、商品分布都可能偏移。我常用的做法是按时间切分训练集用过去 30 天验证集用接下来 3 天测试集用最后 3 天。这样更贴近“用历史预测未来”的真实场景。如果数据里存在强相关性的分组比如同一个用户的多条行为记录还要按组划分避免同组样本同时在训练集和测试集里出现导致评估指标虚高。评估集最好固化下来形成“金标准”数据集每次模型迭代都用同一份测试集做对比。否则你很难判断这次效果提升是因为模型真的变好了还是评估集被污染了。4.2 指标选择模型指标要翻译成业务语言离线指标不能只看准确率。准确率高线上可能依然一团糟因为如果你的业务是“判断用户是否点击”正负样本比例严重失衡一个全输出“不点击”的模型也能有很高的准确率。所以我会根据业务目标选择一组互补指标。比如二分类任务常用 Precision、Recall、F1、AUC排序任务还要看 NDCG、MAP。更重要的是要把这些模型指标翻译成业务指标。举个例子一个反欺诈模型离线提升召回率 2%真实业务里可能是少追回几十万损失一个点击率模型AUC 提升 0.5%实际流量里也许就有几个点的收入变化。建议在每次评估报告里同时写清楚模型指标和预期业务影响。这样评审时老板和业务同学也能直观理解这个模型值不值得上。4.3 模型对比与回归测试模型迭代不是只比较两个指标而是一组实验的横向对比。我习惯每次迭代都建立一个对比表格至少包含模型名称、训练数据版本、关键超参、核心指标、badcase 数量。这样你能看清每个改动带来了什么影响。回归测试也很重要。模型上线之前一定要用一批历史 badcase 和真实请求做回归测试确认新的模型没有在某些特定场景下退化。我在实践里遇到过两种情况一是模型平均指标涨了但某个小众类型全部预测错二是加了一个特征后部分用户群体的收入预测有明显偏移。没有回归测试这类问题往往要等到线上监控发出异常才能发现成本高得多。5. 部署上线从 Notebook 到稳定服务的最后一公里5.1 模型打包与推理服务示例模型训练完成后最常被忽视的是部署环节。很多团队会选择一个 Jupyter Notebook 里跑推理这在 demo 阶段行但真实线上服务绝不可能这样。标准做法是把模型打包成一个可通过 HTTP 调用推理的服务保证每次调用有清晰的输入输出和异常处理。我常用的服务框架是 FastAPI配一个简单的模型加载类。大致结构是这样的from fastapi import FastAPI from pydantic import BaseModel app FastAPI() model load_model(models/model_v2.bin) class PredictRequest(BaseModel): feature_a: float feature_b: float app.post(/predict) def predict(req: PredictRequest): pred model.predict([[req.feature_a, req.feature_b]]) return {score: float(pred[0])}这还不够真正线上服务必须考虑三个问题请求字段校验、模型版本兼容性、异常兜底。比如线上特征缺失时不能直接让请求报错而应该返回一个默认值或标记异常由上层业务决定如何处理。我在部署里吃过亏一度因为某个特征为空值导致整个推理服务 500 崩溃回滚后第一件事就是把异常兜底机制补上。5.2 性能优化批处理、缓存与动态 Batching模型推理性能优化有很多层。最基础的是把加载模型放在进程启动时完成而不是每次请求都从磁盘重新加载。更进一步可以利用动态 batching把短时间内的多个请求合并成一个 batch 输入模型充分利用 GPU 的并行能力。具体来说常用的工具是 Triton 或 TorchServe。以 TorchServe 为例它内置了 dynamic batching 功能你只需要配置一个最大 batch 大小和等待时间。比如空闲等 5 毫秒凑满 8 个请求或 100 毫秒就推理一次。这样可以显著提高吞吐同时控制延迟。延迟和吞吐之间永远是平衡。我自己做压测的时候通常先设定业务容忍的最大 P99 延迟比如 100 毫秒然后在这个约束下尽可能调大 batch直到吞吐不再明显提升。这里要特别记录压测环境的数据不能拿开发机的数字去推算生产环境因为 CPU、内存、网络差异很大。5.3 灰度发布、回滚与压测上线模型时别一把梭全量替换。即使离线指标再好线上真实流量的表现都可能不同。我的标准流程是先做 Shadow 模式影子流量把真实请求同时发给新模型和旧模型但线上仍采用旧模型的结果只记录新模型的表现。影子模式跑几天确认差异不大后再开放 5% 的真实流量给新模型观察核心业务指标和监控指标。如果一切正常逐步扩大范围 20%、50%、100%。这个过程不需要手动操作可以写在 CI/CD 流水线里配合控制变量。模型服务的回滚也不像普通服务那样简单因为模型有版本兼容性问题。回滚之前必须确认旧模型对应的特征处理逻辑还能用、依赖的数据表还在。所以我在每次模型发布时都会保留一份完整的“发布清单”包括模型版本、特征代码版本、配置版本这样回滚才能做到一键。6. 上线后的监控与数据闭环6.1 监控指标延迟、错误率、数据漂移模型上线不是终点而是监控的起点。我见过太多项目离线花几个月把模型训好上线第一周效果不错一个月后业务方突然反映不对结果谁也不知道什么时候开始崩的。原因就是没有做持续监控。线上监控分三层。第一层是服务健康包括请求延迟、QPS、错误率这是传统 SRE 已经覆盖的。第二层是模型行为包括预测分数的均值、分位数、分布形态如果某天预测分数分布突然左移或右移说明输入数据的特征分布可能变了。第三层是业务指标比如点击率、转化率、留存率等这些指标波动往往是模型问题的最终表现。我通常会在服务端把每次请求的特征和预测分数记录成结构化日志然后再用定时任务汇总成指标。这样一个小时级别的数据漂移告警就能做出来。比如设置告警条件特征 A 的均值偏移超过 3 倍标准差或者预测分数均值较昨日变化超过 5%就触发通知。6.2 数据漂移检测与告警模型会过期本质上是线上数据分布在变化。数据漂移检测是 AI 工程里必不可少的一环。常用方法有两类一是逐特征监控分布比如连续特征用 KS 检验或 PSI离散特征用卡方检验二是整体监控模型预测的分布变化直接用预测分数分布做对比。PSI群体稳定性指标相对容易理解它衡量的是两个分布之间的差异阈值一般取 0.1 以内稳定0.1 到 0.25 需要关注超过 0.25 则显著漂移。我自己实践时会分别计算每个特征的 PSI再综合到告警规则里从而快速定位到底是哪个特征变了。注意漂移不一定是坏事也可能是业务正常变化。例如“双十一”期间用户行为模式大变此时漂移告警会响但这是预期内的。所以告警设计要结合业务日历给不同时间段设定不同的基线避免无意义的告警轰炸否则团队会变得麻木。6.3 数据回流与主动学习监控发现问题之后需要尽快把反馈转化为新的训练数据否则模型会持续恶化。数据回流的本质是把线上用户反馈、人工标注、业务结果存入数据仓库作为下一轮训练的增量数据。一个有效的数据闭环流程是线上数据记录 - 自动抽样筛选 - 人工标注 - 质检入库 - 重新训练。筛选样本时不能随机抽而应该让“怀疑错的样本”有更高概率被抽到。这可以用主动学习策略比如优先选择模型置信度低于阈值的样本或者预测分数落在混淆区间的样本让有限的标注人力投在最有价值的数据上。我在实践中一般会每周跑一次数据回流更新训练集然后每月重新训练一次模型并跑离线评估和影子模式。把 AI 项目当成一个持续运营的系统而不是一次性的“上线仪式”问题就不会那么集中爆发。7. 从零实践中的避坑清单7.1 工程化失败的高频原因根据我自己的经验AI 工程失败很少是因为模型不够先进多数是基础没做牢。最常见的原因有这三个数据与代码没有版本关联线上模型“来历不明”出了问题无法回溯。离线与线上特征不一致训练时用 A 方式处理特征线上推理用 B 方式导致推理效果远差于离线条。实验记录不完整超参、数据版本、模型版本靠记忆团队协作时互相说不清。如果要我给一个优先级我会建议先解决特征一致性再解决实验记录最后才是模型迭代。因为一个特征不一致的模型哪怕离线 AUC 再高上线后也会是灾难。7.2 排查问题的心法模型上线出问题第一反应不要“重新训练”而是先定位问题层级。我的排查顺序是服务层 - 数据层 - 模型层。先看接口有没有错误、特征日志是否正常再看特征分布有没有漂移最后才回到模型本身。这个顺序能避免大量无效工作。有一次线上预测分数持续偏高团队怀疑模型坏了一度准备重新训练。后来查特征日志才发现是上游传入了一个新参数模型没识别出来默认值填充导致特征分布偏移。问题不在模型而在数据链路。还有一个心法所有的排查都要基于数据不要凭感觉。预测分数偏高就拉出最近一万条请求的日志看分布、看特征、看时间颗粒度大概率能很快圈定问题边界。7.3 给你的一份启动清单如果你现在正处在“准备从零开始做 AI 工程”的阶段我的建议是不要一口气上全所有工具而是按这个顺序逐步完善先规范代码仓库结构把数据、配置、训练、评估和服务分层。引入 MLflow 做实验追踪从第一个实验开始就养成记录习惯。用 DVC 给第一个数据集建立版本。写一份数据质检脚本并接入训练流程。上线第一个模型时采用影子模式积累监控和回滚经验。逐步增加数据漂移检测和告警再建设数据回流机制。这套顺序是在你意识到“AI 工程”远远大于“训练模型”之后可以立刻落地的最小集。每一步都能独立产生价值不会出现“等完善了才有效果”的局面。我个人在实际操作中最大的感受是AI Engineering 的“from scratch”其实不是炫技而是把基本功补齐。很多团队明明模型能力领先却输在工程执行上非常可惜。如果你能坚持把版本、数据、实验、监控这些看似枯燥的事情一点一点做扎实你会发现模型迭代本身会变得越来越快。到那时候你才真正感受到工程化的回报。