☰
AI工程从零开始:从数据到部署的完整路线图
2026/11/3 15:16:23 网站建设 项目流程

ai-engineering-from-scratch 这个标题,最近在开发者圈子里撞见频率不低。先泼一盆冷水:如果你是被热搜里的 scratch 编程小游戏、scratch 植物大战僵尸、scratch 中秋节作品吸引进来的,那你多半走错门了——这里的 from scratch 不是那个积木式少儿编程工具,而是英文里“从零开始”的意思。我要聊的,是把一条完整的 AI 工程链路从零搭起来:数据怎么来、模型怎么选、训练怎么调、评估怎么定、上线之后怎么维护。这门手艺适合两类人:一是已经会写 Python、想系统建立 AI 工程能力的开发者;二是刚入行、被各种“三天学会大模型”洗脑、需要有人拉一把别走偏的新手。如果你只是好奇 AI 和搭乐高似的拖拽编程有啥关系,可以关掉了;如果你真想从零到一做出一个能用的 AI 应用,这篇可以当作你的第一份路线图。

1. 重新理解“from scratch”:AI工程与零基础入门的真相

1.1 一个热词背后的双重世界:此 scratch 非彼 Scratch

先说个挺有意思的观察。搜索引擎里搜“scratch”这个单词,前排结果几乎被少儿编程生态承包了:scratch desktop for windows、scratch jr desktop、scratch编程枪战小游戏、scratch植物大战僵尸代码、scratch中秋节画月饼……这些都是图形化编程社区里的东西。而在技术圈,“build a large language model from scratch”“build a reasoning model from scratch”是另一条完全不同的检索路径,有人甚至到处找《Build a Large Language Model from Scratch》这本书的资源。两拨人搜同一个词,需求天差地别。

造成这种混乱的原因很简单:scratch 既是麻省理工那个积木式编程工具的名字,也是一个英文短语,意思是“从零开始、白手起家”。AI 工程里说的 from scratch,指的是后者。所以当你看到 ai-engineering-from-scratch 这个标题时,正确的读法是“从零开始做 AI 工程”,而不是“用 Scratch 做 AI 工程”。这不是抠字眼,因为这两条路的学习路径、工具链、思维模型完全不同:少儿编程那边重点是逻辑启蒙和项目创意,AI 工程这边重点是数据、模型、训练、部署的工程闭环。如果你带着“AI 工程”的预期误入了少儿编程的内容,你会觉得太简单;反过来也一样。

1.2 “从零开始”的真实含义:工程不是学术复现

再拆一层:很多人一听到 from scratch,第一反应是“那我得自己实现反向传播、自己写 Transformer、自己从空白文档开始构建一切”。这种理解其实是把“从零开始”和“从零发明”搞混了。AI 工程里的从零开始,意思是:从只有一个业务问题、一块数据、一个空项目目录开始,通过你的设计和组合,最终交付一个能实际运行的系统。至于底层那些梯度下降、注意力机制,它们是工具,不是你必须徒手重造的零件。

打个比方:你要从零开始做一张桌子。一个方法是先去森林里砍树、晒木头、自己刨板子;另一个方法是买来现成的板材和五金件,自己设计尺寸、切割、组装。前一种当然能让你更懂木头,但你大概率一年都做不出一张能坐的桌子。工程实践里,多数人应该走第二条路:用现成的框架和预训练模型当“板材”,把精力花在理解业务、处理数据、设计评估、调试系统上。等你真的吃透了工程流程,再回头去啃“自己实现一个 Transformer”这类东西,效率会高得多。这就是为什么我一直跟新入行的朋友说:别一上来就钻进源码深水区,先把手上的项目跑起来。

1.3 把 AI 工程拆成一条可执行的路线图

真正高效的 from scratch,是心里先有一张全局地图,再按顺序推进。我做了这些年 AI 项目,总结下来一条稳妥的六阶段路线:

  1. 业务问题定义:先把“想解决什么问题”翻译成“可以量化的指标”。比如用户差评预警,指标就是“识别出所有差评的准确率和召回率”。
  2. 数据工程:采集、清洗、标注、划分。这一步通常占整个项目 60% 以上的时间。
  3. 基线建模:先用最简单的模型跑通全流程,拿到一个不算太差的下限。
  4. 调优与评估:在基线基础上逐步加入更复杂的模型和特征,用统一指标衡量每一步的收益。
  5. 部署上线:把模型封装成接口,嵌入真实业务流。
  6. 监控迭代:跟踪线上表现,收集新数据,定期重训。

