
ai-engineering-from-scratch这个名字我在本地仓库里建了不知道多少遍。每次有人看到它都会问我都2025年了开源框架一大把大模型API随便调还谈什么从零开始我的回答通常就一句话框架能帮你跑通模型但帮不了你修好一个烂掉的数据管线也帮不了你判断一个指标是不是在骗你。这两件事才是AI工程真正值钱的地方。这篇文章就是围绕这个仓库展开的。我会把我自己从会用几个库到能独立搭一套AI系统的完整路径拆开来讲包括技术栈怎么搭、为什么要手写一次神经网络、从Demo到上线到底差了哪些环节以及我踩过的那些能让你省下几个星期的坑。适合刚入行的算法同学、想转AI方向的传统后端开发也适合那些已经会用框架但总觉得差点底层感觉的调包侠。1. 先搞清楚AI工程到底在工程什么很多人分不清机器学习和AI工程的区别更分不清AI工程师和研究员的区别。这个如果一开始就搞混后面所有的学习路径都会走偏。1.1 AI工程不是调库而是一整套系统工程我见过太多人学AI的第一步是跑通一个CNN第二步就觉得自己是AI工程师了。真不是。一个AI系统从想法变成稳定的线上服务至少要经历这样的闭环数据采集与清洗 → 特征工程 → 模型训练 → 模型评估 → 服务化部署 → 线上监控 → 数据回流迭代。模型训练只是其中一小段甚至不是最耗时的一段。我自己的经验一个真实项目里数据清洗和特征工程要占掉60%以上的时间模型选型和调参可能只占20%剩下全部是部署、监控、评估、和业务方对齐预期。所以说AI工程本质上是数据工程 模型工程 软件工程三者的交叉地带。你以为你在写模型其实你大部分时间在写数据处理代码、写评估脚本、写接口、写监控告警。1.2 AI工程和传统软件开发的本质差异从传统后端转来做AI工程最容易踩的坑就是把模型当成一个普通函数。代码确实长得像个函数输入特征输出预测。但它和传统函数的底层逻辑完全不同。我列一张表大家可以对照着体会维度传统软件开发AI工程输入输出确定性逻辑同输入必同输出概率系统同输入可能不同输出错误定义Bug有明确因果关系错误隐藏在高误报或漏报里测试方式单元测试断言具体值评估指标衡量统计表现上线流程代码评审后直接部署模型效果评审 数据管线检查 灰度核心瓶颈代码逻辑复杂度数据质量、分布漂移、算力成本迭代周期分钟到小时级别通常以天、周为单位这也能解释为什么很多技术很强的后端转AI时会很挫败你修了半天代码结果模型效果还是不行因为问题根本不在代码里而在训练数据的分布里。反过来传统的那套强方法论——版本管理、模块化、自动化测试、可观测性——放到AI工程里一样适用只不过要针对概率系统的特点改造一下。1.3 现在从零开始时机到底对不对这个我经常被问。我的判断是现在恰恰是从零开始学AI工程最好的窗口期原因有三个。第一基础设施前所未有的成熟。开源模型、向量数据库、推理框架、托管平台都齐了个人开发者用很低的成本就能做出过去一家公司才能做的东西。第二大家在经历AI应用大爆发的初期。这个时候稀缺的不是训练一个大模型的科学家而是能把这些能力稳定落地到具体业务场景里的工程师。这恰好是AI工程这个定位的位置。第三有一定经验的开发者入行有天然优势。工程能力是AI工程师最稀缺的底色之一。会写稳健的代码、理解分布式系统、懂DevOps的人只需要补齐模型和数据这块知识就能很快上手。所以别再纠结现在起步是不是晚了。AI工程不是一个靠背题库能通关的考试它是一个不断有新问题出现的领域。你要学的不是某一个框架的API而是诊断和解决AI系统问题的能力。2. 从零搭建技术底座环境、Python、数学与数据工欲善其事必先利其器。这里说的器不只是软件还有你脑子里的概念脚手架。我见过科班出身数学很强但写不出工程代码的人也见过代码很强见公式就晕的人。AI工程恰恰需要两头都够用。2.1 环境准备别再用Anaconda一键装全家桶了先说我推荐的起步环境。直接用Python 3.10以上的官方版本加venv虚拟环境就够了。很多新手上来就用Anaconda结果环境乱到亲妈都认不出来——conda管理的是整个环境目录pip管理的是当前环境里的包两者混用出问题你根本不知道去哪里排查。我习惯这样建环境python -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate pip install --upgrade pip pip install jupyter numpy pandas scikit-learn matplotlib这套组合足够你跑完前三个月的所有练习。等真正进入深度学习阶段再装PyTorch也不迟。千万别一开始就装全套CUDA、cuDNN、PyTorch、TensorFlow、LightGBM全部安排上你花在解决环境冲突上的时间会比学AI的时间还长。2.2 最精简的数学弹药库会算就行别被公式劝退市面上劝退人的数学书一本比一本厚。但AI工程日常用到的数学其实范围非常窄。我按优先级排一下线性代数必须掌握矩阵乘法、转置、形状变换这几个操作。神经网络前向传播就是一层层矩阵乘法反向传播本质上是矩阵形状的对接。你要能在脑子里看到维度不匹配就立刻知道哪一层写错了。概率与统计理解分布、期望、方差、最大似然的直觉。不需要会推导复杂定理但要知道模型输出的是一个概率分布这个核心含义以及过拟合、正则化跟概率的关系。微积分核心就是链式法则。反向传播就是链式法则的应用。会求导、会复合函数求导就够起步了。我的经验是数学不必先修完再上手。先写代码触发疑问再回头补理论效率远高于先啃三个月的数学教材再动手。比如你手写一次反向传播之后对梯度的理解会比看十遍视频都深刻。2.3 数据直觉AI工程真正的原材料工程如果说数学是内功数据直觉就是AI工程师的吃饭手艺。模型框架是公开的谁都能用但同一份原始数据有人能洗出黄金特征有人怎么跑都过不了基线差别就在这里。起步阶段我建议你做两件事。第一培养看数据先看分布的习惯。拿到一个csv先不要急着喂给模型。看一下每列的缺失率、数据类型、数值范围对目标变量做一下分布直方图看是否偏斜。很多问题从这一步就能提前发现。第二理解数据的信号到底在哪。比如做文本分类你需要关心的不只是词频还有类别间的区分性表达做时间序列预测你要关心的不仅是历史值还有周期性、趋势、节假日效应。这些直觉只能靠大量接触真实数据集培养。再强调一点数据泄漏是AI工程的头号事故源。什么叫数据泄漏就是你在训练时用了未来的信息或者测试集的信息无意中混进了训练过程。比如你在划分数据集之前就对全量数据做了标准化那你已经泄漏了。我后面会有专门章节讲这件事。3. 不带框架手写一个最小神经网络把反向传播焊死在大脑里我认识的所有能独立完成AI项目的人几乎都有一个共同点他们至少手写过一次反向传播。哪怕之后一辈子都在用PyTorch那一次手写也值回票价。为什么因为反向传播是整个深度学习最核心的引擎你对它的理解程度决定了你调试模型时的思考速度。3.1 为什么我强烈建议你手写一次框架把反向传播封装成了loss.backward()一行代码它看起来简单但也正是这种黑盒感让很多人的调参变成玄学learning rate设大了为什么发散、网络层深了为什么梯度消失、用sigmoid在深层网络为什么收敛慢。这些问题如果你亲自动手写过一次前向和反向哪怕只写一个两层网络你都会从猜测变回推理。打个比方自动驾驶已经很成熟了但驾校还是要让你学手动挡。不是为了让你以后开手动挡而是为了让你理解发动机和变速箱的配合逻辑。同理手写反向传播不是为了让你在业务里不用PyTorch而是为了让你理解框架那几行代码背后到底发生了什么。3.2 完整代码用NumPy实现一个两层神经网络我用一个最简单的二分类任务来演示输入一个二维平面的点输出它属于正类还是负类。网络结构是2-4-2隐藏层用sigmoid激活输出层用softmax损失用交叉熵。import numpy as np def sigmoid(x): return 1 / (1 np.exp(-x)) def sigmoid_derivative(a): return a * (1 - a) np.random.seed(42) X np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtypefloat) y np.array([[0, 1], [1, 0], [1, 0], [0, 1]]) # 模拟XOR感知问题 n_input, n_hidden, n_output 2, 4, 2 learning_rate 0.5 W1 np.random.randn(n_input, n_hidden) * 0.1 b1 np.zeros((1, n_hidden)) W2 np.random.randn(n_hidden, n_output) * 0.1 b2 np.zeros((1, n_output)) def softmax(z): exp_z np.exp(z - z.max(axis1, keepdimsTrue)) return exp_z / exp_z.sum(axis1, keepdimsTrue) for epoch in range(5000): # 前向传播 z1 X.dot(W1) b1 a1 sigmoid(z1) z2 a1.dot(W2) b2 a2 softmax(z2) # 交叉熵损失 loss -np.mean(y * np.log(a2 1e-9)) # 反向传播 dz2 a2 - y dW2 a1.T.dot(dz2) / len(X) db2 np.sum(dz2, axis0, keepdimsTrue) / len(X) da1 dz2.dot(W2.T) dz1 da1 * sigmoid_derivative(a1) dW1 X.T.dot(dz1) / len(X) db1 np.sum(dz1, axis0, keepdimsTrue) / len(X) # 参数更新 W2 - learning_rate * dW2 b2 - learning_rate * db2 W1 - learning_rate * dW1 b1 - learning_rate * db1 if epoch % 1000 0: print(fepoch {epoch}, loss {loss:.4f})这段代码不到40行但它展示了深度学习训练的所有关键环节前向传播计算输出、损失函数衡量差距、反向传播逐层计算梯度、梯度下降更新参数。3.3 逐行拆解前向、损失、反向、更新到底在干什么前三步是最容易困惑的我逐个说清楚。前向传播中权重W1负责把输入的特征映射到隐藏空间sigmoid做非线性变换。这里有一个关键点如果没有非线性激活函数多层线性变换叠加起来仍然是一个线性变换堆多少层都跟一层没有区别。所以sigmoid存在的意义不只是把数值压到0到1而是给网络注入非线性表达能力。损失函数这里用的是交叉熵它衡量的是模型预测的概率分布和真实标签分布之间的差距。取负对数的数学直觉是模型对正确类别给的概率越接近1这一项的损失越接近0。用-np.mean(y * np.log(a2 1e-9))里加的1e-9是为了防止log(0)导致数值爆炸这是实际编程里很常见的防御性写法。反向传播是整个代码的灵魂。我先说结论损失函数对某一层参数的梯度等于误差信号乘以这一层的输入转置。以第二层为例dz2 a2 - y这个式子看起来简单实际上是交叉熵损失对softmax输入求导后的简洁结果——softmax和交叉熵组合在一起时梯度化简成了预测值减真实值。如果你单独使用均方误差就不会得到这么干净的表达式这正是交叉熵配合softmax在分类任务中如此流行的原因。3.4 手写之后你获得的内功会回报你很久跑通这段代码之后你至少能获得四个层面的理解。第一你知道了loss.backward()到底算了什么所以在PyTorch里遇到梯度为None、梯度爆炸这类问题时不慌你知道问题大概率出在传播路径上。第二你理解了学习率为什么不能盲目调大。看上面代码learning_rate直接乘在梯度上调太大一步参数更新就跨过最优点损失原地起飞。手写一次你会真正感受到这种不稳定的发生过程。第三你知道了为什么初始化权重不能全设成0。如果W1全为0所有隐藏神经元接受同样的输入反向传播时梯度也一模一样神经元退化成同一个节点网络就失去了表达能力。第四你会发现这个迷你网络跑得非常慢然后你会由衷地感激GPU和PyTorch在研究效率上的贡献。4. 从Demo到产品AI工程化的关键环节一个都别省学模型的同学最容易忽略的是能跑通到能上线之间这段路。我自己在第一个项目上就吃了大亏本地Notebook里模型准确率95%自认为稳了结果上线之后线上效果一塌糊涂。回头看全是工程化环节出了问题。4.1 数据划分训练/验证/测试顺序一步错就会数据泄漏很多初学者拿到数据直接train_test_split一刀切然后开始训练。问题来了你反复用测试集调参测试集其实已经变成了训练集的一部分最终评估结果必然虚高。正确姿势是三层划分训练集用来拟合模型参数。验证集用来选模型、调超参、做早停。测试集只允许在最终定稿时碰一次用来做最后的无偏评估。时间序列数据还要更严格一点不能用随机打乱的方式切分必须按时间顺序保留。比如你要预测明天训练数据就只能是昨天及以前如果你把后天的数据放进训练集就是标准的未来函数泄漏。另一个高频泄漏场景是标准化。有些同学用scikit-learn先对全量数据做StandardScaler再切分数据这是错的。正确的做法是只在训练集上拟合scaler再用同一个scaler变换验证集和测试集。为什么因为测试集代表未知新数据模型不能提前见过它的统计信息。你需要记住泄漏不会让你的模型变好只会让你对它过度自信上线的时候加倍还回来。4.2 评估指标别再只盯准确率你的前任就是这么翻车的分类任务直接看accuracy是最典型的新手操作。举个真实例子银行反欺诈场景中欺诈样本通常占比不到1%。你做一个模型把全部样本都预测为非欺诈准确率高达99%但这个模型一文不值因为它一个欺诈都没抓到。这类场景你需要看的是指标关注的问题适用场景精确率 Precision预测为正类的样本有多少是对的垃圾邮件拦截误伤正常邮件代价高召回率 Recall真正的正类样本有多少被找到癌症筛查、欺诈检测漏掉代价极高F1分数精确率和召回率的调和平均类别不均衡、不想偏重某一边AUC排序能力不依赖具体阈值输出分数做排序的场景PR曲线极不均衡时比ROC更真实欺诈、罕见病、广告点击所以确定评估指标应该在做模型之前就和业务方对齐**你更怕误报还是更怕漏报**这个问题的答案直接决定了你模型训练的侧重点。4.3 实验管理让每一次尝试都可追溯否则你会悔到肠子青我早期做实验很随意改个参数跑一遍看一眼数字觉得差不多就扔一边。等过了两个星期发现自己调出了一个效果特别好的配置却完全想不起来当时用的随机种子是多少、数据有没有做清洗版本、学习率是多少。这种痛苦我相信不少人经历过。现在无论用MLflow、Weights Biases还是简单的CSV表格我建议从第一天就强制自己记录实验。一条记录至少包含数据集版本或文件hash特征列表与预处理方式模型结构与关键参数优化器、学习率、batch size、epoch数随机种子验证集指标和测试集指标一句话备注本次实验想验证什么假设、结论是什么别小看这个习惯。工程化的本质就是可重复、可追踪、可回滚。没有实验记录你的模型调优就是散点式撞运气有记录之后就会变成逐步逼近的搜索过程。4.4 部署与监控模型上线只是开始不是结束模型上线之后真正的挑战才刚开始。你需要面对的问题是线上数据的分布会变用户行为会变模型会悄悄变质。这就是概念漂移和数据漂移。部署层我建议从简单的标准服务化做起。把一个训练好的模型包装成一个HTTP接口用FastAPI就能轻松搞定这里给一个最小示例from fastapi import FastAPI from pydantic import BaseModel import joblib app FastAPI() model joblib.load(model.pkl) class Item(BaseModel): features: list[float] app.post(/predict) def predict(item: Item): prob model.predict_proba([item.features])[0][1] return {fraud_probability: prob}监控层至少要盯三件事请求量与延迟确认服务本身是健康的。预测分布定期对比线上预测值与上线前的分布比如送餐时长平均从30分钟变成45分钟模型的时间观念已经失衡了。实际效果标签回流有些场景能拿到真实结果比如用户会不会点击要定期把线上真实反馈拉回来重新计算当前的精确率、召回率。没有监控的模型上线就像不带仪表盘的飞机起飞——你可能成功起飞了但永远不知道自己什么时候在失控。4.5 一个最小MVP案例把前面所有环节串起来与其读一堆抽象原则不如上手做一个端到端最小案例。我第一次完整做完的项目是二手手机价格预测。你可以选一个类似的小数据集然后强迫自己按下面顺序走完对数据进行探索性分析画分布查缺失。按时间或随机划分训练/验证/测试三份先标准化再进模型。先跑一个线性回归作为baseline别一上来就堆模型。做一次特征工程观察对验证集指标的影响。训练一个树模型对比baseline并选择最好的配置。记录所有实验到CSV表格。把最终模型用joblib保存用FastAPI包成接口。写一个简单的监控脚本每天检查输入特征分布和预测均值。这个流程走一遍比你零散刷10个教程都管用因为它是完整闭环。5. 我的学习路线图与踩坑清单前面讲完了是什么和怎么做这一节我分享一条经过验证的路线还有我花了真金白银学费换来的坑。5.1 给不同基础的人定制的四阶段学习路线我自己把从零到能独立做AI工程项目的路径分成四个阶段每个阶段都有明确产出第一阶段Python 数据操作基础2到4周目标不是精通Python而是能自由地操作数据。学会列表推导、字典、函数、类的基础用法然后重点掌握Pandas的DataFrame操作筛选、分组、聚合、合并。结合Jupyter跑起来找手感每天写一点脚本处理公开数据集。第二阶段核心算法手写 sklearn上手4到6周完成前面那个两层神经网络的NumPy实现再学一遍线性回归、逻辑回归、决策树的基本原理。然后用scikit-learn跑几个经典数据集理解fit、predict、score这套标准接口。这一阶段的核心产出是你能不看框架说明独立写完一个模型的训练和评估流程。第三阶段深度学习框架 一个完整项目6到10周选PyTorch从Tensor的创建和自动求导开始搭一遍全连接网络和卷积网络。然后找一个自己感兴趣的小课题比如中文评论情感分析、图像分类、租房价格预测按照第4章那套MVP流程走完。不要贪大项目小没关系环节要全。第四阶段生产工程化 读源码持续进行学Docker、模型部署、推理加速的基本操作给项目加上日志、监控、版本管理尝试阅读框架中某个模块的源码比如PyTorch的DataLoader迭代器是怎么工作的。这个阶段没有终点但你已经具备独立的工程判断力。5.2 我踩过的几个坑每个都能帮你省下至少一星期这里有五个坑不是什么新手常见错误那种水话都是我真金白银踩出来的。坑一环境版本错乱。有一次我用了两年前的旧项目代码直接在当前Python 3.11环境里跑numpy 1.x和2.x的API差异导致报错一屏一屏地刷。从那以后我只信任两样东西requirements.txt和独立的虚拟环境。每个项目固定住依赖版本才能保证实验可复现。坑二被验证集指标骗了上线即打脸。我之前参与过一个分类项目离线AUC高达0.98上线后效果却明显匹配不上复盘发现是训练/测试划分之前我先做了一层缺失值填充填充逻辑用了全量数据的平均值——这又是一种很隐蔽的泄漏。现在我的原则是任何基于统计量的预处理都得划分完数据之后再做。坑三一上来就堆复杂模型。我早期拿到任务就想上BERT、上大模型结果数据量小跑出来还不如线性模型。后来养成习惯先做baseline用最简单的模型、最少的特征跑出一个合理下限然后在此基础上找改进空间。这个过程能帮你判断是数据问题、特征问题还是模型能力问题比盲目上SOTA模型效率高得多。坑四不记录随机种子。同一个模型跑两次结果不一样这是正常的。如果不固定np.random.seed和torch.manual_seed你的实验就不具备可复现性你今天发现加了A特征效果提升明天可能因为随机波动完全复现不出来。记住不固定种子得出结论的实验都是不可靠的。坑五在Notebook里做开发把生产代码也写在Notebook里。Notebook适合探索不适合运维。我经历过一个项目训练代码全在Notebook里要线上重新训练时没有人敢点那个执行按钮。现在我的习惯是探索阶段用Notebook一旦确认方向立即可靠地把核心逻辑抽成.py脚本保持模块化、可测试、可命令行调用。5.3 三个让我进步最快的小习惯最后分享几个日常工作习惯它们让我保持了长期稳定成长。第一个是每天精读一个开源库的函数源码。不用贪多一天一个就行。比如今天看scikit-learn的train_test_split内部怎么保证类别分布均衡明天看PyTorch的DataLoader怎么做多进程数据加载。半年积累下来你对工具的理解深度会甩开大多数人一个身位。第二个是每次实验都强行写一行总结。为什么改这个参数预期是什么结果和预期是否一致一行就行不用长文。复盘的时候会发现大量被验证的思路其实都指向同一个结论这能帮你快速收敛方法。第三个是每周花一点时间复现公开baseline。找一个论文的公开代码不看代码自己用类似思路实现一遍再和开源实现对比细节差异。这是把纸上知识变成手上能力最真实的方法。我在实际做ai-engineering-from-scratch这个项目时最深的体会是从零开始不是说所有组件都要自己造一遍而是你对一条链路从头到尾都有掌控力。你不知道某个环节的内部逻辑真出问题时你只能对着日志干瞪眼你知道了哪怕你用的全是黑盒工具也能靠推理一步步逼近问题根源。最后再提一个小建议——选一个真实的小数据集带上第4章的所有环节走一遍完整流程做完之后你再回头看框架文档会觉得每一个概念都有了落地的坐标。