
我一直觉得把“ai-engineering-from-scratch”当成一个进阶学习的路线图比把它当成一个具体项目要更准确。因为真正从零开始做AI工程不是一个“跑通一个模型就算完事”的过程而是一整套关于数据、实验、训练、评估、部署、监控的工程打磨。你可以把它理解为AI把模型做出来只算完成一半另一半是把模型变成一个稳定、可维护、能持续迭代的系统。这篇内容适合两类人。第一类是想入行AI工程、但手上只有零散代码经验的人你需要知道该按什么顺序建立能力。第二类是已经在公司里接触过模型开发但发现项目经常卡在“模型效果可以了但根本没法上线”这一步的人你需要突破的点其实就在工程化链路里。1. 先想清楚AI工程和AI科研是两回事1.1 到底什么是AI工程很多人第一次接触“AI Engineering”这个词时会把它想象成“调模型、刷精度”的技术活。我一开始也是这样总以为把准确率从90%刷到95%就是工程能力的体现。真到项目里才发现AI工程的定义比这宽得多。把一个AI系统稳定地跑在真实环境里让它经受住不同数据分布、不同时段流量、不同用户行为的考验这件事占掉了AI工程至少70%的精力。AI科研关心的是“这个方法是否有效”AI工程关心的是“这个系统是否可靠”。有效和可靠之间的差距就是工程化的工作量。举个生活化的例子。科研像是在实验室里做一道菜只要味道好、有理可依就行。工程像是开餐馆要考虑出菜速度、食材供应、成本控制、厨师离职后配方还能不能复现、高峰期会不会出餐混乱。同样是做菜目标完全不同。所以我们讲AI工程第一件事就是把思维方式从“论文复现”切到“系统交付”。你在一个实际项目里至少要用工程视角同时处理五个问题数据基础是否扎实、训练流程是否可复现、评估指标是否反映业务目标、模型服务是否够快够稳、线上反馈是否能闭环回到模型迭代。任何一个环节断了模型的“好效果”都落不了地。1.2 从零开始的人最容易掉进的三个坑我见过很多人也包括当年的我自己都是从零开始做AI项目时踩坑。这些坑看起来是技术问题本质上是思路问题。第一个坑是“没有指标就开始收集数据”。有的项目一开始只开会说要“做一个智能推荐”但推荐什么叫好是点击率高还是用户停留时间长没人说清楚。最后数据收集了一堆训练时才发现字段缺失、正负样本定义模糊之前的活全白干。正确做法是先定义可量化的目标哪怕一开始粗糙一点也要把指标从“感觉好”变成“数字可度量”。第二个坑是“本地跑通了就直接部署”。本地一个小脚本能跑不代表生产环境能活。生产环境里要面对的是几十倍甚至上百倍的请求量、不同的数据特征、网络超时、资源限制。更麻烦的是本地模型的依赖环境往往没固定下来换一台机器就崩。这是典型的“实验代码”和“工程代码”没有区分开。第三个坑是“忽略baseline”。很多人拿到数据就直奔深度学习模型感觉不上一套复杂的神经网络就显不出水平。但在工程里先做一个简单的逻辑回归或规则模型作为baseline能帮你快速判断数据里有没有信号、特征工程的方向对不对、数据量是否足够。没有baseline你连模型有没有真正学习到模式都无法判断更没法跟复杂模型做对比。2. 环境搭建不是装个Python就完事2.1 开发环境的最小可用配置从零开始做AI工程第一关是开发环境。这关看着简单但环境问题能卡住你好几天。Windows、Mac、Linux三套系统的处理方式完全不一样GPU驱动、Python版本、包管理器之间的关系更是又细碎又重要。我的建议是先把基础环境拆成三层来看。第一层是系统层包括操作系统和GPU驱动这一层决定了底层能力。第二层是Python解释器和虚拟环境这一层与你的依赖包管理密切相关。第三层是AI框架和业务依赖比如PyTorch、TensorFlow、NumPy这些。很多环境问题出在层与层之间的版本匹配。装Python时建议用conda或uv这类能同时管理Python版本和虚拟环境的工具不要直接往系统里塞一个全局Python。我在实际项目里用的环境创建命令大概是这样的conda create -n ai-project python3.11 conda activate ai-project pip install \ torch2.3.0 \ torchvision0.18.0 \ --index-url https://download.pytorch.org/whl/cu121这套做法的关键是“纯净隔离”。每个项目都用自己的虚拟环境依赖版本互不污染。等踩过“A项目换依赖导致B项目跑不起来”的坑以后你就明白这不是多此一举了。2.2 依赖管理是第一个工程化分水岭环境能跑起来只是起点真正考验工程化能力的是依赖管理。我见过不少团队代码放在Git里但依赖列表靠“谁记得就补一句”最后新同事clone代码后根本跑不起来。依赖管理的核心目标是可复现。今天跑的代码三个月后还能跑出一致的结果这才是工程化的基本要求。具体到操作上我建议至少做到三点。第一用锁定版本的依赖清单。比如requirements.txt里直接写死版本号或者更进一步用pyproject.toml加lock文件。为什么不用“1.0”这种写法因为依赖库里的小版本升级往往带行为变化可能在某个阴间时刻给你埋雷。锁版本能够减少这种不确定性。第二把环境和代码一起交付。最直接的手段是Docker。容器把系统依赖、Python依赖、代码打包成镜像任何人拿到镜像都能在你的环境基础上运行。在项目早期就引入Docker看起来慢实际上省掉了后面大量“在我机器上明明能跑”的扯皮时间。第三给实验环境加固定种子。依赖管理管的是库实验可复现还需要固定随机种子。深度学习训练里数据shuffle、初始化、dropout都有随机性。固定好numpy、python的random、torch的seed至少能让实验结果在大多数情况下可复现。2.3 数据与模型版本管理依赖和代码都管理起来了还有一个经常被忽略的东西数据。代码可以用Git管但数据通常体积大、变更频繁用Git反而会拖到崩溃。模型文件也一样随便用一个文件名加日期的方式存几天之内就能把服务器磁盘塞满还搞不清哪个版本对应哪次训练。在实践中适合普通团队的做法是引入DVC这类数据版本管理工具或者退一步至少建立清晰的文件目录和命名规范。datasets/ 2024-05-01_raw_v1/ 2024-05-08_raw_v2/ experiments/ 2024-05-01_lr_baseline/ 2024-05-03_bert_finetune/ models/ run_20240501_model.pt run_20240503_model.pt每个数据版本记录下来源、清洗脚本、生成时间。每个实验记录下配置参数、训练日志、评估结果。别小瞧这个阶段的工作它决定着你出了问题之后能不能快速定位到是哪一版数据、哪一组参数导致的。我自己的经验是实验记录做得越细后面复盘越省力。这个教训是我在连续跑废三个实验、却找不到哪个参数变了之后才真正理解的。3. 数据工程大部分AI项目死在数据上3.1 数据采集与清洗的实战要点数据是AI项目的燃料。我见过太多项目模型结构没多大问题训练也都正常最后效果不行一查根因还是数据出了岔子。从零开始做AI工程一定要在半路上专门腾出精力认真处理数据。采集数据的第一个原则是“先明确记录元信息”。比如你采了一批商品评论不能只存评论文本还要存发布时间、用户ID、评分字段、渠道来源。这些元信息以后做特征、做数据切分、做分布分析都用得上。我已经数不清有多少次因为“当初没存这个字段”不得不重新爬一份数据的经历。清洗环节最常用的是“按规则清洗人工抽检”的组合。规则清洗包括去重、去除HTML标签、编码统一、异常值过滤。举个例子处理文本数据时我一般会做完整去重之外还会做近似去重。文本里的表情符号、多余空格、全角半角差异都会导致同一句话被算成不同样本。用哈希去重只能去掉完全一样的用SimHash一类的方法可以去掉高度相似的重复内容。清洗之后要留一手不要把规则写死。清洗脚本本身也要进Git清洗规则变更时要有记录。因为清洗规则本质上是你对数据的理解和假设后面发现效果不对改的往往不是模型而是这些假设。3.2 标注质量如何把控有监督学习绕不开标注。而标注质量往往决定了模型的上限。很多从零开始的项目把大量精力放在模型调参上却对标注漏洞视而不见最后模型拼命拟合了错误答案还一脸懵。做标注质量把控重点不是“让每个人标得都一样”而是“让不一样的地方被暴露出来”。一种常见做法是同一条数据分配给至少两个人标然后计算标注一致性。人工判断一致性的简单指标是Kappa系数核心逻辑是剔除掉“瞎蒙也能碰对”的部分看看两个人真实一致率有多高。可以写几行Python模拟一下这个计算def kappa(observed_agreement, categories): p_o observed_agreement p_e sum([c * c for c in categories]) # 每种标签占比的平方和 return (p_o - p_e) / (1 - p_e) if p_e ! 1 else 0这个值低于0.4说明标注标准不清晰至少要重新培训和讨论。Kappa算出来的数字不是用来供奉的而是用它判断“哪个类别容易产生歧义”然后针对那个类别细化标注规范。还应当给标注环节设定期中抽检。刚开始标100条就停下来随机看几条比全部标完再返工要划算得多。质量问题的特点是发现越晚、修复成本越高这个规律在数据标注上体现得淋漓尽致。3.3 数据切分与数据泄露陷阱数据切分是机器学习里最容易被低估的一环。很多新手习惯用train_test_split直接随机切一刀这在同分布独立样本上有道理但在真实项目中往往不成立。典型的场景是电商评论。同一条商品的评论可能被同一批用户反复批评你随机切分后训练集和测试集里可能出现同一商品、甚至同一用户的相似评论模型等于“已经见过答案”。线上效果自然比验证集效果差出一大截这不是玄学这就是数据泄露。解决这类问题有个原则按数据生成来源切分不要按行随机切分。如果数据是按时间产生的就按时间前80%训练、后20%验证。如果数据按用户汇聚就按用户分桶切分确保同一个用户的数据只出现在一个集合里。命名上可以直接叫“时间切分”或“用户隔离切分”提醒自己这是经过思考选择的切分方式。数据泄露还有一种隐蔽形式是特征本身包含了未来信息。比如用当前时间点的订单数据预测用户是否会流失却把“是否已经流失”作为特征输入进去了这是错误地用了未来的结果来预测未来。这类问题做数据审查的时候要多问一句这个特征在预测时刻真的可获取吗4. 模型训练与评估从跑通到跑稳4.1 基准模型与资源评估数据准备好之后自然进入模型训练环节。但训练的第一件事永远不是直接上大模型。我在前面说过要对baseline认真对待这是有实际操作价值的。先训练一个简单模型比如逻辑回归、线性回归或者一个两层的小MLP达到两层目的。第一验证整条数据链路是否通顺——从数据读取、特征转换到损失计算、反向传播跑通这一整套流程。第二提供一个效果下限参考后续如果复杂模型连这个底线都没超过说明不是模型不够复杂而是数据或特征出了问题。做基准模型的同时建议顺手估算训练资源。我自己习惯写个粗略计算脚本把数据量、每epoch耗时、训练总时长、显存峰值都打印出来。这不单是为了看进度更是为了提前发现资源瓶颈。比如数据量从100万涨到1000万特征维度不变的情况下线性模型的内存和耗时增长是可预估的如果你发现脚本需要跑三天才能出结果那就应该及时优化数据加载方式或调整batch size而不是傻等。这里给出一个开发阶段的直接建议先只用数据的10%到20%做一次完整训练确认loss能降、指标能动、时间可接受再放大到全量数据。我见过太多人一上来就用全量数据结果在浪费了十几个小时后才发现不同的epoch之间loss完全不下降。小样本试跑是帮你在“跑通”和“跑废”之间建立一个安全缓冲。4.2 训练过程的监控指标训练不是“命令一执行等结果”这么简单。一个合格的AI工程流程里训练过程的实时监控是必须的。至少要看四条曲线训练集损失、验证集损失、学习率变化、梯度范数。训练集损失下降证明模型正在从数据里学到东西验证集损失同步下降证明学到的东西有泛化能力验证集损失开始回升而训练集损失继续下降这是过拟合的经典信号。梯度范数过大说明优化器可能积攒了爆炸性梯度过小说明训练可能陷入停滞。四条曲线放在一起能让很多问题一眼暴露。实际工程里我还会看每个epoch的耗时、数据加载耗时占比、GPU利用率。数据加载耗时太高光盯着训练曲线是看不出到底瓶颈在哪里的。建议用psutil或nvidia-smi定时采集资源数据把训练日志和系统指标汇总到一张表里观察久了你就能够凭经验判断瓶颈是数据、显存还是CPU。# 训练过程中简单记录 import torch for epoch in range(epochs): train_loss 0.0 for batch in loader: optimizer.zero_grad() outputs model(batch) loss criterion(outputs, batch.label) loss.backward() grad_norm torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0) optimizer.step() train_loss loss.item() print(fepoch{epoch}, loss{train_loss:.4f}, grad_norm{grad_norm:.4f})这段代码本身没什么高深的但它表达了工程化监控的内核不要只看最终精度要让中间过程可见。4.3 评估不是只看accuracy训练结束进入评估阶段评估标准不能只挂着一个准确率。准确率在大部分真实场景里都不够用因为它对类别不敏感。比如一个风控场景里99%的用户都是正常用户你只要全预测成正常准确率就有99%。但这个模型没有任何用。实际项目里我建议根据业务目标设计一套评估矩阵。分类问题至少要看精确率、召回率、F1甚至要针对不同置信度切点画出阈值-指标曲线。业务场景不同关注的重点不一样反欺诈更看重召回因为漏掉一个坏账损失巨大智能客服更看重精确率因为答错比不答更让用户恼火。评估还要讲究“与业务对应”。模型输出的不是最终决策而是一个概率分。业务方完全可以根据这个分数自定义阈值。所以交付模型时除了给出最优阈值最好给出精确率和召回率随阈值变化的完整曲线。这能让后续团队根据风险偏好自行调整而不是硬编码一个0.5的默认阈值。5. 交付部署与持续迭代AI工程的下半场5.1 模型部署的几种方式模型部署是AI工程里最明显的一道坎。很多人在离线环境里做得很顺利一上线就手足无措。其实部署方案有固定套路关键是想清楚业务的实时性要求。如果业务允许离线计算比如生成日报、批量打标最简单的方式是定时批处理脚本每天跑一次把结果写入数据库。这种方式对基础设施要求最低成本也最容易控制。如果业务要求秒级响应比如在线推荐、实时风控那就需要把模型包装成一个API服务。常见的做法是用FastAPI搭建服务加载模型后提供推理接口。部署时一定要把权重文件从代码仓库里拆出来模型文件放到对象存储或专用模型仓库服务启动时动态拉取否则服务镜像会又大又难管理。如果业务发生在手机或边缘设备上还需要考虑模型量化、剪枝、转成ONNX或CoreML这类格式。边端部署是另一个大话题但从零开始可以先不碰只要知道它会带来额外的优化成本就行。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class Item(BaseModel): text: str app.post(/predict) def predict(item: Item): inputs tokenizer(item.text, return_tensorspt) with torch.no_grad(): logits model(**inputs).logits return {score: float(logits.softmax(-1)[0, 1])}这个例子虽然简单却体现了一个关键原则模型服务和应用代码要解耦。API层只负责把输入变成输出不掺入业务逻辑。业务判断放在调用方这样模型版本更新时不需要跟着改业务代码。5.2 监控、反馈与自动重训部署上线不是终点是AI工程中后半段挑战的开始。因为模型是基于历史数据训练的而真实世界的数据分布会随时间改变。用户行为会变、商品结构会变、季节会影响数据这些都会导致模型效果慢慢衰退。所以AI工程必须要有监控。监控分两层系统监控负责看API的延迟、错误率、吞吐量数据监控负责看输入特征的分布、预测结果的分布。系统监控好理解就是服务器层面的可用性。数据监控容易被忽略但它反映的是模型“适不适合当前环境”。一个直接的办法是定期用新数据跑一遍模型预测看看预测结果的类别分布和训练时期有没有明显偏移。如果你拿到的输入特征普遍开始偏离训练集范围就说明该重新训练了。反馈闭环是AI工程里最体现工程水平的地方。每一条线上预测如果后续得到了用户的真实反馈最好都回流到日志系统形成“预测结果真实结果”的配对数据。累积一批之后用这些新数据增量训练或重训模型让系统形成持续学习和迭代的能力。有了反馈闭环AI系统才不是一次性消费品而是一个可以在运营中不断变好的产品。6. 从零到一一个可落地的推进顺序与踩坑记录6.1 一个具体的项目推进顺序从零开始把AI工程落地我建议按固定顺序走每一步都有明确的检查点。很多项目失控是因为着急推进跳过了中间验证步骤。第一步先定义业务目标和评估指标。比如“将客户流失预警的召回率从现有规则模型的50%提升到70%”。这是业务级的定义。第二步盘点数据和资源。确认手上有什么数据、缺什么字段、标注样本够不够、计算资源够不够。第三步做最小可行性验证。用一小部分数据和最简单模型跑通整个链路确认Pipeline没有硬伤。第四步做baseline模型记录效果。第五步迭代优化引入更复杂的模型或更好的特征。第六步进入部署阶段先以离线批处理或shadow mode跑一段时间让模型先“陪伴”一段时间而不是直接替换业务。shadow mode的意思是模型同步进行预测但不影响真实决策这样可以积累“模型预测与真实结果对照”的样本安全地验证模型可靠性。第七步正式上线并持续监控。这个顺序看起来不刺激却是最稳的。尤其shadow mode这一步被很多从零开始的人直接跳过但在业务价值敏感的系统里它几乎是必须的。上线后的两个小时内我就曾亲眼见到一次误判暴露出明显的数据分布问题那种情况下如果没有shadow mode先跑一周问题会直接作用在用户身上。6.2 项目里遇到过的典型问题与排查思路把问题写下来比泛泛而谈“注意”要有用得多。我把自己常遇到的几个问题和排查思路整理成一张速查表。第一模型在验证集上很好线上表现一塌糊涂。优先怀疑数据泄露和时间分布漂移检查是否存在同源数据出现在两个集合里深挖特征的获取时间点。第二训练loss不降或降得极慢。先打印一次prediction和label看看数值范围是否异常是否分类数不对再用小样本过拟合测试判断代码是否有bug。第三GPU显存OOM。可以先减小batch size规范化模型输入尺寸检查是否有变量被误加入计算图及时把不需要的隐状态detach掉。第四线上服务吞吐量不够。先看瓶颈是把时间花在GPU推理、数据加载还是序列化上针对性地缓存预处理结果或改用更轻量模型。除此之外还有一个经典check训练时损失下降了但验证集精度不动。这种情况大多是数据标签噪声过高模型即使把训练集背下来也没法泛化到新的验证集。优先回去看标注质量和样本分布。6.3 个人体会AI工程能力的本质是什么从零开始做AI工程做的越久越发现真正的工程能力不是“会不会调参”而是“面对不确定性时有系统的方法去逼近事实”。当你遇到模型效果差、上线失败、数据异常时靠的不是运气而是一套你能稳定复现的流程。环境是否可复现、数据是否有版本、实验是否有日志、部署是否有监控、反馈是否在闭环。每个环节多费一点心思整条系统就稳一分。根据我的个人经验想在AI工程这条路上走得远可以刻意训练一个习惯每次完成一个实验都写下“如果我这次重新开始会先做什么”。这个习惯能让你快速复盘出真正重要的事在别人还纠结某一个参数的精度时你已经把整个系统的可靠性提上去了。从零开始的路不难难的是每一步都稳着走。