为什么是这个顺序?因为它把所有决策建立在“可度量的信号”上。很多人一上来就选模型、调参,结果数据质量一塌糊涂,模型再先进也是垃圾进垃圾出。先定义指标、先做好数据、先跑通基线,看起来慢,实际上是最快能拿到可靠结果的路径。下面我就按这条路线,挑几个最关键的环节展开讲。

2. 从第一个能跑的项目起步:最小可行AI工程基座

2.1 为什么强烈建议从文本分类而不是大模型开始

现在所有人的注意力都被大模型吸走了,一开口就是“我要微调一个 LLaMA”、“我要用大模型做 Agent”。我理解这种冲动,但作为一个想建立 AI 工程能力的新手,我强烈建议你从文本分类这类小而明确的任务开始。原因有三条。

第一,数据可控。文本分类的数据集到处都是,你自己业务里的评论、工单、反馈都能用。数据量几百到几千条就能启动,不需要花几个月攒百万级语料。第二,评估清晰。分类任务有标准答案,预测对错一目了然,你可以用一个 F1 分数明确判断模型好不好。反观聊天机器人和 Agent,评估模糊得像玄学,你很难知道改了一版是变好了还是变差了。第三,迭代快。小模型在 CPU 上几分钟训完,预训练模型在免费 GPU 上半小时内也能看到结果。大模型的微调和推理,一次实验可能要烧掉几小时甚至几天,错一步成本极高。

打个比方:你想开餐厅,先别急着租三层楼、雇二十个厨师、设计复杂菜单。先在自家厨房把一道红烧肉做到稳定好吃,再谈扩张。文本分类就是你 AI 工程生涯里那道红烧肉——流程完整、反馈直接、进步看得见。

2.2 数据准备阶段最容易翻车的三个细节

很多新手拿到数据就急着喂给模型,结果后面连环踩雷。数据准备阶段有三个细节,几乎决定项目成败。

第一个:标注标准必须先固定。我见过不少项目,标注员对“这个评论算正面还是负面”的理解都不一致。比如“物流一般但质量很好”,有人标正面,有人标中性,有人标负面。不统一的标签会让模型无所适从。正确做法是开工前写一页标注规范,把边界情况列清楚。哪怕只有你一个人标注,也要这么做,因为你会发现自己上午和下午的判断都可能漂移。

第二个:划分数据集时一定要用分层抽样。拿 sklearn 的 train_test_split 举例,一定要传 stratify 参数,让训练集、验证集、测试集的类别比例保持一致。否则划分出来的测试集可能全是一个类别,你的模型得分会虚高或虚低,根本没法作为决策依据。

第三个:防止数据泄漏。这是最隐蔽的坑。比如你做电商评论情感分类,原始数据里带“评分”字段,模型只要学会“评分是5星就预测正面”,就能拿到满分——但这属于作弊,因为你在实际预测场景里可能拿不到评分,或者评分本身才是你真正想预测的目标。同理,文本里混入日期、订单号、价格等字段,都可能成为模型的“小抄”。记得在清洗时把这些信息剥离干净。

2.3 baseline 思维:先跑通笨办法,再谈聪明模型

数据准备好之后,第一件事不是上深度学习,而是跑一个“笨办法”当基线。我常用的组合是 TF-IDF 特征加上逻辑回归。TF-IDF 把文本变成词频向量,逻辑回归在此基础上做线性分类。它模型简单、训练飞快、可解释性强。

import pandas as pd from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report # 假设 df 已加载,包含 text 和 label 两列 df = pd.read_csv("reviews.csv") # 划分训练/验证/测试集,注意 stratify 保证类别比例一致 train_text, temp_text, train_label, temp_label = train_test_split( df["text"], df["label"], test_size=0.3, stratify=df["label"], random_state=42 ) val_text, test_text, val_label, test_label = train_test_split( temp_text, temp_label, test_size=0.5, stratify=temp_label, random_state=42 ) # TF-IDF 特征 vectorizer = TfidfVectorizer( max_features=20000, ngram_range=(1, 2), stop_words="english" ) X_train = vectorizer.fit_transform(train_text) X_val = vectorizer.transform(val_text) X_test = vectorizer.transform(test_text) # 逻辑回归基线 model = LogisticRegression(max_iter=1000, C=1.0) model.fit(X_train, train_label) # 评估 pred_val = model.predict(X_val) print(classification_report(val_label, pred_val, target_names=["负面", "正面"]))

