1. AI工程和算法研究的分界线:动手之前先想清楚要学什么
1.1 算法工程师和AI工程师的真实分工差异
很多人在入门AI时第一个误区,就是把"AI工程"和"算法研究"混为一谈。我问过不少朋友对AI工程的想象,回答大多是"写神经网络模型"、"调参跑模型"、"训个东西出来很厉害"。但实际上,算法工程师的核心任务是探索"怎么让模型效果更好"——改网络结构、设计损失函数、做实验对比;而AI工程师的核心任务是解决"模型怎么稳定地产生价值"——数据从哪里来、怎么流通、模型怎么被调用、出了问题怎么发现、怎么升级。前者是发明,后者是建造。
我举个更直白的例子。算法工程师拿到一个任务,可能用两周时间在Notebook里试了十种模型结构,最后选了一个指标最好的,写一份报告说"这个方法在测试集上F1提升了3个点",工作就算漂亮完成了。但AI工程师接手之后,要面对的是:这份数据是爬虫抓的,格式乱得一批,每周都在变;模型训练时要占用的GPU不能影响线上正在跑的推理服务;模型上线后接口调用量波动剧烈,一会儿几十QPS一会儿上千;业务方打电话过来说"上周效果还挺好,这周预测结果怎么全是同一个类别"。这些才是AI工程要解决的日常问题。
所以如果你立志做AI工程,"从零开始"这四个字的关键,不在于学会某个深度学习框架的API,而在于建立一套完整的心智模型:数据的生命周期怎么管、训练和推理的差距在哪里、模型版本和代码版本的关系是什么、监控和告警的边界画在哪儿。这篇博文就是按这个思路,从环境搭建开始,一直聊到生产环境的架构参考,把我自己在实际项目里验证过的做法和踩过的坑全部讲清楚。
1.2 AI工程的核心知识地图
我给自己带过的实习生画过一张AI工程的知识地图,大致分五层,每一层都有需要掌握的硬技能:
- 数据层:数据采集、清洗、标注、版本管理、质量监控。工具上要熟悉pandas、SQL、DVC、Great Expectations。
- 模型层:特征工程、模型训练、超参调优、实验追踪。工具上要熟悉PyTorch、scikit-learn、Optuna、MLflow。
- 部署层:模型打包、接口服务化、容器化部署、资源调度。工具上要熟悉FastAPI、Docker、Kubernetes、Triton Inference Server。
- 运维层:监控告警、日志采集、模型漂移检测、A/B测试。工具上要熟悉Prometheus、Grafana、ELK。
- 平台层:当规模扩大后,需要考虑Feature Store、模型注册中心、工作流编排。工具上要熟悉Feast、MLflow Model Registry、Airflow。
这五层里,绝大多数入门教程只覆盖了模型层的前半段,也就是"把模型训出来"。但真正工作之后你会发现,模型层的工作时长占比可能只有20%,数据层和部署运维层才是真正消耗精力的地方。这个比例背后的原因很朴素:模型是建立在数据和系统之上的,地基不稳,上层再花哨也没用。所以这篇文章的顺序,也是按照从地基往上走的路径来安排的。
2. 从零开始搭一台能干活的工作站:工具链选型心得
2.1 硬件选型:先别急着买显卡
我见过太多人一上来就买了一块RTX 4090,结果发现自己的数据集连一个显卡的显存都用不满,或者更尴尬的是,训练时GPU利用率一直在个位数徘徊,瓶颈根本在CPU数据加载和磁盘IO上。我个人的建议是,先看你手上的数据量和模型规模,再决定硬件投入。
- 数据集在几千到几万样本、模型是CV或NLP中等规模的:一块24GB显存的显卡(如RTX 3090、4090)就足够支持大部分训练尝试,甚至很多场景下用云GPU按需租用更划算。
- 数据达到百万级、模型需要长时间预训练的:这时候要考虑多卡并行和分布式训练,个人买硬件的性价比极低,直接考虑云平台。
- 推理阶段的硬件需求比训练低得多:很多模型用CPU也能做实时推理,GPU反而造成资源浪费,部署时按QPS和延迟要求来配就好。
我自己的主力工作机只是一块二手RTX 3080,显存10GB,跑中小规模的项目绰绰有余。真正的大规模训练任务我都是写到云端跑的。很多人忽略的一个点:AI工程的大部分时间不是在训练,而是在写数据处理代码、调试接口、看日志,这些工作对硬件要求不高,但对开发环境的舒适度要求很高——内存够大、磁盘够快(NVMe SSD)、屏幕够大,反而比显卡更影响幸福感。
2.2 软件栈:我推荐的组合及理由
Python环境管理:用conda,而不是直接往系统Python里pip install。理由很直接:不同项目的依赖互相冲突是家常便饭,conda可以帮你隔离出一套套独立的Python环境,每个项目各玩各的,互不干扰。创建环境的命令很简单:
conda create -n ai-engineering python=3.10 conda activate ai-engineering深度学习框架:选PyTorch。虽然TensorFlow曾经是工业界主流,但近几年无论学术界还是工业界,PyTorch的生态优势都越来越明显。不是说TensorFlow不行,而是从学习成本、社区资源、模型仓库丰富度来看,PyTorch都是更省力的选择。安装时注意根据CUDA版本选择对应的torch版本,用官方提供的安装命令一行搞定。
数据处理:pandas和polars二选一。pandas生态成熟、资料多,适合大部分人;polars性能强,处理大规模表格数据时速度快很多,但资料相对少。我自己的习惯是中小数据用pandas,超过几GB的表格数据用polars。
实验追踪:MLflow。这个工具解决的核心痛点是"我上周跑的模型到底用了哪些参数、哪些数据、效果如何"。MLflow可以自动记录每次实验的指标、参数、代码版本、模型文件,还可以用它的Model Registry做模型版本管理。对个人开发者来说,它带来的秩序感是巨大的。
容器化:Docker。这可能是从本地开发到生产部署之间最重要的一道桥。后面我会专门讲Docker在AI工程里的用法,这里先记住一句话:你的Python代码可能在自己的机器上跑得好好的,但换一台机器就崩——Docker就是用来消灭"在我电脑上是好的啊"这个经典问题的。
代码管理:Git是底线,不用讨论。建议从第一天起就养成"每个项目一个仓库,每次改动一个commit,commit message写清楚在干什么"的习惯。这不是纪律问题,是效率问题——你在三个月后回看自己的代码时,commit history会是最好的笔记。
这套组合拳打下来,你的开发环境就已经具备了一个合格AI工程项目的骨架。接下来真正重要的问题只有一个:工作流怎么走。
3. 一个标准AI工程项目的完整落地流程:从数据处理到模型上线
3.1 数据阶段:80%的工作量藏在这里
我反复跟团队讲一句话:"数据决定模型效果的上限,模型只是去逼近这个上限。"你特征工程做得再花哨,模型结构再先进,喂进去的数据本身是脏的、偏的、缺失的,结果一定好不了。这个阶段的工作,大致分四步走。
第一步,明确任务定义和评估指标。很多人一上来就着急处理数据,连"什么算好"都没想清楚。做分类任务,指标用准确率还是F1?做排序任务,指标用AUC还是NDCG?做生成任务,指标怎么人工评估?这些不先定下来,你后面做的所有实验都缺乏参照系。而且指标要跟业务目标绑定——比如一个垃圾邮件识别模型,准确率可能不是最重要的,把正常邮件误判成垃圾邮件的代价,比把垃圾邮件漏判进来高得多,这时候精确率(precision)和召回率(recall)的权重就不一样。
第二步,数据采集和清洗。这一步最消耗体力,但也最不能省。我处理过一份用户行为日志,字段名叫"timestamp"的居然有字符串、Unix时间戳、带时区的ISO格式三种形态混在一起;另一个字段叫"user_id",但有的地方是数字ID,有的地方是MD5加密串。清洗规则只能一条条写、一条条验证,没有什么银弹。我的建议是:把清洗过程写成脚本并放到代码仓库里,用DVC这类工具管住数据版本,保证你每次跑实验用的都是同一份清洗逻辑——这一点极度重要,后面讲数据泄漏的时候还会提到。
第三步,数据标注和增强。小型项目常常需要人工标注。我踩过的坑是,刚开始标注时标准不明确,前两百条标完发现标准变了,全部返工。走对的路子是:先小批量标注五十条,和标注的同学(或者自己)对齐标准,再迭代两三轮,最后才大规模铺开。数据增强方面,CV任务常用的翻转、裁剪、颜色抖动,NLP任务常用的同义词替换、回译,都是轻量级提升鲁棒性的手段。但要记住:增强样本必须只在训练集上做,验证集和测试集必须是"干净"的。
第四步,训练/验证/测试集划分。这个划分不是随手train_test_split就完事的。如果是时间序列数据,要用时间切分而不是随机切分;如果是多分类且某些类别样本极少,要考虑分层抽样;如果有数据泄漏风险,划分要先于任何特征处理。划分完之后,记得保存一份划分好的数据文件作为"基准数据",之后所有实验都用同一份划分,否则实验结果不可比较。
3.2 训练与实验追踪:让每次尝试都可复现
进入训练阶段,很多人会直接开始敲代码写model,但我建议你先建立一套实验追踪的机制,再开始跑第一个实验。MLflow的用法大致是这样:
# 安装 MLflow pip install mlflow # 训练脚本中记录 import mlflow mlflow.set_experiment("credit-risk-model") with mlflow.start_run(): # 记录超参 mlflow.log_param("learning_rate", 0.001) mlflow.log_param("num_layers", 3) # 记录指标 mlflow.log_metric("val_f1", 0.82) mlflow.log_metric("val_precision", 0.79) # 记录模型 mlflow.sklearn.log_model(model, "model")这套机制的价值在哪儿?我举一个实际场景。你某次实验突然效果特别好,想复盘到底改了哪个变量。如果没有实验追踪,你的记忆大概率是靠不住的;有了MLflow,你可以一目了然看到这次run对应的代码commit、参数配置、数据版本、评估指标,复现只是重新跑一次的事。
训练过程中还有几个实操小技巧:
- 设置固定随机种子(seed),否则同样的训练代码每次跑出来的结果都略有偏差,排错时非常难定位。
- 用早停(early stopping)监控验证集指标,防止过拟合同时也节约时间。
- 定期保存checkpoint,训练中GPU机器断电、内存溢出都是常态,没有checkpoint = 前面的算力全部白费。
- 梯度裁剪对一些模型来说是稳定训练的关键,特别是Transformer类模型,这个超参值得好好调一调。
3.3 模型打包和部署:容器化是基本功
训练完成后的模型只是一个artifact,真正要让它产生业务价值,必须变成可以被外部系统调用的服务。最常见的方案是封装成REST API。
用FastAPI封装模型的代码简单直接:
from fastapi import FastAPI from pydantic import BaseModel import joblib app = FastAPI() model = joblib.load("model.joblib") class PredictRequest(BaseModel): features: list[float] @app.post("/predict") def predict(req: PredictRequest): result = model.predict([req.features]) return {"prediction": result.tolist()}但这一步真正的坑,藏在你没注意到的地方。比如:模型文件怎么打进镜像?推理时预处理逻辑和训练时是否完全一致?多个模型同时部署时端口和内存怎么分配?
我建议docker化部署的模板大概长这样:
FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY model.joblib . COPY app.py . # 健康检查 HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD curl -f http://localhost:8000/health || exit 1 CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]这里有个细节值得展开。你的推理预处理逻辑必须在服务里完整复刻训练时的预处理逻辑,一字不差。这个是我见过最多线上事故的根源:训练时做了归一化、缺失值填充、特征组合,部署时漏了其中一步,模型推理输出的结果就完全变味了。所以现在我的做法是:把预处理逻辑单独封装成一个模块,训练和推理共用同一份代码,而不是在训练脚本里写一遍、在推理服务里又写一遍。
4. 实测中最容易翻车的三个环节
4.1 数据泄漏:数据处理顺序错了全盘皆输
数据泄漏是个很隐蔽但后果极严重的错误。最典型的一种是我自己踩过的:在划分训练集和测试集之前就做了全量数据的标准化(StandardScaler)。
当时的情况是这样。我用一份用户信用数据做违约预测模型,数据共五万条,我先用MinMaxScaler对整个数据集做了归一化,然后才划分训练集和测试集。训练出来的模型在测试集上F1高达0.93,我当时还高兴得不行。直到后来看了别人分享的数据泄漏案例,才猛地反应过来:归一化的时候,测试集的均值和最大值信息已经被"偷看"了——模型见过的特征分布里面已经包含了测试集的统计信息,这个测试集分数虚高得没有意义。
正确的顺序是这样的:
# 错误的做法 scaler = MinMaxScaler() X_scaled = scaler.fit_transform(X) # 用全量数据fit X_train, X_test = train_test_split(X_scaled, ...) # 正确的做法 X_train, X_test = train_test_split(X, ...) scaler = MinMaxScaler() X_train_scaled = scaler.fit_transform(X_train) # 只用训练集fit X_test_scaled = scaler.transform(X_test) # 测试集只transform类似的数据泄漏场景还包括:特征选择在全量数据上做、缺失值填充用了全量数据的统计值、文本向量化时词汇表覆盖了测试集的词。规律就是一句话:任何从数据里统计出来的信息,都只能从训练集里学,测试集永远只做transform不做fit。
4.2 训练和推理的预处理不一致
前面提到过,训练和推理的预处理不一致是线上事故的头号元凶。这里补一个更具体的实例。
我做过一个NLP文本分类项目,训练时对文本做了这么一串处理:小写化、去标点、去停用词、用BERT tokenizer分詞。模型上线后接到的线上请求五花八门,有的文本全是英文大写、有的带着HTML标签、有的带着表情符号,而推理服务里的预处理代码,只写了tokenizer(text),前面的清洗步骤全都没写进去。结果线上预测效果惨不忍睹。
这个问题说起来非常蠢,但为什么会反复发生?因为训练时的预处理代码散落在Notebook各个单元格里,部署时重新写推理脚本,根本没有一个统一的模块可以导入。后来我的解决方案很朴素:所有预处理逻辑从进Notebook的第一天起就放在一个单独的preprocess.py里,训练脚本和推理服务都import preprocess。这样想不一致都难。
另外一个相关的细节是:训练环境里的库版本和生产环境里的库版本要保持一致,尤其是不稳定版本的神器。某个库的大版本升级常常带来行为变化,比如字符串处理函数的默认参数变了,输出就不一样了。Docker镜像锁版本、requirements.txt精确到小版本号,是省掉一堆麻烦的关键。
4.3 版本管理只有代码没有数据
很多Git仓库管理得很规范,代码干干净净,但数据文件要么裸放在服务器目录里、要么用网盘传来传去。等到某天想复现一个两个月前的实验结果,数据集已经被人改过了一版,特征列被人加了两行,原始文件找不到了,实验就没法复现了。
现在我的数据管理习惯是:
- 数据文件不进Git(大文件也不适合),但用DVC对每个版本的数据文件生成一个元数据记录,并推送到远端存储。
- 每次实验记录
data_version这个字段,和代码的git commit绑定。 - 数据变更必须有变更说明,和代码commit一样,写清楚"改了什么、为什么改"。
具体操作大概是这样:
# 安装 DVC pip install dvc # 将数据纳入版本管理 dvc add data/raw/credit_data.csv git add data/raw/credit_data.csv.dvc git commit -m "add raw credit data v1" # 之后每次切换数据版本 dvc checkout这套流程的好处是,哪怕过了半年,只要查一下当时实验日志里记录的git commit和DVC版本号,两行命令就能把数据、代码、模型全部恢复到当时的状态。这不是可有可无的好习惯,而是严肃工程项目的必需品。
5. 从Demo到生产系统:进阶路线与架构参考
5.1 监控与评估:模型上线只是起点
模型部署上线,不是项目的结束,而是运维的开始。很多模型上线后效果会随时间衰减——用户行为变了、数据分布漂了、外部环境变了。你如果不监控,就只能等业务方来找你,那时候已经晚了。
我建议的最小监控清单包括:
- 推理请求量、延迟、错误率:这是最基础的健康指标,接口挂了要在分钟级别发现。
- 输入数据的分布漂移:比如特征均值、方差有没有突变,类别分布有没有明显倾斜。可以用一些轻量级的统计检验,比如PSI(群体稳定性指标)来计算分布差异。
- 预测结果的分布:模型预测的正样本比例如果突然从5%跳到20%,大概率是哪里出了问题,即使还不确定具体原因,也应该触发告警。
工具链上,Prometheus加Grafana是开源社区最常用的组合,收集和展示指标都很方便。告警规则要设计得分层级:P0级告警(服务不可用)立刻通知所有人,P1级告警(指标漂移)进入排查流程,P2级告警(潜在风险)每周汇总review。不要把所有异常都设成紧急告警,告警疲劳会让真正的问题被忽略。
5.2 一个可参考的最小生产架构
把前面所有功夫串起来,一个单模型项目的最小生产架构大概是这个轮廓:
- 数据管道:定时任务从业务数据库或数仓抽取数据,经过清洗、特征工程后写入特征存储或训练集文件。
- 训练管道:DVC拉取最新数据版本,MLflow记录实验参数和指标,通过的时候把注册到Model Registry。
- 模型服务:从Model Registry拉取指定版本的模型,部署到Docker容器里,通过FastAPI对外提供推理接口。多个模型实例放在负载均衡后面,支持滚动更新。
- 监控告警:Prometheus采集推理服务的指标,Grafana展示仪表盘,规则触发时通过企业微信或钉钉机器人发送告警。
这套架构听起来不复杂,但把每个组件的部署配置、权限管理、更新流程全部落地,已经是一个合格的AI工程落地项目了。快速迭代的小团队完全可以用这套底座跑一两年没问题。
5.3 未来三个可扩展的方向
如果项目规模继续扩大,有三个方向值得提前布局。
第一个是特征平台(Feature Store)。当多个模型共用一套特征时,特征计算的重复性和一致性会变成大问题。Feature Store的核心价值是把特征计算集中管理、提供一致的在线和离线特征服务,避免"训练时用的特征和推理时拿到的特征不一样"这种问题。
第二个是工作流编排。当模型数量变多、训练频率变高、依赖链条变长,靠crontab一个个脚本调度已经控制不住了。Airflow这类工具可以帮你管理复杂的DAG依赖,可视化地看到每个环节的状态和耗时,排查问题效率高很多。
第三个是LLM应用工程化。大语言模型给AI工程带来了全新的挑战:Prompt版本怎么管理?RAG的知识库更新机制怎么设计?模型的输出质量和延迟怎么权衡?这些问题的答案还没有统一范式,但对工程师来说反而是最大的机会——越是早期,越值得投入。
最后分享一点个人体会
写了这么多,把AI工程从零开始的路子从头捋了一遍。我自己刚入门的时候也走过弯路,拿着算法教程啃了很久,结果到了真实项目里发现最有用的反而是:清晰的评估指标、严格的数据管理、可复现的实验环境、可靠的部署流程。这套东西不性感,甚至有点琐碎,但正是这些琐碎构成了AI工程的地基。如果你正在这条路上,我给的建议是先跑通一个小项目的完整闭环——不用大模型不用大数据,哪怕是对一个几千条的数据集做分类,把数据版本、实验追踪、Docker部署、基础监控全部走一遍。这个过程走完,你收获的不只是代码,而是一整套"遇到问题知道从哪里下手"的工程直觉。
另外有个小技巧,是很多资料里不讲但实际非常有用的:写实验笔记。不用写多正式,就是记录今天做了什么尝试、结果如何、为什么放弃或继续。坚持一个月后回头翻,你会发现一些当初忽略的细节,其实是关键变量的蛛丝马迹。这个习惯帮我省过的排查时间,要比我花在记录上的时间多得多。
希望你手里的每一个模型都不只是"跑通了",而是真正稳定地、长期地产生价值。