这几年总有人私信问我,说想转行做AI,一上来就问“我该学PyTorch还是TensorFlow”。我理解大家的焦虑,但更想说清楚一件事:如果你的目标写的是“ai-engineering-from-scratch”,那模型框架只是路径上很小的一段。AI工程是“工程”,不是“算法”。我做了几年AI落地相关的项目,从小脚本到现在负责端到端链路,踩过不少坑,今天把从零开始的完整思路、方法、工具链和避坑经验整理出来。这篇文章更适合两类人:一类是从算法/数据分析方向想往工程化走的朋友,另一类是完全零基础、准备入行但不知道该从哪下手的初学者。我会尽量说人话,把每个步骤背后的为什么都拆开。
1. AI工程到底是什么:先把这个概念框清楚
1.1 算法、机器学习、AI工程的分界
我见过不少人在简历上写“熟悉机器学习”,结果连一个模型都没上过线。这不是讽刺,而是很多初学者把“训练出一个高准确率模型”当成了终点。实际上,训练模型只是AI工程这条流水线里的一个环节。算法同学解决的是“给定数据,怎么优化目标函数”,AI工程解决的是“怎么让模型稳定、高效、可维护地跑在真实业务里”。区别很大,前者可以在Notebook里反复跑,后者要面对的是数据漂移、版本兼容、资源调度、接口延迟、监控告警。
我习惯用一个生活化的类比:算法像是研发一道新菜,你可以在家里厨房反复试,盐多放少放都没关系;AI工程是把这道菜做成中央厨房的标准化供应,要考虑食材采购、切配标准、烹饪时间、冷链配送、用户投诉处理。很多刚入行的朋友只盯着“菜谱”,忽略了“中央厨房”才是你能拿到高薪的核心。
所以“from scratch”不是让你从线性回归推导开始,而是让你从头搭建一套能把模型真正用起来的能力闭环。数据、训练、评估、部署、监控、迭代,缺一环都不叫AI工程。
1.2 一个AI项目的完整生命周期
如果我在公司里接到一个新的AI需求,脑子里会自动浮现一条流水线:业务问题定义、数据采集与清洗、特征工程、模型训练与调优、离线评估、模型部署、在线监控、线上反馈回收。
其中业务问题定义最容易被新人跳过。比如业务方说“我们要做一个推荐”,你如果直接开始写模型,大概率会失败。你要先弄清楚推荐什么、给谁推荐、在什么页面上、用户行为数据从哪里来、糟糕体验的定义是什么。AI工程的第一条军规就是“先确认问题,再谈技术”。
从数据到模型的环节大家相对熟悉,但部署和监控往往被忽略。我记得第一次部署模型时,以为只要把模型文件放到服务器上就结束了,结果第二天准确率断崖式下跌。原因很简单,线上特征分布变了,模型没有自动感知能力,而监控面板上根本没埋这个指标。后来的经验告诉我,模型上线不是终点,而是开始。线上推理日志、特征分布告警、定期重训任务,这些才是工程化的重头戏。
1.3 我建议的学习顺序:不做课本的奴隶
现在市面上的课程和书籍很多,但大部分是“算法先导”的路径:先学数学、再学模型、最后才提工程。对于“from scratch”的AI工程路径,我建议反过来:先建立端到端的整体感知,再去补细节知识。
先拿一个公开数据集跑通一个最简单的回归或分类任务;然后把这个模型用FastAPI包成接口;再用Docker把它容器化;接着学一点监控,比如记录推理耗时和预测分布。这个过程可能只需要一两周,但它会在你的脑子里种下一个完整的“工程地图”。之后再去补数学、补分布式训练、补更深的模型原理,你才知道每个知识点到底用在哪里。学习顺序不一定非要从泰勒公式开始。
我在下面放了一张非常适合零基础入门的选型对照表,都是开源且社区活跃的东西,学起来不容易被带偏。
| 环节 | 推荐工具 | 学习重点 |
|---|---|---|
| 编程语言 | Python | 语法、面向对象、异常处理、装饰器 |
| 数据处理 | pandas、NumPy、SQL | 数据清洗、聚合、关联查询 |
| 模型训练 | scikit-learn、PyTorch | 训练循环、验证集、超参数 |
| 实验管理 | MLflow | 记录参数、指标、模型产物 |
| 接口封装 | FastAPI | API设计、请求校验、异步处理 |
| 容器化 | Docker | 镜像构建、依赖固化 |
| 监控 | Prometheus、Grafana | 指标采集、可视化、告警 |
| 调度编排 | GitHub Actions / Airflow | 自动化训练、定时重跑 |
2. 地基:先解决语言、数据和工具链
2.1 Python不是万能的,但它确实是AI世界的主语
很多零基础的朋友问我,是不是必须把Python学得很深才能开始。我的建议是:不需要等你成为Python专家,但至少要熟练到“不查语法也能写出一个类”的程度。AI工程的日常不是天天写模型,而是写各种胶水代码:从数据库读数据、清洗格式、调接口、拼参数、写定时任务。这些活儿考验的是基本功,不是模型理解。
我见过有同学一上来啃《流畅的Python》,啃了两周就放弃了。其实可以先掌握列表推导、字典操作、函数、类、装饰器、with语句、try-except,这些基础足够你写出干净可维护的代码。装饰器在FastAPI里会用到,生成器在处理大文本时很有用,这些边做边补更高效。
Python相关的一个重要能力是“读错误日志”。新手经常跑了一行代码,报错就慌。其实Python的错误信息已经把文件、行号、错误类型写得清清楚楚。要学会先读最后一行,再往上找原因。这个习惯会伴随你整个AI工程生涯。
2.2 数据处理能力:比模型重要十倍
很多人在训练时遇到“准确率上不去”,第一反应是换模型。但实际上,问题大概率出在数据上。AI工程中最耗时间的不是训练,而是数据处理。一个真实的项目里,你可能有70%的时间在干“数据苦力活”。
我常用的组合是pandas + SQL。SQL用来从公司数仓里捞数据,pandas用来做探索性分析和清洗。新手可以先学会pandas的这几个操作:读CSV、查看缺失值、fillna/dropna、groupby聚合、merge合并、apply自定义函数。这些操作覆盖了日常80%的需求。
数据质量检查有一个容易被忽视的重点:检查训练集和线上特征的一致性。比如训练时你用了“用户最近7天购买次数”,线上如果拿到的特征延迟了一天,这个偏差会直接导致模型效果变差。这不是模型能自己纠正的。我的习惯是把特征定义写成一个单独的函数,训练和推理共用同一份代码,从根源上避免两端特征不一致。
2.3 环境管理:从依赖地狱到可复现
AI工程的“脏活”之一就是管理依赖。今天装个torch,明天装个sklearn,后天升级了numpy,结果另一个项目跑不起来了。我最早也遇到过这种问题,一天时间都耗在配环境上。
我现在的标配是conda + Docker两件套。本地开发用conda创建隔离环境,每个项目一个环境,Python版本和依赖都写进environment.yml。到了要部署的环节,用Docker把代码、依赖、系统库全部打包成镜像,这样不管部署到哪个服务器,跑起来的效果都和本地一致。
新手经常忽略锁版本。pip的requirements.txt如果写成“numpy>=1.19”,这个“>=”会带来极大的不确定性。今天跑通,三个月后可能就装上了不兼容的版本。建议把依赖固化成具体版本号,比如numpy==1.21.4。更进一步,可以使用pip-tools或poetry生成锁定版本的lock文件。环境可复现,是所有工程化的基础。
3. 模型开发:从训练到评估的工程化习惯
3.1 训练脚本的规范化:别再把所有代码塞进Notebook
Notebook适合做探索,但不适合做工程。我在带项目时,要求所有训练代码必须转成脚本,并且要有清晰的目录结构。一个最基本的训练项目目录大概是这样的:
project/ ├── data/ # 原始数据和中间数据 ├── src/ │ ├── data_process.py # 数据清洗、特征工程 │ ├── train.py # 训练入口 │ ├── evaluate.py # 离线评估 │ └── predict.py # 推理封装 ├── models/ # 模型产物 ├── config.yaml # 参数配置 └── requirements.txt # 依赖清单目录结构本身不是目的,目的是让任何人拿到你的仓库都能跑起来。训练脚本要有参数入口,比如通过argparse读取--batch_size、--lr、--epochs。不要把这些值硬编码在文件里。配置文件和代码分离,这个习惯能帮你后面做自动化训练。
训练过程还要保存有效的Checkpoint。不能只在训练结束后保存最终模型,最好每个epoch或每个best模型都存一份。存的时候带上训练参数、数据版本、评估指标。因为当你后来发现指标异常时,需要能回滚到之前的版本排查问题。
3.2 实验管理:不要用Excel记录训练结果
早期我自己也是用Excel记实验,记了几次就放弃了。实验多了以后,你根本记不住哪组超参对应哪个模型。更麻烦的是,模型文件名和实际参数对不上,回查时欲哭无泪。后来我换成了MLflow,这是目前开源社区里最常用的实验管理工具之一。
MLflow可以自动记录每个实验的参数、指标、模型产物,并提供一个Web界面按时间排序。你训练时只需要在代码里加几行:
import mlflow with mlflow.start_run(): mlflow.log_param("lr", 0.001) mlflow.log_param("batch_size", 32) mlflow.log_metric("auc", 0.86) mlflow.pytorch.log_model(model, "model")这样做的好处是,任何一次实验的完整上下文都在。你只要打开MLflow UI,就能对比不同实验的指标、参数,还能直接加载某个run的模型做测试。对于团队协作来说,实验记录统一化也避免了“你用的是哪版模型”这种低水平沟通。
3.3 评估指标:别只盯着准确率
我在面试的时候经常问一个问题:如果正负样本是99比1,你的模型准确率99%,这模型有价值吗?答案是基本没价值,因为全部预测成负样本也能达到99%。这个例子在AI工程里非常实际。分类问题要关注Precision、Recall、F1,回归问题要关注MAE、RMSE,排序问题要看NDCG、AUC。
更重要的是,指标一定要贴合业务目标。比如做欺诈检测,漏掉一笔欺诈交易的成本很高,所以召回率要优先;做商品推荐,用户不想看到太多不相关的东西,精度可能更重要。工程实现上,评估代码必须和训练代码分离,保证测试集不泄露到训练过程中。最稳妥的做法是单独写一个evaluate.py,从数据目录读取留出的验证集,对模型产物做评估。
4. 上线部署:让模型开始真正干活
4.1 模型服务化:用FastAPI封装一个推理接口
模型训练完成后,下一个问题是怎么让业务系统调用它。最朴素的办法是写一个Python脚本,加载模型后对输入数据做预测,但这种方式太笨重。我一般用FastAPI把模型包成一个HTTP服务,一次加载模型,常驻内存,接收请求后返回预测结果。
一个最小可用的服务大概长这样:
from fastapi import FastAPI from pydantic import BaseModel import joblib app = FastAPI() model = joblib.load("models/model.joblib") class InputData(BaseModel): feature1: float feature2: float @app.post("/predict") def predict(data: InputData): x = [[data.feature1, data.feature2]] pred = model.predict(x)[0] return {"prediction": float(pred)}这里有几个工程细节容易踩坑。第一,模型加载要在模块导入时完成,不能每个请求都重新加载,否则延迟高到没法用。第二,输入参数要有类型校验,Pydantic在这里帮了大忙,传错类型直接返回400。第三,批量推理比单条推理吞吐量高很多,如果业务方有一批数据要打分,可以设计一个/batch_predict接口,接收数组输入。
上线前还要考虑超时和异常处理。如果模型内部抛了异常,不能让用户看到堆栈;要捕获异常后返回统一的错误码,并记录日志。这些细节决定了你这个接口是“演示级”还是“生产级”。
4.2 容器化部署:Docker不是可选项
如果只在自己电脑上跑模型,不学Docker也没问题。但一旦需要部署到公司服务器或云环境,Docker就是迈不过去的门槛。它解决的核心问题是环境一致性:本地装好的依赖、系统库、Python版本,全部打包进镜像,服务器上直接跑,不需要手动配环境。
一个简单的Dockerfile长这样:
FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY ./app /app CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]新手有几个常见问题。第一,镜像基础不要选“latest”,要明确版本,否则某天基础镜像更新后,你的服务可能就起不来了。第二,COPY代码之后要记得把不需要的文件写进.dockerignore,比如本地数据集、模型文件,避免镜像过于臃肿。第三,容器内的进程要和容器的生命周期绑定,否则容器启动后进程pid为1的不是你的服务,会出现容器还在但服务已经挂掉的情况。
镜像构建好之后,可以用docker run本地验证一遍,再推送到镜像仓库,后续的部署、滚动更新都基于这个镜像进行。只要能保证镜像可复现,上线就不再是玄学。
4.3 监控与反馈:模型上线不是终点
很多模型的失效都不是突然崩溃,而是缓慢退化。数据分布变了、用户习惯变了、上游特征质量变了,都会让模型指标一点点下滑。如果没有监控,业务方可能比你先发现问题,那时候就相当被动了。
监控要做两层。第一层是系统监控,重点关注接口延迟、吞吐量、错误率、内存和CPU使用率。推荐用Prometheus采集指标,用Grafana画看板。第二层是模型监控,需要统计线上预测结果的分布,比如分类问题里“预测为正样本的比例”是不是突然升高了。如果分布发生明显偏移,就要考虑重新训练或回滚版本。
我这里做了一个简单的问题排查表,不一定全面,但都是日常最常见的隐患。
| 现象 | 可能原因 | 排查思路 |
|---|---|---|
| 线上准确率下降 | 特征分布漂移 | 比较训练和线上的特征均值/分布 |
| 接口响应变慢 | 推理数据量过大或CPU瓶颈 | 查看监控指标,考虑批量推理 |
| 偶发报错 | 输入数据缺失或类型异常 | 检查Pydantic校验和异常日志 |
| 模型效果一直上不去 | 训练数据泄漏 | 检查时间序列划分是否严格 |
5. 常见问题与排查实录
5.1 数据泄漏:静悄悄地拉高你的指标
数据泄漏是AI工程里最“阴险”的问题之一。现象是离线评估指标特别漂亮,一上线就垮。我踩过一个真实的坑:做某个时序预测任务时,因为清洗逻辑写错了,把未来信息混进了训练特征。离线的AUC高达0.97,线上实际效果排名却垫底。
排查数据泄漏,有两点经验可以分享。第一,在特征工程阶段,任何聚合操作都要反复检查时间窗口,比如“用户历史购买统计”只能用当前时间点之前的记录,不能让预测时刻之后的数据参与计算。第二,在数据划分上,不要随便用train_test_split处理时间序列数据,要用时间序列切分,保证训练集完全在验证集之前。泄漏带来的“高指标”是幻觉,工程上宁可要一个真实的、稍微低一点的指标。
5.2 训练复现困难:随机种子和版本锁
同一个模型脚本,第一次跑AUC是0.85,第二次跑变成0.84,这是很多新人的困惑。原因通常是随机性:随机初始化、随机数据Shuffle、GPU的非确定性运算。要保证训练可复现,第一步是在代码里固定随机种子:
import random import numpy as np import torch def set_seed(seed): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed)但这还不够,深度学习框架的某些操作(比如某些CUDA并行计算)即使固定种子也可能有微小偏差。如果实验要求完全可复现,需要设置torch.backends.cudnn.deterministic = True,同时关闭benchmark模式。更实用的是记录“数据版本+代码版本+依赖版本+参数配置”,一旦结果异常可以回到当时的实验环境。
5.3 内存和显存管理:OOM不是玄学
跑模型时最常见的报错是OutOfMemory,CPU内存不够和GPU显存不够的表现不一样。CPU内存不够,通常是因为一份数据被复制了很多份。比如pandas读了一个大文件,你做了过滤,又做了merge,原始DataFrame还占着内存。建议及时del掉不用的中间变量,或者用gc.collect()手动回收。
GPU显存不够,原因可能是batch_size太大、输入图片过大,或者模型本身太大。这时候优先调小batch_size,观察显存占用变化。如果有多个模型同时加载,可以考虑用CPU跑部分模型,或者用推理服务框架做模型分片。不要一遇到OOM就崩心态,先看显存是持续涨还是一下子爆,这能帮你判断是内存泄漏还是批次过大。
5.4 延迟和吞吐优化:别等到上线再想
有些模型在离线评估时算得挺快,一上线发现接口平均延迟1秒,根本扛不住。原因可能是单条推理循环、未做批量处理、特征计算逻辑过于复杂。我一般会分三步优化:先做特征计算耗时分析,找出瓶颈;然后看模型推理部分能否用torch.jit或ONNX加速;最后考虑在服务层面加缓存,高频且重复的请求直接从Redis里取结果。
这里有一个性价比很高的做法:把不需要实时推理的场景全部转成离线批量预测。比如“每日用户评分”,完全可以用定时任务,每天凌晨算好结果写到数据库里,白天直接查表。实时推理的复杂度高、成本大,工程上能做离线就尽量离线。
6. 一条可复制的从零到一实操路径
6.1 用十周时间完成一个小而全的AI项目
如果你看完上面这些内容还是不知道怎么动手,我建议你直接给自己定一个十周的小项目。选一个经典又简单的场景,比如“客户流失预测”,或者“电影评分预测”。第一周搭好Python环境和项目目录;第二周用pandas做数据探索和清洗;第三周用scikit-learn训练一个逻辑回归模型当基线;第四周用MLflow记录所有实验;第五周用FastAPI包一个推理接口;第六周把服务装进Docker;第七周加一点监控指标;第八周做一次参数调优;第九周整理文档;第十周复盘整个链路。
这个过程里的每一步都会逼你用到真实工程中的技能。做完之后,你会对“ai-engineering-from-scratch”这句话有非常具体的理解。它不是一个名词,而是一条从数据到价值的完整生产线。很多知识点一开始看不明白,是因为没有上下文,等你亲手跑完一个全流程,再看论文和源码,理解深度完全不一样。
6.2 最后分享一点我的个人体会
做AI工程这几年,我最大的感受是:会调模型的人很多,能把模型稳定变成业务价值的很少。公司里缺的从来不是“会跑通一个Notebook”的人,而是能扛住数据质量、模型上线、监控告警、故障恢复这一系列脏活的人。从零开始不是让你把论文公式背一遍,而是让你亲手把每个环节都做一遍,踩一遍坑,然后理解为什么工程化要这么设计。如果你已经在路上,别怕慢,多试错、多复盘,这条路是真实可以走通的。