跑这个基线有几个目的:一是验证你的数据管道没问题,从加载到评估整个链路通顺;二是拿到一个“下限”分数,后续任何模型的改进都必须超过它,否则就是在浪费时间;三是给你一个对照物,让你看清复杂模型到底带来了多少真实提升。我第一次带项目的时候,团队里有人主张直接上 BERT,我先用逻辑回归跑了个 0.87 的 F1,后来 BERT 微调完是 0.92——虽然涨了,但你也得知道这 0.05 是用多少训练时间换来的,值不值,由业务场景说了算。

3. 核心细节拆解:训练、评估与迭代的工程闭环

3.1 训练环节最容易踩的三个坑

训练环节看似人人都会,但工程经验往往体现在细节上。有三次踩坑经历,每次都是血泪教训。

第一次踩坑是不划分验证集就反复调参。早期我做项目图省事,直接在测试集上调参数,调一版测一版,很快测试集上的分数“涨”上去了,心里还挺美。后来才发现,这等于考试前先看了答案,测试集的评估价值被彻底污染了。正确的做法是:留出训练集、验证集、测试集三份数据,用验证集做模型选择和调参,全部确定之后,才允许碰一次测试集。测试集是期末考试卷,只能考一次。

第二次踩坑是类别不平衡直接训。有次做工单分类,90% 的工单是“咨询”,剩下 10% 是“故障报修”。模型学了个偷懒策略:把什么都预测成“咨询”,准确率直接 90%。你说它错了吗?从准确率看没错,但业务上一张故障单被误判成咨询,用户要被多晾好几天。解决思路有两个:一是用 class_weight 参数给少数类加权,二是在评估指标上换成 F1 而不是准确率,让模型没有偷懒的余地。

第三次踩坑是随机种子不固定。同样的代码,跑两次结果不一样。一开始我还以为环境坏了,后来才意识到是没设随机种子。AI 里面到处是随机初始化、随机抽样、随机 dropout,不固定住,你根本无法定位“这次效果变好到底是因为改动,还是因为运气”。所以我在所有项目的开头都会加这一行:

import random import numpy as np import torch def set_seed(seed: int = 42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed)

别嫌这一步麻烦,等你要写实验报告、要复现之前的结果时,你会感谢当初固定了种子。

3.2 评估指标别只看“正确率”

“准确率”是新手最爱挂在嘴边的指标,但在 AI 工程里它往往是最容易骗人的一个。原因在于类别不平衡:当 95% 的样本都是负类时,模型什么都不学,把全部预测成负类,准确率就有 95%。所以评估指标的选择,必须跟业务目标和数据分布对齐。

场景推荐指标原因
类别大致平衡、关注整体正确Accuracy直观、易交流
类别不平衡、关注少数类F1 / F1-macro兼顾精确率和召回率,少数类表现会拖分
风险识别、诈骗检测Recall / 召回率漏掉一个骗子比误伤一个好人代价高得多
排序 / 打分场景AUC衡量模型区分正负类的排序能力,与阈值无关
多分类且各类重要程度不同加权 F1 / 各类别 F1 加权平均避免大类掩盖小类问题

我个人的习惯是:每版模型都输出 classification_report,把精确率、召回率、F1 按类别列出来,而不是只盯一个总分。这样你能快速定位“模型到底哪一类不行”。比如做差评识别时,F1 总体 0.93 很好看,但点开细看,负类召回率只有 0.61——也就是说近四成的差评漏掉了,业务上这就是事故。指标只有拆到类别粒度,才有指导意义。

3.3 实验追踪:用一张表管住你的所有尝试

做 AI 项目,最大的隐形浪费是记不住自己试过什么。大部分人的真实状态是:上周跑了个实验,效果不错,但这周想回去复现,发现代码里的参数已经被改成别的了。为了避免这种“失忆”,我从第二个项目开始强制自己做实验记录。早期没上什么高大上的工具,就是一张 Markdown 表格:

实验编号数据版本模型关键参数验证 F1测试 F1备注
v1>from transformers import ( AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments, ) from datasets import Dataset import pandas as pd # 组装训练数据 train_df = pd.DataFrame({"text": train_text, "label": train_label}) val_df = pd.DataFrame({"text": val_text, "label": val_label}) train_ds = Dataset.from_pandas(train_df) val_ds = Dataset.from_pandas(val_df) model_name = "distilbert-base-uncased" tokenizer = AutoTokenizer.from_pretrained(model_name) def tokenize(batch): return tokenizer(batch["text"], truncation=True, padding=True, max_length=128) train_ds = train_ds.map(tokenize, batched=True) val_ds = val_ds.map(tokenize, batched=True) model = AutoModelForSequenceClassification.from_pretrained( model_name, num_labels=2 ) training_args = TrainingArguments( output_dir="./checkpoints", evaluation_strategy="epoch", save_strategy="epoch", learning_rate=2e-5, per_device_train_batch_size=16, per_device_eval_batch_size=32, num_train_epochs=3, weight_decay=0.01, logging_dir="./logs", ) trainer = Trainer( model=model, args=training_args, train_dataset=train_ds, eval_dataset=val_ds, tokenizer=tokenizer, ) trainer.train()

