
很多朋友问过我同一个问题想系统学习AI工程是不是得先啃完几本经典教材、把Transformer的每一行公式手推一遍然后才敢碰代码我过去也觉得应该这样直到自己真正走完一遍才发现答案恰恰相反。所谓AI engineering from scratch这个from scratch并不等于从数学原理白手起家而是从一条能端到端跑通的最小闭环开始在一次次真实的失败里把知识补回来。这篇内容把我自己从零搭建模型、训练、评估、部署的经验完整梳理了一遍适合刚接触AI工程的学习者也适合那些已经能在notebook里跑通模型、但面对完整项目仍然不知道从哪下手的人。你会看到一条AI工程链路到底由哪些环节构成每个环节里最容易被低估的风险点是什么以及怎样用最低的成本完成一次有质量的从零到一。1. 从零开始之前先给AI工程画一条边界线1.1 算法研究与AI工程是两种不同的能力很多入门者最大的痛苦其实是分不清自己到底要学什么。算法研究员的重心放在模型结构、损失函数、训练技巧上目标是让某个指标在基准数据集上提升零点几个百分点。而AI工程师的重心完全不同数据流水线怎么搭、训练怎么复现、评估怎么做才公平、推理耗时怎么压、线上模型怎么监控。两者有交集但分工差异非常明显。如果你把AI engineering from scratch理解为纯论文复现或手写Transformer那你走的是研究路线学习资料和项目形态都会很学术。但如果你想做的是工程落地那需要的几乎是另一套知识栈Python工程化、数据处理、训练系统、模型压缩、服务部署和运维监控。我的建议是动身之前先明确路线不然很容易被眼花缭乱的学习资料带着跑。1.2 最小闭环的五个环节我给从零开始定义了一个最小闭环一共五件事拿到一份数据、清洗并按规则切分、训练一个小模型、用指标评估、部署成一个简单API。这五件事全部跑通才算真正迈进AI工程的门。很多人入门的路径是一上来就微调大语言模型、或者想从零预训练一个属于自己的LLM觉得这才是from scratch。但说实话那只是从零工程的一半甚至一半都不到。没有数据工程和部署验证模型永远只活在Jupyter里和真正的产品之间还隔着一整条生产线。所以我后面所有章节都围绕这五件事展开。2. 环境搭建与项目骨架把时间花在能复用的地方2.1 硬件、CUDA和版本够用就行AI工程的环境搭建没有想象中复杂但踩坑率不低。我的通用起点是NVIDIA显卡 CUDA PyTorch Python虚拟环境。具体选型上我现在的建议是不要追求最新版本。举个例子我长期使用的一组组合是Python 3.10、PyTorch 2.1、CUDA 12.1这个组合跨了几年依然稳定。新版本往往带来更激进的API变动一些第三方扩展库还没来得及适配你一升级反而会引入莫名其妙的报错。硬件方面如果预算有限云端GPU按小时租用比买一张卡更理性尤其是练习阶段。我见过太多人花大几千块买了显卡最终利用率不到一成。一个更务实的方案是内存足够的CPU机器用来做数据清洗和预处理配合按需租用的GPU做训练两三个月的练习期下来费用可能比一张显卡的零头还少。2.2 从一开始就按工程结构组织代码我见过太多训练脚本长成一个单文件数据加载、模型定义、训练循环、参数配置全部堆在一起。跑通一次之后作者自己第二天就不想再看第二眼。工程化的第一步不是写多优雅的框架而是把代码切成边界清晰的模块。我常用的一套项目结构是project/ configs/ # yaml配置文件 data/ # 数据下载、清洗、切分脚本 models/ # 模型定义 train.py # 训练入口 evaluate.py # 评估入口 deploy/ # 推理服务相关 tests/ # 基础测试 logs/ # 训练日志与实验记录别小看这个结构它最大的价值是让你每一步操作都能单独验证。数据脚本跑完可以检查输出模型模块可以单独实例化训练入口只负责把各部分串起来。配置文件用YAML而不是直接在代码里写死是我建议从第一天就养成的习惯。训练任务的可复现性太重要了而一份配置文件就是你每轮实验的病历本。2.3 复现三件套版本、日志、随机种子从第一次正式训练开始我就强制自己记录三样东西代码版本、数据版本、超参数。代码用Git管理数据在进入训练前先计算一次hash并记到实验日志里超参数统一放进config文件。随机种子需要固定这一点新手经常忽略。不固定种子你会被训练结果的随机波动搞到怀疑人生。我常用的配置是import random import numpy as np import torch def set_seed(seed42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed)还有一个被忽略的习惯日志。我希望自己在第一天就坚持用日志库而不是print。print在一次性脚本里够用但训练跑上几十个小时之后日志文件里按时间戳排列的持续输出才是真正能帮你定位问题的工具。print会被终端缓冲截断会淹没在滚动信息的海洋里而日志系统可以按级别过滤、落盘、追溯。3. 数据工程AI项目里被低估的主力3.1 脏数据如何进入训练集有一个反常识的事实在大部分AI工程任务中数据处理的耗时占项目总工时的60%到70%。我做过一个文本分类项目模型结构从论文里复现出来只花了半周清洗数据却用掉三周。很多人觉得这是效率低但真正进入生产环境后你会发现脏数据总会以意想不到的方式出现在评估结果里。我清洗数据时固定会做几件事。第一是去重不仅要去完全重复的样本还要做模糊去重因为相似度极高的样本会把训练集分布拉偏。第二是去空和格式统一这听起来基础但当你面对多来源抓取的数据时格式混乱几乎是必然的。第三是标签与内容的一致性校验这是最容易被忽视的。当数据集来自多个渠道时同一语义的样本可能被标成不同标签不校正的话模型学到的就是标签噪声。3.2 分组切分与数据泄漏训练集、验证集、测试集的切分方式直接影响你对模型能力的真实判断。很多人切数据时随手shuffle一下再按比例切这在某些场景没问题但一旦你的数据带时间属性或存在同源聚集乱切就会带来数据泄漏。举个例子在跨时间的预测任务里你如果先把所有样本打乱再切分验证集里就会混进未来的数据。模型在验证集上表现很好因为它在训练时已经见过相近时间片的信息到了真实世界面对的时间点都在训练数据之后性能立刻跳水。这就是典型的泄漏导致的乐观偏差。我的做法是先按一个合理的分组维度切分比如时间、账号、会话然后再从每个组内部采样组成训练、验证、测试集。这样能保证验证集和测试集扮演真正没见过世面的角色评估结论才可信任。3.3 tokenizer是模型的第一道加工线在文本模型的世界里分词器决定数据进入模型时的形状。不同分词器的词汇覆盖和压缩率差异很大尤其对中文和代码文本选择不当会让有效序列长度变得扭曲进而影响训练效果。我直接用Hugging Face的tokenizer接口标准的处理方式是from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(bert-base-uncased) encoded tokenizer( text, paddingmax_length, truncationTrue, max_length512, return_tensorspt )这里有新手容易忽略的两点。第一padding方向默认在右训练时影响不大但推理时某些GPU算子对左边padding的矩阵布局更友好线上延迟会有可感知的差异。第二分词器词表必须和模型严格匹配。你换了一个预训练模型却忘记换tokenizer模型会疯狂报错甚至更糟——不报错但输出乱码。数据准备完毕前我还会看三个维度的统计词汇覆盖率、标签类别分布、序列长度分布。它们能直接告诉你模型训练过程中会遇到数据层面的哪些困难。4. 训练最小闭环从单机小模型到多卡4.1 刻意从小模型开始我的核心建议是不要一上来就训练大模型。先构建一个小规模的Transformer在几十万条样本上跑通训练、验证、保存的全流程再考虑扩大规模。小模型迭代成本低你可以快速验证数据管线、代码逻辑、评估流程有没有问题。我见过有人一上来就申请八卡A100跑一个十亿参数模型结果代码里的数据标签错位在几十万条数据跑完之后才暴露出来既浪费算力又消耗信心。反过来小模型能让全流程在半小时内循环一次这种快速反馈对学习阶段的人来说是极其宝贵的。4.2 训练参数与损失曲线解读以文本生成任务为例一套足够起步的训练参数大概是training_args { per_device_train_batch_size: 8, gradient_accumulation_steps: 4, learning_rate: 5e-5, num_train_epochs: 3, warmup_ratio: 0.1, fp16: True, logging_steps: 50, save_steps: 500, }fp16混合精度基本可以无脑开显存占用和训练速度都会得到明显改善精度损失在多数任务里可以忽略。梯度累积是为了应对显存不足的招它把几个小batch的梯度攒起来再更新一次效果等价于增大了batch size。但要注意等效batch变大之后学习率一般也要跟着微调否则收敛速度可能变慢。训练过程中损失曲线是最诚实的仪表盘。如果训练loss迟迟不降先检查学习率是否合适尝试2e-4或者做一次学习率扫描如果训练loss在降但验证loss反弹说明模型开始过拟合这时可以增加数据量、调大dropout或提前停止如果loss一开始就离谱地大大概率是数据标签错位或者tokenizer配置有问题不要继续等先停下来修。4.3 多卡训练DDP的正确用法当单卡显存真的不够时再上分布式。PyTorch的DDPDistributedDataParallel是实现数据并行最简单可靠的方式核心用法是import torch.distributed as dist from torch.nn.parallel import DistributedDataParallel as DDP dist.init_process_group(nccl) model DDP(model, device_ids[local_rank])我调试分布式训练时有个原则先在单卡上跑通一个极小数据集确认模型逻辑和训练循环没有问题再改成DDP。这样能把并行环境的变量和代码逻辑的变量分离开省掉很多排查时间。另外如果你的单卡batch size已经小到1、还想继续增大batch优先考虑梯度累积而不是直接上更复杂的并行策略。张量并行、流水线并行这些技术虽然强大但配置复杂度和调试难度是另一个量级新手阶段除非必要不建议先啃它们。5. 评估与迭代让模型可衡量、可进步5.1 评估集与指标设计指标不能只看accuracy或者loss这是我从几个项目里得来的教训。尤其是在文本生成任务里验证集困惑度相差10%换成真实用户的体验可能只是都还行和有一点怪的差别。反过来有些模型困惑度非常好看停下来一问却答非所问。所以我在每个项目里都会维护一个专门的人工评估集规模不需要大500到1000条就够难度要贴近真实使用场景每轮实验后我会随机抽几十条样本自己看一遍感受模型输出有没有变好。这种人工观感和数值指标互为印证才能形成完整的评估体系。评估集的分布一旦确定就不要轻易改动。这是第二个重要原则。你每改一次评估集之前所有实验之间的对比都失去了公平性你会被我明明改进了指标怎么反而降了这类问题反复折磨。5.2 LoRA微调从零训练之外的实用路线从零完整预训练一个大语言模型的成本绝大多数团队和个人都承受不起。工程实践中更主流的方式是拿一个开源的基座模型配合LoRA做参数高效微调。LoRA把更新参数量降到极低比例显存和时间开销都大幅下降。LoRA的核心配置是秩r和缩放系数alphafrom peft import LoraConfig lora_config LoraConfig( r8, lora_alpha16, target_modules[q_proj, v_proj], lora_dropout0.05, )r值我在项目里试过4到32总结出的经验是r太小模型学不进去最终指标偏低r太大会失去参数高效的优势还更容易过拟合。8到16是一个比较稳妥的区间。alpha通常取r的两倍这个比例在多数任务里表现稳定。5.3 一次只改一个变量复盘自己失败的实验记录时我发现绝大多数模型越调越差并不是因为方向错了而是一轮里同时改了好几个变量最后根本不知道改动该归功于哪一步。正确的迭代方式是单次实验只改动一个变量这轮只动学习率下轮只换数据量再下轮只调LoRA的秩。我在项目里用一个实验对比表记录每一轮的信息实验编号数据规模训练轮数学习率评估指标备注00150万35e-50.86基线00250万32e-40.87调学习率003100万35e-50.88增数据积累五组以上实验记录后趋势会自己浮现出来。这种有据可循的迭代比凭感觉调参要可靠得多。6. 部署与反馈闭环模型的价值在上线后6.1 导出、推理服务与量化模型训练完只是第一步把它变成能被服务框架加载的格式才是工程的一半。我通常先保存成safetensors格式由Hugging Face生态直接管理权重。如果推理服务要跑在ONNX Runtime或TensorRT上就需要提前做模型转换。转换过程经常出现算子不兼容的问题我的经验是转换前先跑一遍官方样例确认环境没有问题再转自己的模型否则你会分不清错误来自转换工具还是网络结构。一个最简单的推理API用FastAPI实现流程无非是加载模型、接收请求、分词、推理、解码、返回。但有一个细节很多人会栽跟头模型要常驻显存不能在每次请求时动态加载。服务启动后我会用一个虚拟请求先跑一次预热让CUDA上下文初始化完毕否则第一个真实用户会被冷启动拖慢几秒钟甚至几十秒。量化是让模型跑得更快的重要手段。把FP16权重转成INT8显存占用接近减半推理速度提升明显对大多数任务来说质量损失在可接受范围。我实践下来觉得torch.compile搭配INT8量化是既有稳定性又有收益的组合。需要记住的是量化收益最明显的场景不是演示用的强机而是资源紧张的线上部署这时候它是优先级极高的优化选项。6.2 监控、数据回流与静默退化部署之后监控不能省。我至少会记录三类指标请求延迟、错误率、输入分布的变化。第三类最隐蔽也最重要。生产环境的输入分布和训练分布一旦偏离太远模型表现会悄悄下滑。这种静默退化不会立刻让接口报错用户也不会每次都吐槽但业务效果会一点一点变差。应对办法是建立数据回流机制定期收集线上的真实样本进入下一轮标注和重训。模型更新的循环一旦转起来整个AI工程才真正成为一个活系统。7. 回望从零到一几条带有痛感的经验写到最后我翻出自己过去几年的实验记录整理出几条最想对正在从零开始的人说的话。第一条不要等基础全部扎实再动手。AI工程是一个极度依赖反馈的领域很多教科书没写的细节只能从踩坑里学会但踩坑的前提是你已经有一个能跑起来的东西哪怕它非常简陋。第二条算法能力和工程能力都重要但工程能力更容易被低估。能写好数据管道、能让训练过程复现、能定位线上问题这些能力不显眼在关键时刻却最值钱。第三条建立自己的实验记录习惯比看一百篇教程都有效。每一组实验的配置、结果、异常都应该沉淀下来。那些看似无聊的记录最终会成为你判断力的土壤。第四条关于时间预期。从零到独立跑通一条小模型的完整训练链路快的话两到三周。从零到能可靠地交付一个生产级AI项目节奏正常的话也需要一年左右。这类能力是磨出来的不是看出来的。最后分享一个我至今仍在用的习惯每隔一段时间就主动做一个自己没做过的小任务——换个数据集、换个模型结构、换个部署环境。这些刻意制造的不舒适是成长最快的时刻也是这条路上最有意思的部分。