
这两年AI领域火得一塌糊涂从大模型到Agent再到多模态几乎每隔几个月就会冒出一个新概念。后台经常有朋友问我想转AI工程方向该怎么开始我的回答通常就一句话——找一个具体问题把数据、训练、部署整条链路亲手跑通一遍你就入门了。光刷教程、存资料没用那些只有在真正动手时才会遇到的坑才是AI工程里最值钱的经验。这个经验总结下来就是今天想和你聊的这套思路我把整个学习路径命名为ai-engineering-from-scratch。它不是某个框架的官方文档也不是一道面试题解析而是一条从零开始的实战路线。适合刚入行的算法工程师、想转AI方向的后端开发也适合想做个人AI项目的独立开发者。核心目标只有一个让你在没有现成脚手架的条件下也能独立完成一个可以上线、可以维护的AI应用。1. 先对齐认知AI工程不是AI研究from-scratch也不是从零造轮子很多人一听到“from scratch”第一反应是“要从反向传播开始手写Transformer”。这个理解不能说错但和实际工程需求完全不是一回事。AI工程里的“从零开始”指的是在没有现成业务模板、没有现成部署脚本的情况下你有能力自己把一个AI应用从数据准备做到线上服务。你不需要重新发明优化器也不需要重新实现Attention你需要的是把已有的成熟组件用对、用稳、用明白。研究岗和工程岗的工作方式差异很大。研究关注的是“新算法能不能work”结论往往体现在论文和实验记录里工程关注的是“这个系统能不能稳定跑三个月”结论体现在可用性、延迟、吞吐和成本上。同一个模型在Notebook里跑通和在生产环境里稳定服务中间隔着一整条工程链数据校验、版本管理、训练复现、模型评测、接口封装、资源监控、灰度发布。这些恰恰是“ai-engineering-from-scratch”要补的东西。我习惯把AI工程能力分成三个台阶。第一层是调用API注册一个服务、拼几个Prompt就能出结果这是体验层第二层是微调开源模型基于Llama、BERT、Qwen这些模型在特定数据上做训练这是应用层第三层是自建训练和推理管线能自己搞定数据清洗、分布式训练、推理优化这是基建层。大多数人的目标是第二层和第三层之间而“from-scratch”路线正是帮你在前两层站稳脚跟并摸到第三层的门槛。这个项目适合的读者是有一定编程基础、但没系统做过AI项目的朋友。你不需要数学天赋异禀但至少得能熟练写Python、会基本的Linux命令。如果你完全不会编程那第一步应该是先补基础语法而不是直接上手训练模型。如果已经有几个跑通的AI项目这套内容对你来说偏基础可以重点看第四章的踩坑部分那些问题在真实业务中非常常见。2. 四块底子缺一不可数据、模型、训练、部署的入门厚度真正开始之前得先盘点一下自己的“地基”。AI工程不是一个单一技能而是四块能力拼起来的数据工程、模型应用、训练调优、部署运维。哪一块太短项目都会卡住。我见过不少模型调得不错的同学一到上线就被接口响应时间、并发问题折腾得够呛也有很多后端背景的朋友代码写得挺干净却不知道Loss不降该怎么排查。四块底子都不需要你成为专家但每一块都得有足够的操作经验。2.1 Python工程化别让Notebook毁掉你的第一个项目如果你是靠Jupyter Notebook起步的那第一个要改掉的习惯就是用Notebook写训练脚本。Notebook适合做探索、画图、验证想法但它很难做版本管理也很容易让代码状态变得不可复现。真正的AI工程代码应该是一个结构清楚的Python项目有requirements.txt或pyproject.toml管理依赖有config.yaml放参数有train.py、eval.py、serve.py这种入口脚本还要有日志和基本的异常处理。这个转变不是形式主义。举个我自己的例子第一次训练BERT分类模型时全部代码都在Notebook里中途调了三十几次参数几个月后再回来看根本分不清哪份输出对应哪版代码。后来改成脚本加配置的结构每个实验记录下代码commit号和参数文件问题才彻底解决。所以哪怕只是自己学习也建议从一开始就用正规的工程结构写代码。2.2 数据能力真正会花最多时间的地方很多人以为AI工程的核心在模型实际上真实项目里80%的时间都在跟数据打交道。你需要会清洗文本、处理缺失值、做标签分布检查、划分训练验证集、做一些简单的数据增强。数据质量直接决定了模型效果的上限后面所有花在调参上的时间都是在弥补数据不干净带来的损失。这里有一个很反直觉的经验拿到数据后先别急着训练先做一次数据体检。文本长度分布、类别是否均衡、有没有重复样本、标签有没有标错、特殊字符和乱码占多少比例。这些检查花上一个小时可能比后面调三天参数都管用。我见过一个中文评论分类项目第一版模型F1一直卡在70%上不去后来发现是数据里大量样本的标签和内容完全对不上清洗后F1直接跳到85%模型代码一行没改。2.3 模型与训练够用就好但原理不能是黑盒模型环节不需要把每个网络结构都推导一遍但有几个核心概念必须真正理解损失函数、优化器、学习率、Batch Size、Epoch、过拟合和欠拟合。尤其是学习率它可能是训练环节里最影响结果的一个超参数。学习率太大Loss会震荡甚至发散太小模型学得慢还容易陷在局部最优。新手建议用3e-5到5e-5这个范围起步配合warmup和线性衰减大部分NLU任务都不会出大问题。选模型时也要有意识。做中文文本分类可以先用bert-base-chinese做对话或生成可以选Qwen2或Llama3这样支持中文的开源模型做轻量级线上服务则需要考虑albert、tinybert这类体积更小的选择。通用原则是先用一个成熟的baseline模型跑通全流程再考虑是否换更大或更小的模型。不要一开始就追求“最强模型”因为你的瓶颈往往不在模型能力而在于流程还没理顺。2.4 部署与运维能稳定跑起来才算真正做完训练出好的参数只是第一步把模型变成一个可以对外提供服务的接口才是AI工程的临门一脚。你需要把训练好的权重加载进一个轻量级服务框架比如FastAPI、Flask然后处理好输入校验、模型加载时机、并发控制、显存占用等细节。再进一步就是容器化部署用一个Docker镜像把整个依赖环境打包这样换一台机器也能一键启动。这部分的入门门槛其实不难难的是“稳定”二字。模型服务跑起来之后你要关注的是QPS、延迟、显存变化趋势和错误率。这些指标不是锦上添花而是线上事故的第一道防线。我后来做过一个文本审核服务高峰期显存被慢慢吃满如果不盯着监控很容易触发OOM。这个问题在第四章我会详细讲。3. 最小闭环实战7天从一台空机器跑通一个文本分类服务理论说再多不如动手做一遍。我在这里给你一个可以直接参考的“7天最小闭环”方案。它不追求复杂的业务场景就做一件最简单的事训练一个中文情感二分类模型然后封装成HTTP接口最终能在浏览器里调用它。这套流程跑通之后你可以把其中的每一步替换成更复杂的任务但骨架不需要变。3.1 第1~2天环境与依赖的确定性准备一台带GPU的Linux机器安装好Python 3.10、CUDA驱动和PyTorch。这里最关键的词是“确定性”所有依赖版本都必须固定。用requirements.txt把torch、transformers、datasets、scikit-learn、fastapi、uvicorn这些库的版本锁死避免几个月后环境升级导致脚本跑不了。CUDA和PyTorch的版本匹配是最容易踩坑的地方。PyTorch官网安装命令里会写明对应的CUDA版本比如pip install torch --index-url https://download.pytorch.org/whl/cu121这里的cu121表示CUDA 12.1。先别管哪个版本最新直接看你GPU驱动支持的CUDA版本然后用PyTorch对应版本即可。我自己的经验是不要追求最新选择已经发布半年以上的稳定版本坑都已经被人踩平了。3.2 第3~4天数据准备和训练脚本找一份公开的中文情感分类数据比如外卖评论或电商评论通常几千到几万条就够用来学习。用HuggingFace的datasets库加载数据切分训练集和验证集然后用AutoTokenizer完成文本编码。以下是一个关键训练片段你可以直接参考from datasets import load_dataset from transformers import ( AutoTokenizer, AutoModelForSequenceClassification, TrainingArguments, Trainer, ) dataset load_dataset(json, data_filestrain.jsonl) tokenizer AutoTokenizer.from_pretrained(bert-base-chinese) def tokenize(batch): return tokenizer(batch[text], truncationTrue, paddingmax_length, max_length128) dataset dataset.map(tokenize, batchedTrue) train_data dataset[train].shuffle(seed42).select(range(8000)) eval_data dataset[train].shuffle(seed42).select(range(8000, 10000)) model AutoModelForSequenceClassification.from_pretrained(bert-base-chinese, num_labels2) training_args TrainingArguments( output_dir./checkpoints, num_train_epochs3, per_device_train_batch_size16, per_device_eval_batch_size32, learning_rate3e-5, warmup_ratio0.1, evaluation_strategyepoch, logging_dir./logs, save_strategyepoch, seed42, ) trainer Trainer( modelmodel, argstraining_args, train_datasettrain_data, eval_dataseteval_data, ) trainer.train()这里有几个细节值得说明。shuffle(seed42)保证了每次划分数据时得到相同结果这直接关系到实验可复现。max_length128足够处理大多数短文本评论如果文本很长再加大。learning_rate3e-5是BERT系列微调的稳妥默认值不要拍脑袋改成1e-3这种大学习率。训练过程中关注训练集和验证集的Loss曲线如果训练Loss持续下降但验证Loss不降或上升说明过拟合了可以增加数据量或减小模型容量。3.3 第5~6天用FastAPI封装模型服务训练完成后导出模型再加载到服务里。一个标准的做法是训练脚本只负责产出模型参数服务脚本独立加载参数并对外提供接口两者不要耦合在同一个文件里。服务端核心逻辑不复杂from fastapi import FastAPI from pydantic import BaseModel from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch app FastAPI() tokenizer AutoTokenizer.from_pretrained(./checkpoints/checkpoint-500) model AutoModelForSequenceClassification.from_pretrained(./checkpoints/checkpoint-500) model.eval() class Item(BaseModel): text: str app.post(/predict) def predict(item: Item): inputs tokenizer(item.text, truncationTrue, paddingTrue, max_length128, return_tensorspt) with torch.no_grad(): outputs model(**inputs) logits outputs.logits pred int(torch.argmax(logits, dim-1)[0]) return {label: pred}有一个容易忽视的性能问题默认情况下FastAPI是同步阻塞的而模型推理是CPU/GPU密集型操作同步接口在并发请求增加时响应时间会大幅波动。简单做法是用def改成异步效果有限正确方向是后续引入任务队列或推理服务框架比如Triton或vLLM。但作为最小闭环先把接口跑通、能返回结果这个阶段的任务就完成了。3.4 第7天容器化、压测与监控把服务打包进Docker这一点在做AI工程时会反复用到FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [uvicorn, serve:app, --host, 0.0.0.0, --port, 8000]如果你在GPU机器上跑需要额外安装NVIDIA容器工具包启动时用--gpus all参数。容器化最大的价值是把“能在我机器上跑”变成“能在任何机器上跑”后续多人协作时这个能力是关键。然后写一个最简单的压测脚本用requests并发发送几十个请求统计平均响应时间和错误率。同时用nvidia-smi周期性记录显存使用量观察模型服务是否稳定。到这里你已经在7天里完整走过了AI工程的闭环数据清洗、模型微调、服务封装、容器部署、基础压测。这个经历比看一百篇教程都值钱。3.5 为什么要选这个技术组合BERT加FastAPI加Docker可能有人觉得不够“新”但恰恰是这种成熟组合最适合起步。BERT类模型参数量适中单卡就能训练推理速度也够快HuggingFace生态把数据处理和模型调用封装得很完整能让新手把精力集中在理解流程上FastAPI写接口成本低、文档自动生成调试起来非常方便Docker解决环境问题省去“换台机器就崩”的烦恼。这套组合不一定是线上最优解但一定是学习性价比最高的解。4. 我在前几次实战中踩过的坑现象、根因与修复这个章节是我最想跟你分享的部分。下面几个问题都是我在真实项目里遇到过的每一个都花了不少时间排查。如果你能提前知道这些坑至少能省出好几个周末。4.1 固定了seed却还是不可复现我吃过一次大亏训练脚本里明明设置了torch.manual_seed(42)但两次训练出来的F1分数差了0.02模型预测结果也不完全一致。后来排查发现原因有三个。第一我只固定了PyTorch的seed没有固定Python的random和NumPy的np.random.seed第二DataLoader的随机打乱操作有独立的随机源需要给generator传参数第三CUDA卷积操作本身存在非确定性算法需要额外设置torch.backends.cudnn.deterministic True和torch.backends.cudnn.benchmark False。完整做法是写一个set_seed函数把random、numpy、torch都固定住并在Transformer的TrainingArguments里设置seed和data_seed。不要嫌麻烦实验不可复现意味着你过去所有调参结论都可能是错的。4.2 Docker里的DataLoader死锁有一次模型训练在本地跑得好好的完完整整打包进Docker后一启动训练就卡住不动CPU占满但Loss不更新。查了很久问题出现在DataLoader的num_workers参数上。Docker容器默认对shared memory的限制很小而PyTorch的DataLoader多进程模式需要共享内存在进程间传递数据。当num_workers大于0时容器的默认/dev/shm空间不够用就会产生死锁。解决办法有三种把num_workers设为0简单但训练变慢在启动容器时加--shm-size8g参数或者在Dockerfile里设置ENV PYTHONUNBUFFERED1配合日志排查。我后来习惯把--shm-size直接写进部署脚本避免每次新建容器都踩一遍。4.3 验证阶段不关梯度导致的显存泄漏这个坑非常隐蔽。我在训练一个文本生成模型时发现显存占用会随着Epoch增加而缓慢上涨到最后GPU直接被OOM杀进程。一开始怀疑是模型泄漏后来定位到问题出在验证/推理代码里我调用模型时没有包上torch.no_grad()。如果不关梯度每次推理都会构建计算图计算图在反向传播不需要时会延迟释放显存就一点一点堆积。凡是只在推理阶段执行的代码无论是验证集评估、生成结果还是线上服务都必须加上with torch.no_grad():。这是AI工程里最容易犯、也最容易排查的问题先看代码里有没有漏掉no_grad。4.4 恢复训练后Loss突然飙升训练跑到第10个Epoch时机器重启我用Trainer的checkpoint恢复了训练结果Loss从0.2直接跳到1.5。后来才发现我恢复模型权重时只加载了model.pt却没有恢复optimizer.pt和scheduler.pt。优化器的动量信息、学习率调度器的步数状态全部丢失模型相当于带着一个“失忆”的优化器继续训练Loss当然会崩。正确做法是保存时把模型权重、优化器状态、调度器状态、当前Epoch和随机种子全部打包恢复时逐个加载。HuggingFaceTrainer的trainer.train(resume_from_checkpointTrue)会自动处理这些但如果你手写训练循环就要特别小心。这个坑在项目周期长、训练频繁中断的场景里尤其致命。4.5 实验记录一团糟的教训训练了十几个版本后test_v2_final、test_v2_真的最终、final_2024_ok这样的文件夹越来越多最后谁也说不清哪个模型效果最好、用了什么参数、在什么数据上训练过。后来我用MLflow管理实验每次训练自动记录超参数、数据集版本和评估指标。不想引入额外工具的话至少要在项目里维护一个experiments.md把每次实验的时间、数据、参数、指标写清楚。AI工程里忘记记录等于白做实验后面复盘时你会非常感激当时的自己。5. 从最小闭环走向真正的AI工程路线图与习惯养成跑通一个最小闭环之后下一步不是急着学更多模型而是把这条链路做深、做稳。我把它拆成四个阶段你可以对照自己的情况来定位。第一阶段的目标是稳定复现。把上面的文本分类项目换不同的数据集、不同的模型重复跑三遍直到你闭着眼都能搭起整个流程。第二阶段可以做自动化比如用脚本统一管理数据预处理、训练、评估用Docker来保证环境一致性最好再加一个简单的定时任务或CI检查。第三阶段是性能和成本优化学习模型量化、蒸馏、批量推理、缓存策略让同样的GPU可以服务更多请求。第四阶段走向平台化尝试K8s调度、多模型管理、A/B测试、线上监控告警这个阶段你已经可以设计一个小型ML平台了。这几个阶段里工程习惯比工具选择更重要。我的几条个人建议是第一所有代码都用Git管理每个实验对应一个commit第二数据集本身也要有版本没有版本的数据比没有版本的代码更容易让实验失控第三实验记录要写进文档哪怕只是几十行Markdown第四模型服务必须加监控显存、延迟、QPS和错误率这四类指标一个都不能少。如果你准备完全靠自学走过这条路线我的建议是把目标缩小。不要一开始就想着做一个聊天机器人或推荐系统先做一个单模型单接口的小工具。把你自己的一个日常需求做成AI功能比跟风做热门的Agent项目更有价值。做完之后试着把项目整理成一篇文章、一份文档或一次分享输出会倒逼你把原理真正想清楚。我在实际带人做AI项目时最深的感受是大部分人不是被难倒的而是被自己吓倒的。总觉得要先读完论文、先精通数学、先看懂所有源码才配动手写训练代码。其实完全不用。先把这个最小闭环跑通你自然就知道下一步该补什么。那些一开始觉得深不可测的分布式训练、推理加速、模型评估都是在一次一次跑通流程之后才慢慢变清晰的。如果你正准备开始自己的第一个AI工程实践那我的建议是今晚就把数据集找到明天把训练环境装好周末结束前让模型跑出一个结果。别追求完美先追求闭环。一个简陋但完整的系统永远比一个精致但停留在纸面的计划有用得多。