
如果有人问你“零基础能不能搞AI工程”我一般会反问一句你说的零基础是指不会写代码还是指没做过项目因为我见过太多人卡在“会调包但不会造轮子”和“会造轮子但不会上线”这两个阶段。而“ai-engineering-from-scratch”这个选题恰恰瞄准了从0到1搭建AI工程能力的完整过程不是教你看一篇论文然后跑通一个demo而是让你掌握一条能独立交付AI服务的链路。这篇内容适合这些人一是刚入行的算法工程师发现自己天天在用别人封装好的框架却说不清底层发生了什么二是想转行AI的软件工程师已经会写代码但不知道模型训练、数据流水线、推理部署这些环节该怎么串起来三是自己做独立项目的开发者想让产品具备AI能力但不想只当API的搬运工。文章会按照我实际验证过的路径来拆解该避的坑一个不落。1. 先搞明白AI工程师到底在做什么很多人对AI工程师的理解就是“调模型、写网络结构、跑训练”这个理解放在五年前还行放在现在会让人走很多弯路。我面试过不少简历上写着“熟练使用PyTorch/TensorFlow”的候选人一问到“你的模型上线后QPS能到多少”“显存不够你怎么处理”“数据漂移了你怎么办”基本就沉默了。这不是他们不行而是没人告诉他们AI工程的全貌长什么样。1.1 工程化才是门槛不是算法原理现在的AI落地算法创新早就不是最大瓶颈了。你去看那些真正赚钱的AI项目用的模型往往不是什么发在NeurIPS上的最新架构而是经典的ResNet、Transformer甚至是逻辑回归。难点在哪里难点在于让模型在真实环境里稳定跑起来。我见过一个很典型的例子一个做工业质检的团队模型在实验室里F1能到0.98结果上了产线之后因为相机角度、光照变化、来料批次差异F1直接掉到0.85。他们花了两周去调模型结构效果微乎其微后来把数据流水线改成在线增强、加入更多现场样本才把指标拉回来。所以AI工程师的核心能力本质上是在干三件事把数据变成模型能吃的东西、把模型变成能服务业务的东西、把服务变成能持续运维的东西。这三件事的复杂度远高于读懂一篇论文的网络结构图。1.2 从零构建的路径和普通人走的捷径市面上大多数入门路径是这样的先学Python再看机器学习理论然后跑几个公开数据集最后拿一个项目写到简历里。这条路径的问题在于每一步都是孤立的。你学了特征工程但不知道特征怎么在线上实时计算你学了模型训练但不知道怎么把模型打包成服务你学了部署但没处理过模型版本迭代。真正的from scratch路径应该是这样的先用一个端到端项目当骨架不管多简陋跑通“数据→训练→评估→部署→调用”全链路。再沿着链路逐个环节深挖遇到哪个环节不懂就补哪个环节。最后回到项目里重构把当初“能跑就行”的部分升级成“工程合格”的标准。这个路径看着慢实际上是最快的。因为每一步都有上下文你知道自己在干什么、为什么要这么干而不是对着课程目录一章一章地啃。2. 地基工程把Python写出工程味坦白说会用Python写脚本的人一抓一大把但能把Python写出工程味的人真的不多。AI项目里很多你以为的“模型问题”最后定位下来全是代码工程问题。2.1 虚拟环境与依赖管理别等到上线才后悔我见过太多项目用conda装了一堆包最后环境一塌糊涂连作者本人都不确定某个依赖是不是还需要。这里我的建议是从一开始就养成两个习惯每个项目独立虚拟环境用venv或conda都行但必须独立。依赖锁定用requirements.txt精确到版本别用这种范围约束。有人会觉得“我本地能跑就行了管那么多干什么”。等到你部署的时候发现numpy版本从1.24升到1.26某个运算结果变了模型输出对不上你就知道锁版本的用处了。我自己就吃过这个亏一个语义相似度服务本地测试结果和线上结果不一致排查了一天最后发现是transformers库版本差异导致的tokenizer行为不同。2.2 数据处理从pandas到高效流的进化初学阶段用pandas处理数据没有任何问题但你要认识到它的边界。我之前处理一份2亿行的用户行为日志用pandas读CSV直接内存爆掉。后来换成dask和pyarrow按列读取、分块处理才把任务跑完。更关键的是AI工程里的数据流通常是多阶段的采集、清洗、标注、转换、切分、验证。每个阶段都可能成为瓶颈。比如数据清洗你以为是简单的去重和填充空值实际上你可能要处理编码问题、时间戳格式不统一、字段值大小写不一致、同一实体的多种表达方式等等。我的习惯是给每个阶段写独立的处理脚本输出带校验的中间结果。这样任何一步出了问题你有据可查不用从头重跑。2.3 代码规范与版本控制这是团队协作的底线很多初学者没有意识到AI项目和其他软件项目一样是需要版本控制的。而且不只是代码要进Git数据集的版本、模型的版本、实验配置的版本都应该有记录。我自己的一个最低配置是这样的代码用Git管理主干分支保持可运行状态。实验记录用配置文件每次训练把超参数、数据路径、模型结构写到一个JSON里和模型文件一起保存。数据集变更时记录变更前后的样本数和关键统计量。这样做的好处是三个月后你回来看自己的项目还能说清楚当时为什么这么设置而不是面对一堆“model_final_v2_really_final.pt”的文件发呆。3. 亲手跑通一个端到端项目文本分类服务实战说再多理论不如直接上手一个项目。下面这个项目非常典型也是我一直推荐给初学者的第一个完整项目一个垃圾评论分类服务。听上去很简单对吧但简单项目才能让你把注意力放在工程链路上而不是被复杂的模型结构带走。3.1 数据准备标注质量决定模型上限做文本分类你可以去下载别人标注好的公开数据集比如中文的THUCNews、英文的AG News。但如果你想体验完整的工程流程我强烈建议你自己标注一份数据哪怕只有2000条。为什么因为只有自己标过数据你才知道数据标注里有多少让人抓狂的细节。比如“这个商品质量不错物流太慢了总体来说还是很满意的”——这算好评还是差评如果按多标签分类它应该同时属于“质量好”和“物流慢”。但如果你的业务只分好评差评那这条到底算哪种这不是模型问题是标注规范问题。你需要在动手之前定义清楚边界否则模型学到的就是一堆噪声。数据准备好之后按6:2:2的比例切分训练集、验证集、测试集。这里有个小技巧切分之前先把数据打乱但要固定随机种子保证每次运行结果一致。3.2 模型选型不是越复杂越好对于2000条数据规模的文本分类任务我劝你别上来就用BERT。用小规模的模型比如fastText或者TextCNN已经能跑到不错的基线。这样做有几个好处训练速度快迭代成本低你可以在短时间内尝试多种预处理和超参数组合。模型简单出问题容易定位原因。部署成本低CPU也能扛住推理。等到基线模型跑通之后你可以再尝试用一个预训练模型比如bert-base-chinese做对比。这个对比过程本身就是工程中常见的做法先有基线再迭代优化而不是一开始就上最贵的方案。3.3 训练脚本的结构设计这里给一个训练脚本的最小结构涉及关键点我会额外标注数据读取模块负责加载数据、做标签编码、划分数据集。预处理模块负责分词、构建词表或加载预训练tokenizer。模型定义模块和预处理解耦方便替换不同的模型结构。训练循环模块包括前向传播、损失计算、反向传播、优化器更新。评估模块在验证集上计算准确率、精确率、召回率、F1。日志模块打印训练过程中的loss和指标变化方便监控。写训练脚本最忌讳的是所有逻辑堆在几十个函数里看似每个函数都不长但数据流完全没法追踪。你应该让任何一个新同学拿到你的脚本能在五分钟内说清楚整个流程的数据走法。3.4 训练中的参数设置逻辑很多初学者喜欢到处复制超参数什么learning_rate2e-5、batch_size32抄完就跑。但参数的设置是基于一定逻辑的你需要理解而不是复制。以学习率为例如果你是训练一个随机初始化的小模型学习率通常可以设大一些比如1e-3到1e-2配合Adam优化器。如果你是微调预训练模型学习率就要小很多一般是2e-5到5e-5因为预训练权重已经学到了很好的特征表示学习率太大会破坏这些特征。另外batch_size的选择会影响训练的稳定性和收敛速度。显存允许的情况下batch_size大一些可以让梯度估计更稳定但太大也可能让模型收敛到泛化能力更差的极值点。我的经验是如果训练loss震荡得很厉害先把batch_size调大一倍试试。还有一个容易被忽略的问题类别不平衡。如果垃圾评论只占总样本的10%你用准确率做指标模型可以全程预测“正常”拿个90%的准确率然后毫无用处。这时候要看F1或者AUC并且在loss里给少数类加权。4. 部署与上线模型要真正跑起来才算完模型训练完了测试集上F1也漂亮但离“能用”还差得远。部署这个环节才是真正拉开普通算法工程师和合格AI工程师差距的地方。4.1 模型格式转换与推理框架选型训练好的PyTorch模型不能直接扔给生产环境用。通常你需要把模型转换成更轻量、更适合线上服务的格式。主流的做法有两种TorchScriptPyTorch官方方案适合在Torch生态里做优化。ONNX跨框架格式转换后可以用ONNX Runtime推理支持CPU和GPU加速。我用ONNX比较多。转换之后模型文件通常能压缩到原来的十分之一甚至更小推理速度和显存占用都有明显改善。这里有一个要注意的坑转换前必须把你的预处理流程用测试样本验证一遍确保模型的输入和你的预处理输出完全一致。我见过太多人在这一步翻车训练时用的是tokenizer的输出部署时直接给模型喂原始字符串。4.2 写一个正经的推理服务而不是跑个demo很多人觉得自己已经会部署了因为他们用Flask写了一个接口load模型之后调用model.predict()。但这和真正的生产级推理服务之间还隔着好几个层级。一个合格的推理服务至少要考虑以下几件事模型加载是启动时完成的不是每次请求都加载一遍这看起来像废话但我真的见过加载写在函数里的代码。批量推理与动态batch的取舍同一时间来的请求可以攒起来一起推理提高吞吐量。请求超时和失败重试策略模型推理不是免费的需要给请求设置超时时间。优雅的异常处理模型推理报错时接口返回的业务逻辑不能被暴露出去。我用FastAPI写过不少推理服务整体感觉比Flask更顺手自带OpenAPI文档配合uvicorn做ASGI服务器性能足够。一个最简的推理服务结构大概是这样启动时加载模型写一个/predict接口接收文本请求请求进来后走预处理、模型推理、后处理最后返回格式化的JSON结果。4.3 性能优化吞吐、延迟与成本的平衡部署上线之后你迟早会遇到性能问题。一个模型推理需要50毫秒看起来很快但如果你的接口QPS只有10用户的平均响应时间会变成多少加上网络开销和并发排队很容易超过500毫秒这就很难接受了。性能优化的顺序我建议按照影响从大到小来排模型剪枝和量化把FP32变成FP16或者INT8推理速度提升两到四倍。分布式推理多实例部署配合负载均衡简单粗暴但有效。推理框架调优ONNX Runtime的线程数、执行模式等参数。GPU和CPU选型小模型在CPU上够用就别浪费GPU资源。关于量化这里多说一句量化不是无损的有些敏感任务做完之后指标会掉。你在上线前必须用真实测试集重新评估量化后的效果把指标下降控制在允许范围内否则上线之后用户反馈变差你连原因都不好找。4.4 监控没有监控的部署就是盲人摸象我自己早期做过一段没有任何监控的部署模型上线之后用户反馈才意识到出了问题。后来我学乖了部署服务之前先把监控想好至少要有以下几项在线指标QPS、请求耗时、成功率和错误率。推理延迟包括模型推理耗时和全链路耗时。数据漂移线上请求的输入分布和训练集分布是否有明显变化。模型预测分布预测结果的置信度分布是否正常比如分类任务里是不是所有样本都集中在某一个类别。监控不难难的是养成这个习惯。你可以用Prometheus加Grafana这套组合社区成熟、资料丰富、上手成本可控。就算没有基础设施也应该在日志里记录下请求和响应的关键字段出了事至少有迹可循。5. 在没有真实业务的情况下怎么积累工程经验这个问题的潜台词是我做了很多练习题和课程项目但感觉和真实的AI工程完全不是一回事。这很正常因为课程项目本身就屏蔽了工程复杂性。但我们可以主动去模拟这种复杂性不用非得等到上班才学。5.1 用开源项目补足工程视野GitHub上有大量可以学习的项目我挑三个方向给大家参考搜索引擎类看看别人怎么处理大规模文本索引和召回排序。推荐系统类观察特征工程和在线推理的衔接方式。对话系统类体会一个有状态的服务如何管理上下文。读这些项目的重点是读工程结构不是读模型代码。你要关注的是他们怎么组织代码、怎么管理配置、怎么处理失败、怎么保证可观测性然后把思路迁移到你的项目里。5.2 给自己造一个“伪生产环境”没有真实业务不等于你不能模拟真实环境。我建议你把自己的个人项目当成一个正经产品来对待要求如下代码必须进Git必须写README。训练和推理必须分开跑训练的实验脚本和上线用的推理服务是完全不同的代码路径。必须有部署产物不管是Docker镜像还是打包好的服务文件。必须有监控指标哪怕只是用日志简单记录请求量。当你能把一个Demo项目做成“可以给别人用”的状态你就已经获得了一半的工程能力。剩下的一半是在真实环境中踩坑积累出来的但你已经有了基本的判断力到公司之后学习效率会高很多。5.3 面试和工作中脱颖而出的关键点把这个路径走完之后你和普通候选人的差别就出来了。面试官如果看重理论你可以讲清楚Transformer的self-attention机制如果看重工程你可以拿出一个端到端的项目详细说明数据怎么处理、模型怎么部署、性能怎么优化、线上出问题了怎么排查。我面试过一些让我印象深刻的候选人他们都有一个共同特质对自己做过的东西有完整的上下文。他们不会只说“我用BERT做了文本分类”而是会主动提到“当时数据标注规范是怎么定的”“基线模型是用了什么”“部署时遇到什么问题怎么解决的”。这种项目感是刷题和看课学不来的。最后分享一个我踩过几次坑之后形成的习惯在动手开始一个AI项目之前先花半小时把整个链路在纸上画一遍标出每一个环节的输入输出和依赖关系。哪怕画得不规范也没关系这个动作逼着你想清楚全局而不是走一步看一步。我很多项目的返工都是因为一开始少想了一个环节多花的返工时间远超当初省下的半小时。