这里有两个工程要点要特别说。第一,max_length 设成 128 是因为电商评论普遍很短,设太长只是浪费计算资源。如果做长文档分类,再按实际长度分布调整。第二,学习率用 2e-5 是预训练模型微调的常见起点。预训练模型已经被训练得足够好了,学习率太大会把学到的知识“冲掉”,太小又学不动下游任务。

4.3 结果对比与错误分析

微调 DistilBERT 后,验证集负类召回率升到 0.92,F1 0.93,测试集负类召回率 0.91,F1 0.92。相比基线,负类召回率涨了 14 个点,业务要求达标。这个提升也符合预期:预训练模型能理解词序、语法和上下文,不会像词袋模型那样被“质量不好但物流挺快”这种表达骗了。

但项目不能止步于“指标达标”。我坚持带实习生做了一步很多人会偷懒的事:错误分析。从测试集里被预测错的样本中随机抽了 50 条,一条条读过去,归纳出三个失败模式:一是反讽和俏皮话,比如“真是谢谢你啊帮我发了三天才发出”,模型识别成正面,人类一看就知道是气话;二是短文本信息不足,比如单一个“服”字,没有上下文谁都不知道是服气还是服了;三是专业术语和商品名干扰,模型把一些描述性词汇当成了情感信号。

这一步的价值在于:你知道这个模型的上限在哪、将来主要的优化方向是什么。如果要继续提指标,方向一是用更长的上下文和更大的模型,方向二是加入额外的用户行为特征,方向三是专门收集反讽样本做数据增强。没有错误分析,你只知道分数,不知道下一步该干嘛。

4.4 最终模型验收和交付物清单

项目收尾时,我让实习生整理了一份交付清单,包括:训练代码和依赖文件 requirements.txt;数据清洗脚本;标注规范文档;实验记录表(包含 v1 基线、v2 微调、v3 调参全程);最终模型权重文件和指标报告;一段简单的推理脚本,封装成函数,输入一句话输出标签和置信度。这份清单后来直接交给负责部署的同事,对方没有任何沟通成本就接住了。这也是我想强调的:AI 工程的交付物不只是模型,而是整套可复现、可交接、可追溯的工程资产。

5. 常见问题与排查技巧实录

5.1 新手高频问题速查表

平时带人的过程中,以下问题出现频率极高。整理成一张速查表,碰到对应症状直接查:

症状常见原因解决思路
loss 不降或为 NaN学习率过高、数据包含异常值调低学习率,检查数据归一化和缺失值
训练集指标高,验证集暴跌过拟合加正则(weight_decay/dropout)、早停、扩大数据量
所有预测都是同一个类别类别极度不平衡、模型学到捷径用 class_weight、换评估指标、做数据增强
微调预训练模型时 OOM 报错batch size 太大或 max_length 太长减小 batch size、降低 max_length、用梯度累积
跑同一个脚本两次结果不同没固定随机种子 / GPU 非确定性固定 seed,必要时设置 torch.use_deterministic_algorithms
验证集分数很高,上线后不准数据分布漂移、训练数据泄漏检查泄漏,监控线上输入分布,定期用新数据重训

前三个问题尤其多发。我见过的解决办法无非是“降学习率”“加正则”“重采样”,但很多人卡在不知道怎么判断是哪种问题。我的经验是:先看训练集和验证集之间的差距。如果训练集很高、验证集很低,是过拟合;如果两个都低,是模型容量不够或特征不行;如果两个都还行(比如都 0.7),那可能是指标定义和数据划分本身有问题。

5.2 我踩过坑后沉淀的几条独家经验

先说一条差点让我赔上项目进度的教训:验证集污染。有一版实验里,我为了省事,对全部数据做了标准化之后再划分训练验证集。结果因为统计量是从整个数据集算出来的,验证集的信息提前“泄漏”到了训练阶段,验证指标虚高了 5 个点。上线前我用测试集一测,才发现真实成绩没那么好。从那以后,所有需要拟合数据分布的预处理步骤,比如标准化、TF-IDF 词表构建,我都严格执行“先 fit 训练集,再 transform 验证集和测试集”的规则。代码上就是 vectorizer.fit_transform(X_train),然后再用同一个 vectorizer.transform(X_val) 和 transform(X_test)。顺序错了,你的指标就是假的。

