我特别想聊聊“AI工程”这件事。很多人一开始接触这个方向,都会以为AI工程就是训练模型、调参、刷精度。这个认知我踩过整整半年,直到把第一个模型真正推到线上、被真实流量打了一遍,才彻底意识到:AI工程是一条完整的链路,从数据到训练到部署到监控,每一环都决定最终成败。今天这篇就围绕 ai-engineering-from-scratch 这个主题,把我从零搭建AI工程能力的完整思路、实操过程和避坑记录捋一遍。它适合两类人:一是传统后端想转入AI方向的开发者,二是算法岗新人——能训出漂亮的模型但不知道怎么让它稳定跑在线上。
1. 从零开始之前:先把AI工程这件事拆清楚
1.1 “模型训练”不是全部,这是一次重新认知
我刚开始接触AI工程时,理解非常简单粗暴:把数据丢给模型,训练出一个高精度的模型,任务就结束了。后来第一个真实的业务项目打脸了。模型离线评估的F1值很高,但放到线上之后,响应慢、数据分布和训练样本完全不一样、偶发性报错一堆,每天有大量请求根本到不了模型推理那一步就挂了。
这件事给我一个特别重要的启发:AI工程其实是一条流水线,模型训练只是其中一段工序。完整的AI工程要解决的不只是“模型能不能收敛”,而是“系统能不能在复杂多变的真实场景里,持续、稳定、低成本地提供可靠的模型服务”。
从零开始搭建AI工程能力,本质上是在搭建这四块:
- 数据工程能力:数据从哪来、怎么清洗、怎么保证质量、怎么更新。
- 实验与训练能力:模型怎么选、怎么训练、怎么评估、怎么复现。
- 服务化能力:模型怎么部署、怎么加速、怎么和前向业务流程对接。
- 运维与迭代能力:线上效果怎么监控、分布漂移怎么发现、模型多久更新一次。
这四个部分缺一不可。缺了数据工程,模型就是无源之水;缺了服务化,模型只能躺在Notebook里;缺了监控迭代,模型早晚被真实环境淘汰。
1.2 从零开始不等于从零学算法理论
这里有一个关键判断。不少想转AI工程的朋友,一上来就死磕厚厚的深度学习理论,或者把李航的《统计学习方法》从头啃到尾,结果啃了大半年还在原地踏步。我的建议是:AI工程的重心是“工程”二字,算法理论需要懂,但不需要等完全学懂才能动手。
我当时给自己定了一条原则:算法知识够用就行,但是工程能力必须过硬。什么是“够用”?比如Transformer的原理、梯度下降的基本过程、损失函数背后的直觉、过拟合和欠拟合的成因,这些必须掌握,因为它们直接影响你排错的能力。但像最新的注意力机制变体每个都去深挖数学推导,就没有必要了。
我把学习路径拆成了两条腿走路:
- 第一条腿:并行学习Python工程基本功、Docker、Linux操作、CI/CD基础,这些可以马上上手。
- 第二条腿:以项目为抓手,在真实任务中补充模型训练、性能调优、部署监控等知识点。
事实证明,这种“工程先行+项目驱动”的方式,比纯啃理论高效得多。第一个小项目中,我边写数据预处理脚本边学会了Pandas的核心操作;几个真实项目下来,主流模型的原理、训练技巧、部署方案都形成了肌肉记忆。
2. 技术栈选型与核心工具的正确打开方式
2.1 框架和工具选型的核心思路
从零开始最怕的不是不会用工具,而是被工具绑架。现在AI领域的轮子更新速度惊人,今天出一个新框架,明天出一个新库,要是每个都去追,时间就全浪费了。我选型有一条标准:社区活跃度 + 生产环境验证 + 维护者可靠性,满足这三点的工具才值得投入时间。
具体到我自己的技术栈,经历多次踩坑后稳定成以下组合:
| 环节 | 我用的工具 | 选型理由 |
|---|---|---|
| 开发语言 | Python 3.10+ | AI生态最全,上手快,工程库丰富 |
| 深度学习框架 | PyTorch 2.x | 动态图调试方便,社区体量最大,生产部署方案成熟 |
| 数据处理 | Pandas + Polars | Pandas入门友好,Polars处理大数据更快,两者互补 |
| 模型服务 | FastAPI + TorchServe | FastAPI轻量且调试方便,TorchServe承担高并发场景 |
| 容器化 | Docker | 解决环境一致性,从开发机到服务器不再“水土不服” |
| 实验管理 | MLflow | 跟踪实验参数、指标、模型产物,避免实验混乱 |
| 监控 | Prometheus + Grafana | 开源标配,指标采集和可视化都非常灵活 |
选这套组合,不是因为它们最潮,而是因为它们在真实生产环境中被验证的次数最多。踩坑时随便一搜就能找到解决方案,对于从零起步的人,这比什么都重要。
2.2 Docker和实验管理这些“非模型”能力,为什么才是AI工程的分水岭
说实话,模型训练的知识体系其实很成熟,网上教程满天飞。而真正区分AI工程能力强弱的,往往是那些和模型没直接关系但和“工程”强相关的能力。
Docker就是典型例子。我最初完全不明白容器化的意义,总觉得“在我的电脑上能跑就行”。直到有一次要把训练好的模型部署到客户的GPU服务器,对方的Python环境版本和我的完全不一样,各种依赖冲突,足足折腾了两个通宵。后来把全部环境打包成Docker镜像,一条命令就解决了所有环境问题。
MLflow也属于这类“不起眼但关键时刻救命”的工具。早期做实验我完全不记录参数,经常遇到这种情况:上周跑出过一个效果很好的模型,这周想复现,但参数改过什么早就忘了。MLflow把每次实验的超参数、数据集版本、模型指标、模型文件全归档,实验管理变得清清楚楚。后面做模型上线、模型回归验证时,这些记录直接决定效率。
这些工具有一个共同特点:不学它们,模型照样能训练;但学了它们,整个AI工程周期会顺畅一个数量级。
3. 全流程实操:一个文本分类服务从零到上线
3.1 项目定义与需求拆解
理论说再多,不如手底下过一遍。这里用一个虚拟的场景来还原整个实操过程:做一个电商评论情感分类服务,输入一段中文评论,模型输出“正向”或“负向”,要求单条请求延迟在200毫秒以内,服务能稳定应对每秒50个并发请求。
这个需求很典型,麻雀虽小但五脏俱全,数据、训练、部署、监控都会碰到。
按照AI工程的思想,我先做需求拆解,而不是急着找模型:
- 数据:中文电商评论数据集,大约2万条,正负样本均衡。
- 特征方式:直接使用预训练中文BERT模型做文本编码,不在小数据上从零训练词向量。
- 模型:考虑到延迟要求,不能直接上超大模型,选用轻量级BERT变体(如6层结构)。
- 服务:FastAPI封装,Docker部署,暴露
/predict接口。 - 监控:记录请求量、延迟、预测分布,设置基础告警。
3.2 数据清洗与预处理的三个关键点
数据准备阶段最容易轻视,但它决定模型上限。我这次处理评论数据,做了三件关键的事:
第一,编码统一和无效字符清理。中文评论里全角半角混用、HTML标签残留、特殊符号乱飞。我写了一个统一的清洗函数,把所有Unicode标准化为NFKC形式,把标点统一,去掉无关符号。这一步看起来简单,但实际能把模型精度提升两三个百分点。
第二,去重和冲突标签检查。评论数据里经常有重复文本对应不同标签的情况,说明标注质量有问题。我的策略是保留出现次数最多的标签,同时把冲突严重的数据剔除,避免模型学到错误的知识。
第三,训练集和测试集的严格隔离。这里有个容易踩的坑:重复数据同时出现在训练集和测试集里,导致评估值虚高。我用文本内容哈希做了去重后再切分数据,确保同一条评论不会同时出现在两个集合里。
分享一个小技巧:数据清洗规则必须先在小批量样本上检查效果,再全量应用。我试过一次,直接全量清洗后才发现正则表达式漏了一种特殊情况,导致几千条样本被错误截断。先看小样、再跑全量,能省掉很多返工时间。
3.3 模型训练实验的完整记录
我的模型底座用的是HuggingFace上的中文预训练模型,选择了6层的轻量版本,层数少一半,推理速度比标准BERT快约40%。这个决定非常关键,因为需求里写了延迟要控制在200毫秒内。
训练过程分了三个阶段:
阶段一:Baseline实验。直接用预训练模型,在评论数据集上微调3个epoch,batch size为32,学习率2e-5。这里我不手动设置太多花哨的参数,先跑出一个基准指标。结果是验证集F1约0.92。这个数值说明两件事:预训练模型本身能力很强,数据质量也不错。
阶段二:关键参数调优。针对学习率和训练轮次做了一组小规模对比实验。学习率分别试了1e-5、2e-5、5e-5,训练轮次分别试了2、3、5。我发现2e-5配合3个epoch是最优组合,学习率过高(5e-5)会导致loss振荡,轮次过多(5)则出现明显过拟合——训练集F1逼近1,验证集反而下降。
阶段三:类别权重调整。数据本身正负均衡,不需要特殊处理,但我习惯性检查了类别分布,确认没有明显Bias后再进入下一步。
训练结束后,我把模型通过MLflow做了归档,记录下完整的参数组合、评价指标和模型文件。这一步不只是为了规范,更是为了后面模型回溯时不用对着代码猜。
3.4 模型服务化:把模型变成可调用的API
模型训练完,真正的工程挑战才开始。
FastAPI接口设计。我写了两个接口:一个/health用于健康检查,一个/predict用于情感推理。/predict接收JSON格式的文本,内部先做文本清洗和预处理,然后送入模型推理,最后返回类别和置信度。整个流程控制在几毫秒级,完全满足延迟需求。
一个性能陷阱:PyTorch模型推理默认是逐条进行的,遇到并发请求会排队。我做了两件事优化。第一,开启Torch的torch.no_grad()模式,关闭梯度计算,推理速度提升明显。第二,把模型加载到GPU上,并且用Batch方式处理请求——把并发请求攒成一个小批次,一次性推理,吞吐量大幅提升。
Docker部署。写了一个多阶段构建的Dockerfile,第一阶段安装依赖和下载模型文件,第二阶段构建精简运行镜像。这里有个重要细节:模型文件不能每次启动都现场下载,应当打包进镜像,否则启动时间会非常长,而且依赖外部网络不稳定。
一个关键配置:worker数量。我用Uvicorn的--workers参数启动多进程,但这里踩过坑:如果每个worker都加载一份模型,4个worker就要约8GB显存。后来我调整为1个worker加Batch推理的方式,显存占用降下来了,并发能力没怎么打折。这个取舍在真实项目中非常重要。
3.5 上线与压测的完整记录
部署完成后,我用Locust做了简单的压测。每秒50个并发请求,压测结果显示接口P95延迟在160毫秒左右,满足需求的200毫秒以内。这时候正好验证了之前的模型选型决策——如果用标准BERT,P95延迟很可能就超出限制了。
压测过程中还发现一个有意思的问题:CPU模式下的延迟波动特别大,GPU模式下就稳定很多,原因在于CPU模式下文本长度差异会导致推理时间差异明显。所以我在预处理阶段统一做了文本截断,把超过128个字符的评论截断,长尾推理时间被控制住了。
4. 线上监控与迭代:模型上线不是终点
4.1 监控什么:不只是服务器指标
模型服务上线后,我从传统运维监控思维跳出来,重新定义了几个关键监控项:
传统指标当然要盯:CPU、内存、显存、QPS、P95延迟、错误率。但AI工程更关注的是两个特殊的指标:
- 预测分布:模型输出的正负向比例。如果历史稳定在50%左右,某天突然变成80%负向,大概率是数据分布漂移了。
- 特征分布漂移:我定期对输入文本长度、关键词分布做统计,跟训练时期的数据对比。文本长度突然变长或变短,意味着来的请求已经偏离了模型训练的样本空间。
这两个指标是模型退化的早期信号。我在Grafana里做了折线图,每天观察一次,效果非常直观。
4.2 数据漂移的应对策略
监控发现漂移后不是立即重训,而是有一个循序渐进的手段。我的处理优先级是这样的:
- 轻度漂移:先看是否影响业务,如果只是用户表达方式变化但语义没变,可以先观察。
- 中度漂移:收集新样本,加入旧训练数据,做增量训练。
- 重度漂移:重新做数据标注、重新验证模型底座,必要时换模型。
我用了一个很简单的方式来量化漂移程度:把新请求的文本向量和训练集的质心向量做距离计算,距离超过某个阈值就触发告警。这个方案虽然朴素,但在实际项目中非常可靠,而且容易实现。
4.3 模型更新策略与A/B验证
模型不是训好了就永远不动。我的更新流程分三步:
- 影子部署:旧模型服务线上,新模型在后台同步接受请求,但不把结果返回给用户。连续运行几天,对比新旧模型的预测分布和性能。
- A/B测试:按请求量的小比例(比如5%)切流量到新模型上,对比业务指标。
- 全量发布:A/B表现稳健后,全量切到新模型,同时保留旧模型回滚通道。
这套流程让我避免了一次事故。那次新模型离线指标很好,但影子阶段发现它对某些特殊表达的输出分布异常,及时拦住了发布。整个模型更新流程有多重要,经历过一次就会刻骨铭心。
5. 实操路上的高频问题与排查技巧实录
5.1 训练不收敛:先别调参数,查数据
我带过新人,也踩过很多次训练不收敛的坑。多数情况下参数不是罪魁祸首,真正的问题出在数据上。典型的几种情况:
- 标签错乱,文本与标签不对应。
- 特征列包含了未来信息或ID类噪声特征。
- 预处理不当,比如缺失值填充逻辑错误。
排查顺序该怎么走?我一般是先可视化一批训练样本,人工检查文本和标签是否合理;再检查数据集的类别分布;最后才去调学习率、优化器。顺序反了,问题会越查越乱。
5.2 推理延迟超标:拆解每一个耗时环节
模型性能不达标时,我用Profile工具逐环节打点,看时间花在哪里。常见开销分布如下:
- 数据预处理和序列化:一些极端情况下占掉30%以上时间,是首先排查的点。
- 模型推理本身:如果是这个环节慢,就要考虑模型裁剪或者量化。
- 网络传输和反序列化:在分布式部署时容易忽略,需要检查是否有无效的重复序列化。
我遇到过一个场景:光预处理里的文本正则清洗就占了40%的延迟。优化方案是把清洗逻辑精简,减少正则回溯,延迟直接降了一半。
5.3 模型更新后线上效果反而变差
这个问题的常见原因有三个:
- 新模型虽然整体指标高,但特定场景处理风格变了,比如对某些词汇特别敏感。
- 数据切分方式变了,导致训练分布和上一版差异较大。
- 推理时是否沿用旧模型的预处理逻辑没有对齐。
处理办法是:更新前后对同一批历史请求做离线评估,输出逐条对比,找出风格差异;另外对比新旧模型的预测分布,异常变化早发现。
5.4 常见问题速查表
| 现象 | 第一排查点 | 常见解法 |
|---|---|---|
| 训练loss不降 | 数据标签与文本是否对应 | 可视化数据,检查预处理 |
| GPU显存不足 | batch size是否过大 | 调小batch或使用梯度累积 |
| 推理延迟高 | 预处理是否过度耗时 | 精简正则,开启batch推理 |
| 接口偶发超时 | 是否多个worker竞争GPU | 减worker,加batch |
| 线上指标和离线不一致 | 数据分布漂移 | 重新采样训练集,增量训练 |
6. 从零到一:最后再分享一点我的真实体会
回顾整条AI工程路径,从最初以为“会训练模型就够了”,到后来能独立完成数据、训练、部署、监控全链路,我自己最大的转变是视角的变化。AI工程师的核心竞争力,不在于调参多快,而在于能看清模型从数据到业务的完整路径,知道每一步的风险在哪里,出了问题能不能快速定位和修复。
如果你现在正走在从零开始学习AI工程的路上,我的建议很简单:别只对着教程敲模型,去拿一个真实场景的小项目,把数据清洗、模型训练、API封装、Docker部署、监控告警整个串一遍。哪怕这个项目很小,过程中遇到的所有坑,都会变成你下一份工作的资本。
最后分享一个小经验:永远保留模型历史版本和对应的数据版本。我在一次紧急回滚时深有体会,没有版本管理,你连“回滚到哪个模型”都说不清。把实验管理当作工程基建一样对待,这是我从零到一过程中养成的最高价值的习惯。