
做AI工程最让人困惑的不是学不会而是不知道先学什么、学到什么程度、学完怎么用。“ai-engineering-from-scratch”这类标题在 GitHub 上出现得越来越多但点进去要么是几十个教程链接的收藏夹要么上来就是一套深度学习的复杂公式对零基础的人完全不友好。我把自己从只会写 Python 脚本到独立完成 AI 项目的整个路径沉淀成一套可复制的工程化学习方法它不要求你先啃完一整本数学教材也不要求你刷完市面上所有热门课程而是围绕“从零构建一个真正能用的 AI 系统”来倒推每一步该学什么、该做什么。这篇内容适合两类人一是刚入行想走 AI 方向但不知道怎么规划时间的同学二是已经在写代码但总觉得“只会调包、不懂原理”的工程师。按这条路线走下去你得到的不只是知识清单而是一条能逐步跑通的实战路径。1. AI 工程到底是做什么的先看清它和算法研究、数据分析的边界很多人对 AI 工程的理解是“训练一个模型、调一调准确率”这其实把这件事想窄了。AI 工程的全链路包含数据获取与清洗、特征工程、模型训练与评估、部署上线、监控迭代。当你从零开始做最容易卡住的环节往往不是模型本身而是数据和服务化。1.1 同一张“AI 帆布”下的三种角色到底有什么不同我会把 AI 圈子里的工作粗分成三类算法研究员、数据分析师、AI 工程师。前者探索新模型结构论文和创新是核心产出分析师的战场在离线报表和商业洞察上而 AI 工程师的职责是让模型稳定、高效地在生产环境里跑起来。角色核心产出主要工具链最考验的能力算法研究员论文、创新结构PyTorch、数学推导创新能力、数学功底数据分析师报表、洞察结论SQL、Pandas、可视化业务理解、逻辑表达AI 工程师可用系统、稳定服务Python、MLOps、后端工程权衡、问题定位三者有交集但学习路径完全不同。想让职业生涯走得更稳从工程切入是最好的选择因为它不用你一开始就在数学证明上达到很高深度却能逼你把“技术纸上谈兵”变成“能跑通的东西”。1.2 为什么“从零开始”容易沦为空谈因为你被“教程地狱”绑住了市面上大量的“从零开始学 AI”资料都是把三个知识体系混在一起倒给你数学基础、模型原理、工程工具。没有经验的人学了一个月最后连“我该用哪个框架”心里都没数。我踩过的坑就是第一轮学习时贪多三天换一个主题结果只积累了文件夹。from-scratch 的核心思路其实更像“滚雪球”先做第一个极小的、能完整跑通的东西再围绕它扩展。比如第一个目标不是“做出一个 ChatBot”而是“把一份文本分类的数据集训练到可用的准确率并封装成 API”。后者包含学习所需的全部核心要素却可以把复杂度压到最低。我后面所有实操的内容都是围绕这个思路展开的。2. 从零开始的保姆级学习路线自下而上比网上的“速成课”靠谱得多网上有很多 48 小时学 AI 的速成课程我基本不推荐。原因很简单速成课教的是“怎么在高层次上描述模型”而不是“怎么在遇到各种奇怪错误时把它修好”。用我的方法大约需要 4~6 个月每天投入 2~3 小时。下面按阶段拆解。2.1 第一阶段数学只学三大块别去啃完整教材绝大多数 AI 初学者听到“数学基础”就会退三步。其实从工程视角看你不需要学完整的高等数学只需要三块运算法则线性代数中的矩阵乘法、转置、形状变化微积分里的导数与链式法则理解梯度下降的方向概率论中的条件概率与极大似然估计我不推荐直接去啃教材。更高效的方式是“用模型理解数学”先跑一个线性回归把损失函数、导数、更新公式三行代码一起看比做一百道习题都有用。我当时花了三天写了一个“用 numpy 手写线性回归”的小脚本虽然代码很粗糙但从那以后所有框架里的 Dense 层、learning rate 都变得具体起来。基础不必一次性学完。学到后面遇到具体问题时再回来翻记忆会牢固得多。我自己到现在还会因为温习“为什么优化器要分 Momentum 和 Adam”而去翻数学笔记这种查漏补缺比集中轰炸效果更好。2.2 第二阶段Python 不用学全围绕数据操作来学就够了AI 工程里的 Python 学习范围和传统后端开发差别很大。你不需要精通装饰器、元类、异步编程但必须对四类操作烂熟于心数据加载与清洗Pandas 的read_csv、dropna、fillna数组运算与向量化NumPy 的矩阵变换、广播机制数据可视化Matplotlib 和 Seaborn 的画图基本操作脚本组织与依赖管理函数、类、虚拟环境、requirements.txt判断自己是否掌握的标准很简单给你一个 10 万行的 CSV你能不能在 5 分钟内完成“读取、查看缺失值、处理异常、提取特征列并输出为新的数据集”这个流程。多数速成课不会专门强调这套能力但它才是工程里的“地基工程”。2.3 第三阶段机器学习原理 深度学习框架两条腿同步走走到这里很多人的下一步就是直接开 PyTorch 或 TensorFlow 的教程。我的建议是先慢半拍认真跑几个传统模型逻辑回归、决策树、随机森林。原因有二其一传统模型训练时间短、参数少特别适合观察“欠拟合”和“过拟合”这种手感是直接调深度学习模型很难获得的。其二深度学习框架的抽象层级高很多概念如 batch、epoch、learning rate在传统模型里不用学但一旦遇到深度学习理解不透就会像看天书。先花三周左右用 sklearn 在同一个数据集上训练 3~5 个模型比较它们的准确率和 F1然后用 PyTorch 搭一个全连接网络重新做一遍同样的分类任务。你可以直观看到传统方法和神经网络之间的性能差异也能建立起“不同模型解决不同问题”的判断力。2.4 第四阶段工程化四件套——Docker、Git、CI/CD、监控在真正的业务系统里模型训练只占 20% 的工作量剩下 80% 都是工程化的事情。这四件套从零开始就要接触不用精通但必须会基本操作Git每天提交代码养成写清晰 commit message 的习惯Docker给模型写一个能完整复现运行环境的镜像CI/CD用 GitHub Actions 或 GitLab CI 做自动化测试和部署监控记录模型在线上推理的延迟、吞吐量以及输入分布的变化我见过太多人模型训练得很好却因为不知道怎么把服务丢到云端最后项目只能停留在笔记本的 Jupyter Notebook 里。工程化能力是“从零开始”到“从零到一”的桥梁它决定着你做的东西能不能被别人用上。3. 实战走一遍从零搭建并部署一个文本情感分类系统下面我用一个具体项目把所有知识点串起来——给 IMDB 影评做情感分类正面/负面并把它部署成一个 HTTP 服务。这是一个非常经典的任务难度适中且能覆盖全链路很适合做你的第一个 from-scratch 项目。3.1 项目定档为什么选文本分类而不是图像或推荐系统先说选型逻辑。图像识别需要解决数据增强、GPU 显存、复杂网络结构等问题对零基础来说门槛偏高推荐系统依赖用户行为数据和评价指标的特殊性工程链路较长而文本分类可以直接从公开数据集拿数据建模思路直观部署需要的服务器配置也不高。这个项目能把所有核心环节串起来数据获取与清洗文本特征工程TF-IDF 或词向量模型训练与超参数调整评估与误差分析服务化部署FastAPI Docker3.2 环境准备与依赖安装少走弯路不管用什么系统都要先准备一个干净的 Python 3.10 环境。这里强烈建议用虚拟环境否则后面各种包的版本冲突会让人抓狂。python -m venv venv source venv/bin/activate # Windows 下执行 venv\Scripts\activate pip install pandas numpy scikit-learn pip install torch # 按官网命令选择适合自己机器的版本 pip install fastapi uvicorn joblib我习惯把joblib加上因为传统模型的持久化用它最简单。装完依赖后建议跑一下python -c import torch; print(torch.__version__)确认框架能正常调用。这里如果装的是 CPU 版 PyTorch也没有关系这个项目对算力的要求并不高。如果发现安装慢国内用户可以把 pip 源换成清华或阿里云的镜像速度会快很多。但要注意混用不同来源的包可能导致依赖冲突所以尽量使用同一个镜像源并锁定版本号。3.3 数据获取与清洗原始文本变成干净训练集利用datasets库一条命令就能拿到 IMDB 数据集。更保险的方式是直接去斯坦福的公开页面下载 CSV 文件。以后自己做项目时数据格式可能很脏所以清洗步骤值得认真写。import pandas as pd df pd.read_csv(IMDB Dataset.csv) print(df.head()) print(df[sentiment].value_counts())这个数据集比较干净但依然要处理几个问题去掉 HTML 标签。统一小写英文语境下。过滤掉过短或过长的评论。import re def clean_text(text): text re.sub(r[^], , text) text text.lower() text re.sub(r\s, , text).strip() return text df[clean_text] df[review].apply(clean_text) df df[df[clean_text].str.len() 50]这里有一个坑我得特意提一下不要轻易去停用词如 the、a、is。很多人一上来就把它们删了但在情感分类里像“not good”这样的否定表达如果被拆掉会直接影响语义。清洗时尽量做“保守处理”只去除明显的噪音。3.4 特征工程为什么先用 TF-IDF 而不是直接上 BERT深度学习时代很多教程会直接从预训练模型开始但作为从零开始的工程我建议先做传统模型。原因在于TF-IDF 和逻辑回归的训练时间只需几分钟而 BERT 微调动辄数小时。先用传统模型建立基线你才能知道后面用复杂模型到底带来多少收益。from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( df[clean_text], df[sentiment].map({positive: 1, negative: 0}), test_size0.2, random_state42, stratifydf[sentiment] ) vectorizer TfidfVectorizer(max_features10000, min_df2, ngram_range(1, 2)) X_train_tfidf vectorizer.fit_transform(X_train) X_test_tfidf vectorizer.transform(X_test)几个关键参数的考量max_features10000限制特征数量避免高维稀疏矩阵导致内存爆炸。min_df2只保留在至少 2 条评论中出现过的词过滤罕见无意义的词。ngram_range(1, 2)同时保留单个词和相邻两个词让“not good”这样的组合有机会被模型捕捉到。stratify保证训练集和测试集中的正负样本比例一致避免评估时出现偏差。这些细节都是工程经验。没有它们模型也能跑但在真实场景中就会出现“训练时表现挺好测试时崩盘”的问题。3.5 训练强基线模型逻辑回归在文本分类上往往不弱逻辑回归是文本分类里最容易被低估的模型之一。它训练速度极快、可解释性强而且在 TF-IDF 特征下通常能拿到 85% 以上的准确率。直接上复杂模型不是不可以但你失去了一个对照的锚点。from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, f1_score, classification_report model LogisticRegression(max_iter1000, C1.0) model.fit(X_train_tfidf, y_train) y_pred model.predict(X_test_tfidf) print(Accuracy:, accuracy_score(y_test, y_pred)) print(F1 Score:, f1_score(y_test, y_pred, averagebinary)) print(classification_report(y_test, y_pred))C是正则化强度的倒数默认是 1.0。如果你想微调可以试试 0.5 或 2.0。调参的推荐方式不是一个个手试而直接用GridSearchCV或Optuna做小范围搜索。我一般会在基线模型上先确认一个方向再投入时间去调更大模型。3.6 升级到深度学习模型PyTorch 实现简单的 TextCNN当基线模型已经跑通我们可以尝试第一个深度模型。TextCNN 结构简单、训练快非常适合入门。把文本转成序列然后用 Embedding 层替代 TF-IDF能让模型自动学习词语的语义表示。import torch import torch.nn as nn class TextCNN(nn.Module): def __init__(self, vocab_size, embed_dim100, num_classes2): super().__init__() self.embedding nn.Embedding(vocab_size, embed_dim) self.conv1 nn.Conv1d(embed_dim, 128, kernel_size3, padding1) self.conv2 nn.Conv1d(embed_dim, 128, kernel_size5, padding2) self.fc nn.Linear(128 * 2, num_classes) self.relu nn.ReLU() def forward(self, x): emb self.embedding(x).permute(0, 2, 1) # (batch, embed_dim, seq_len) c1 self.relu(self.conv1(emb)).max(dim-1).values c2 self.relu(self.conv2(emb)).max(dim-1).values return self.fc(torch.cat([c1, c2], dim-1))这里我故意把卷积核宽度设为 3 和 5分别观察相邻 3 个词和 5 个词构成的局部语义。max池化用于从每个卷积结果中抽取最强烈的特征这种“多尺度观察再精炼”的思路也是实践里常用的。训练时我把batch_size定为 64学习率用 0.001 的 Adam 优化器。一个需要注意的经验是对小数据集来说通常训练 5 到 10 个 epoch 就会出现收敛多跑反而会过拟合。你可以打印训练集和验证集各自的损失曲线观察它们什么时候开始分叉。3.7 部署用 FastAPI 把模型封装成可供调用的服务模型训练完成后下一步是让其他人能通过 HTTP 接口调用。FastAPI 是当前最合适的轻量方案自带 OpenAPI 文档调试起来非常方便。import joblib from fastapi import FastAPI from pydantic import BaseModel app FastAPI() vectorizer joblib.load(vectorizer.joblib) model joblib.load(model.joblib) class ReviewRequest(BaseModel): text: str app.post(/predict) def predict(req: ReviewRequest): vec vectorizer.transform([req.text]) prob model.predict_proba(vec)[0, 1] pred int(prob 0.5) return {prediction: pred, positive_prob: round(prob, 4)}启动服务uvicorn app:app --host 0.0.0.0 --port 8000然后在另一个终端里用 curl 测试curl -X POST http://localhost:8000/predict \ -H Content-Type: application/json \ -d {text: This movie is fantastic!}如果返回的positive_prob接近 1说明模型和接口都正常了。这里我还会加一个微小但实用的细节把预处理函数从训练代码里也封装成一个preprocess()函数让接口层和训练层共用同一条数据处理逻辑避免“训练时清洗过、上线时没清洗”的灾难。3.8 容器化让模型在任何机器上都能一键启动在项目初期就接触 Docker会让后期协作和部署省掉无数“在我电脑上能跑”的纠纷。写一个简单的DockerfileFROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD [uvicorn, app:app, --host, 0.0.0.0, --port, 8000]构建并运行docker build -t sentiment-api . docker run -p 8000:8000 sentiment-api这个镜像里会包含词向量矩阵和模型文件。注意不要把数据和模型权重打进镜像里太大用dockerignore排除不必要的缓存数据。这个小项目搭建完成后你就已经有了“从数据到部署”的完整手感这比刷十遍教程都管用。4. 真实项目中最容易踩的 5 个坑以及我亲手把项目跑废后的排查思路从零到一的过程中模型训练反而是最不容易出问题的一环真正让人反复返工的是各种数据和工程细节。下面这五个坑是我项目实操中的真实经历每一个都让交付延过期。4.1 隐藏的数据泄露你精心设计的测试集并不干净数据泄露的前提是“未来信息被历史数据偷看”。我在一个项目里为了提升指标做过一个操作用全体数据的均值和标准差去做标准化然后再切训练集和测试集。看似合理的做法其实已经在测试集上留下了“全局统计信息”指标虚高得毫无意义。排查方法很简单训练前先切分再在训练集上做fit测试集上只做transform。这个教训适用于所有特征工程环节。能用管道就传sklearn.pipeline它对切分顺序的保护做得比手动代码更安全。4.2 类别不平衡但你只看准确率评估指标选了就不要换在类别失衡的数据集里比如 99% 的正常请求1% 的异常准确率会把你的模型“包装”得很优秀。比如全部预测为负样本也能拿到 99% 的准确率但这毫无用处。必须一开始就明确用F1-score、Precision、Recall或AUC。我建议在项目启动时就打印完整的classification_report同时关注正样本的召回率避免重点类目被整体淹没。这也是为什么我在第 3 节的项目里同时打印 Accuracy 和 F1。习惯了同时看多个维度到了真实项目里才不会只被某一个漂亮的数字迷惑。4.3 训练环境和部署环境不一致CPU 上训练、GPU 上部署后模型卡死有一次我在开发机上用 PyTorch 加了cuda设备推导逻辑到了部署机只有 CPU直接报错。根源是我把设备判断写死在import torch后的第一条语句没有做成动态路由。经验教训是所有跟设备、路径、版本相关的逻辑做成一启动就检查的配置项。更稳的做法是device torch.device(cuda if torch.cuda.is_available() else cpu)部署前还要用torch.save(model.state_dict(), ...)保存权重而不是把整个模型对象pickle下来。前者跨版本的兼容性更好后者一旦环境差异较大就会崩溃。4.4 线上系统和训练代码分叉预处理逻辑两套实现线上数据自然变形这种问题通常能在第一次灰度时炸出来。训练代码里写了“删除 URL”线上推理时却忘了这一步于是模型中出现的 URL 特征在线上变成了一堆乱码直接影响预测结果。我现在的准则是“训练和推理共用一套代码路径”。把清洗函数放进一个公共模块例如text_utils.py训练代码和 API 都从那里引用绝不各写一份副本。把项目做“脏”很容易整理起来却相当费时。4.5 只关注模型指标忽略推理延迟和资源消耗一个离线 AUC 达到 0.95 的模型如果单次推理需要 2 秒现实中用户是无法接受的。部署前最好先压测一下。可以用locust或简单写一段并发脚本观察 P95 延迟。我自己的经验先在低配机器上用 CPU 推理跑通看吞吐量是否满足预期。如果延迟过高可能要做模型蒸馏、量化或者切换到更轻量的结构。从工程角度讲“刚刚好能上线”比“指标最好看”更重要。5. 52 周执行计划与高效自学的几条实用建议很多人的问题不是学不会而是缺乏一条能把碎片时间串起来的计划。我建议把学习拉成 52 周不用太拼关键是每天都有一点产出。阶段时间跨度核心目标产出物热身上路第 1~8 周掌握 Python 数据处理与基础数学概念完成 5 个小脚本一个可视化分析核心理论第 9~20 周理解监督学习全流程能做简单建模用 sklearn 完成分类与回归各一个深度学习第 21~32 周会用 PyTorch 搭建并训练网络用 TextCNN 完成文本分类项目工程化第 33~44 周掌握 Docker、FastAPI、Git 协作部署一个带 API 的模型服务完整实战第 45~52 周独立完成一个端到端项目展示在 GitHub 上并附带 README这套计划最大的特点是每个阶段都有明确的产出物而不是学了“感觉掌握了”。推荐每周留出半天时间做复盘把所有产出下来的代码、文档和实验记录整理成一个清晰目录。自学过程里的另一个容易被忽视的问题是“资源囤积”。很多人收藏了几百个教程真正打开的次数却很少。我现在的策略是“同一个主题只保留一份最配套的资料”比如算法原理就带着《统计学习方法》和《动手学深度学习》其他的都是查询时临时用。看得完、做得完永远比收集得全更重要。另外每隔两周做一次“纸上架构”练习拿出一张白纸画出正在学习的系统里数据是怎么流动的从数据源到最终输出。这样你会发现很多你以为学会的环节其实只是停留在脑子里一段模糊的台词。写在最后的建议如果你尝试了这个过程但中途遇到了挫折不要怀疑自己基础差。几乎所有做 AI 工程的人都经历过“代码报了三天错最后发现是版本不匹配”的崩溃时刻。我的经验是先从“让一个最小系统跑起来”开始再逐步往里面加复杂度。先跑通再优化最后才是理解深处的原理。一个特别想分享的小技巧是从第一天起就建立一个experiments文件夹每个实验用日期加简短描述命名里面保留代码、参数配置和结果截图。这个小习惯会在你回顾项目时救你无数次你会清清楚楚看到自己从零到一走过的每一步。这比任何课程结业证书都更有说服力。