第二条经验是关于指标和业务目标错配的。有次做客户流失预警,模型团队一直在刷 AUC,做到了 0.95,觉得稳了。结果业务方根本不看这个,他们关心的是“这周要打电话给哪 500 个客户”。你 AUC 再高,如果不能转化成一份可执行名单,或者转化出的名单里真正流失的没几个,业务方照样不满意。后来我把评估改成“Top 500 名单的命中率”,再按这个目标调阈值、调模型,业务反馈才变好。这个教训让我养成了个习惯:动手前先问业务方一句,“模型做对了,你们会用什么动作来响应?”答案直接决定评估指标的形态。

第三条关于“盲目上大模型”。微调一个 7B 参数模型需要多少显存、多少训练时间、多少数据?很多人一头扎进去才发现,自己的数据量连一个小模型的参数都喂不饱。我的经验是:先把数据质量做上去,再用小模型跑通流程,最后才根据差距决定要不要扩大模型规模。大多数业务场景,DistilBERT 这个体量的模型已经能解决 80% 的问题,剩下的 20% 往往不是模型大小问题,而是数据覆盖度问题。

6. 从入门项目到生产级AI工程:下一步怎么走

6.1 完成分类项目后,补齐工程化三件套

当你跑通了第一个分类项目,恭喜你,你拥有了 AI 模型的“实验室能力”。但离真正生产环境,还差三块拼图。

第一块是服务化。模型不是 Jupyter Notebook 里躺着的文件,它要变成别人能调用的接口。最简单的做法是用 FastAPI 包一层 HTTP 服务,把推理脚本封装成 POST 接口,再用 Docker 打成镜像部署。这块的难点不在于写接口,而在于要处理并发、超时、错误返回、模型加载预热这些工程细节。比如模型加载很慢,你应该在服务启动时加载一次,而不是每个请求都重新加载。

第二块是监控。上线不是终点。你还要盯着线上数据分布是否发生漂移、单个样本的预测置信度是否异常、特征缺失率是否上升。我见过一个评论分类模型上线后越来越不准,排查半天发现是业务改了页面,新评论里冒出来一堆火星文,训练数据里根本没有这个分布。没有监控,这种漂移你根本发现不了。

第三块是成本意识。模型大不一定好,模型快、便宜、够用才是王道。我在很多项目里做过“模型压缩换成本”的决策:用蒸馏后的轻量模型,把推理速度提升一倍,精度只损失一个点,这对高并发业务来说是巨大的性价比提升。做一个合格的 AI 工程师,要习惯给每个模型算账:训练成本多少、推理成本多少、精度提升带来的业务收益能不能覆盖这部分成本。

6.2 什么时候值得去啃 “Build a Large Language Model from Scratch” 这类教程

回到热搜里的另一条线索:“build a large language model from scratch”,现在这种教程和书特别多。我的态度很明确:值得学,但要挑时机。如果你连一个完整的分类项目都没做完、连 train/validation 划分的意义都没体会过,直接去啃“从零实现 GPT”多半是自我感动。因为你没有工程直觉做支撑,那些反向传播公式和注意力矩阵在你眼里就是一堆看不懂的符号,看完即忘。

比较合理的节奏是:先完成第 4 章这种端到端项目,建立工程手感;遇到下面这些“为什么”时,再回头啃原理:为什么学习率太大会训不动?为什么 Transformer 比 LSTM 更适合并行?为什么推理时 KV Cache 能加速?带着具体问题去读源码和论文,吸收效率是漫无目的阅读的十倍。

我个人非常推荐的做法是:抽一个周末,跟着教程用 PyTorch 从零写一个极简版语言模型,规模控制在几百万参数那种,能拼出像样的句子就够。这个练习不是为了复用,而是为了让你理解每行代码背后的形状变换、损失计算和梯度流动。做完之后,你对 HuggingFace 库里那些封装好的 API 的理解会完全不同——你会知道 Trainer 帮你省了多少事,模型内部的哪些环节决定了推理速度。但请记住:这是学习手段,不是生产实践。业务项目里该用现成框架就用现成框架,别为了“秀肌肉”手写模型。

这几步走下来,你会发现从零开始做 AI 工程真的没有那么玄。它不是你想象中遥不可及的算法研究,而是一个又一个朴素的工程决策:数据清洗得干不干净、指标定得合不合理、实验记不记得清楚、部署监控到不到位。我做 AI 工程这些年,最大的体会是:这个领域不缺懂模型的人,缺的是能把一个项目稳稳当当从 0 推到生产环境的人。希望这篇分享能帮你省掉一些我当年撞过的墙,早点把这条路走通。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询