
我最近大半年都在折腾一件事把手头几个AI项目从“能跑通代码”变成“能稳定上线服务”。这整个过程的本质就是标题里写的ai-engineering-from-scratch——AI工程从零开始。老实讲模型调参本身并没有那么折磨人真正让人半夜爬起来看监控的是数据、版本、部署、监控这些工程环节。任何一个地方掉链子模型在离线指标上再漂亮上线也是原形毕露。这篇文章不聊算法Paper也不提供“AI速成大法”而是把我从零搭建AI工程体系时踩过的坑、验证过的方案、留下的配置原原本本梳理一遍。适合谁看一种是刚入行、想从“会调库”走向“能交付”的算法工程师另一种是团队里已经开始有多个模型项目但总感觉“每次上线都像第一次上线”的工程负责人。1. 先搞清楚AI工程到底在解决什么问题1.1 为什么“模型跑通”和“系统可用”之间隔着一条鸿沟很多人在Notebook里把模型跑通准确率看着不错就觉得完事了。但把同样一个模型放到线上你会发现一堆Notebook里根本不存在的问题请求一多就超时、特征顺序变了导致预测结果错乱、模型文件和生产环境依赖不一致导致加载失败、训练数据分布和线上实时数据分布根本不匹配。这些问题不带任何学术美感却直接决定项目能不能落地。AI工程的定义我自己的理解很朴素把“某一次成功的实验”变成“可重复、可控、可观测的稳定系统”。它关注的是模型之外的那部分——数据怎么管、实验怎么记、服务怎么发、线上怎么盯。一旦你开始同时维护两三个模型项目就会明白没有这套工程体系会乱成什么样你今天改了数据集明天改了预处理逻辑后天换了个基座模型结果线上效果变差了你根本说不清是哪一步引入的。所以AI工程不是锦上添花是雪中送炭。它是模型从实验品变成产品之间的一切必要工作。1.2 AI工程的最小闭环长什么样我一开始犯的错误是追求大而全上来就想上Kubernetes、搞Feature Store、搭完整的ML平台。结果光在基础设施上就耗了两周业务模型一点没推进。后来我砍掉大部分想法只保留一个最小闭环环境可复现 → 数据有版本 → 实验有记录 → 模型可打包 → 服务可部署 → 线上有监控 → 监控反馈回数据集。这七个环节首尾相接形成一个圈。每个环节不需要用多复杂的工具但必须有。刚开始哪怕用Shell脚本和CSV记录都行先把闭环跑通再逐步把每个环节的工具替换成更专业的方案。如果一上来就追求生产级MLOps基建大概率是建了个漂亮的空壳业务根本用不起来。我给出的顺序建议是先做模型打包和服务化再做实验记录再做数据版本最后做监控。因为前两件事能立刻让业务方看到“模型能上线了”给了信心后面的事才好推进。2. 从零搭AI工程环境、数据与实验管理2.1 环境一致性别在“我机器上能跑”上栽跟头AI工程的第一道坎是环境一致性。最常见的翻车现场本地Python 3.9、PyTorch 1.13一切正常测试服务器上是Python 3.8、PyTorch 1.12结果某个算子行为不一样推理结果直接对不上再换到生产环境的Docker容器CUDA库版本又不对模型加载报错。你说这算谁的锅解决方案一句话从第一行代码开始就把环境写死。具体做法是用requirements.txt或pyproject.toml锁住Python包版本包括传递依赖也尽量锁住。直接用pip freeze requirements.txt是最原始的方案但会把一堆无用包也锁进来。更建议用 Poetry 或 uv它们能生成可锁版本的 lockfile。操作系统和基础镜像固定。训练和推理各自维护一个Dockerfile基础镜像写死具体tag比如pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime不要用latest。每次跑完训练把当时的镜像tag记进实验记录里。CUDA、cuDNN 的版本要跟框架编译时对齐。最简单的验证方法在目标环境跑一遍模型的CPU和GPU推理输出差的绝对值如果超过1e-4说明环境不一致的可能性很大先排查环境再排查代码。我习惯在项目根目录放一个environment/文件夹里面存着基础镜像对应的Dockerfile、requirements文件、Makefile或justfile用来一键搞定“构建镜像→启动训练→启动服务”之类常规操作。新人接手项目时第一件事不是装环境而是执行make dev如果失败就知道是环境问题而不是代码问题。2.2 数据版本管理喂给模型的数据不能“随缘”模型训练里有个我最开始忽视的问题数据集变了但没有记录“什么时候变的”“在哪一版基础上变的”。结果就是同一个模型代码隔一个月重跑指标完全不同而整个团队没人记得清训练集到底增删了多少样本。数据版本管理的核心原则把数据集当作代码一样对待。数据集每次变更都应该有一个明确的版本号、变更说明和哈希校验值。在入门阶段最轻的方案是每个数据集文件夹里放一个metadata.yaml记录数据来源、清洗规则、样本数量、标签分布、生成时间。用git-lfs存小数据集几个GB以内可以或者用对象存储 一个 JSON/YAML 清单文件记录版本。训练脚本启动时加载指定版本的数据快照并把版本号写入训练日志。如果数据集比较大、结构比较复杂再上 DVCData Version Control。DVC 的核心思想不复杂把数据文件放在对象存储或NAS上用Git管理“数据文件的指针和哈希”。你切换Git分支数据也跟着切换训练时拉取的就是当时对应的快照。DVC让“哪个代码版本 哪个数据版本”成为一个可以精确回溯的组合。我在实操中的体会是数据版本化最重要的不是选哪个工具而是把“训练集/验证集/测试集不允许覆盖式修改”这条纪律定下来。每次数据清洗、去重、修复标签都必须生成新版本旧版本保留。否则你线上模型出问题想复盘时连“模型当时是用什么数据训的”都说不清。2.3 实验追踪让每一次尝试都能复现实验追踪我是最晚补的代价是我吃过大亏有一版模型效果特别好但我死活想不起来用了什么超参组合。因为我是Notebook里随手改几个参数跑出来的没有记录。后来回头复盘那版的关键在于学习率调度策略而那个策略我根本没记下来。从那以后所有训练任务都接入实验追踪系统。我的首选是 MLflow Tracking因为它是开源方案里对团队最友好的安装轻量Python API简单而且除了跟踪指标外还能顺便管理模型文件。MLflow 里的核心概念三个mlflow.set_experiment(project_name)划定实验范围。mlflow.log_param()记录超参数mlflow.log_metric()记录每个Step的指标。mlflow.log_artifact()把模型文件、预处理配置、标签映射表等文件归档进去。实操中的建议把模型的预处理逻辑也当作“参数”记录下来。很多人只记超参不记预处理。其实preprocessing的不同比如是否做标准化、用什么方式做缺失值填充对效果的影响往往比某个超参还大。我会在训练脚本里把预处理的关键配置序列化成JSON然后log_artifact存进去。这样复盘时打开一次实验代码、数据、预处理、超参、指标、产物全都能对上才叫真正的可复现。3. 模型训练与评估从跑通到可交付3.1 选基座模型还是自己训练标准是什么很多新人面对的第一个AI工程决策是这个任务到底用别人训练好的模型还是自己从零训练这本质上是一个工程成本问题不是技术面子问题。我的决策标准很直接如果任务属于通用领域文本分类、NER、情感分析、通用目标检测首选使用预训练模型或大模型API做微调而不是从零预训练。理由是预训练成本极高你一个人或一个小团队根本刷不出和数据规模匹配的收益。如果任务非常垂直比如特殊文档版式解析、特定工业场景缺陷检测需要大量领域数据那应该基于通用基座做继续预训练或充分微调而不是从零Random Init。如果对延迟和成本敏感且任务逻辑简单直接可以考虑蒸馏一个小的专用模型。具体实操里我给大家一个“最稳妥起步”的路径先用现成模型/API做一版端到端POC验证业务可行性然后把POC里的badcase汇总判断是缺数据、缺特征还是任务定义不清最后再决定要不要微调、用什么模型微调。这样每一步都有依据不会把宝贵的算力和时间浪费在自嗨式调参上。3.2 评估体系怎么搭不能只盯着准确率AI工程落地时业务方问“效果怎么样”如果你只回“准确率93%”这个对话大概率会出问题。因为离线准确率高不等于线上好用。比如一个欺诈识别场景正样本只占0.1%你模型把所有样本都判为正常准确率也是99.9%但业务上一分钱防不住。我的经验是把评估切成三层模型层指标除了总体准确率还必须看查准率、查全率、F1尤其是少数类上的表现。建议同时输出混淆矩阵。对于排序任务看NDCG、MAP对于生成任务看ROUGE/BLEU以及人工抽检率。业务层指标模型产出的结果真实投到业务里会产生什么变化比如信用卡反欺诈里的“拦截率”“误伤率”、搜索场景里的“点击率”“无结果率”。这些指标才真正代表模型对业务产生了正向价值。稳定性指标训练集、验证集、测试集之间的指标方差以及同分布样本在不同时间段的指标波动。如果模型测试集分数很高但换个时间段的数据就崩说明泛化能力不行上线风险极大。所以我建议每个模型项目都建一份评估文档固定评估脚本和评估数据集。每次算法迭代必须跑同一套评估流程量化对比而不是拍脑袋说“感觉好多了”。为此我写了一个evaluate.py输入模型产物路径输出一份JSON报告里面包含模型层指标、分阈值曲线、badcase列表。这份报告会自动归档到MLflow供以后回溯。3.3 训练资源有限时的省钱策略不是所有人都有一柜子GPU可以随便造。我自己做AI工程的经验里训练资源往往是瓶颈所以省钱策略必须前置。Batch Size 和梯度累积大Batch一般更稳但显存不够时用梯度累积模拟大Batch关键是把有效Batch调大后适当调整学习率否则收敛不稳。混合精度FP16能大幅省显存和加速但注意 loss 可能出现 NaN尤其是小模型和大学习率组合下。建议AMP和Loss Scaling一起用跑短实验验证稳定性。提前停止、早停和模型快照监控验证集指标连续N个epoch不涨就停止同时保存最佳模型快照。而不是傻跑固定epoch数。合理选择模型体量先用小模型比如BERT-tiny、ResNet18把流程跑通再把规模换大。全流程数据处理→训练→评估→导出→上线用小模型验证没问题再上大模型能省大量试错成本。微调时冻结大部分层只训练最后几层或Adapter。这样显存占用和计算量能缩小一个数量级。如果效果不够再逐层解冻。这块想跟大家多说一句训练资源少不丢人用有限资源把流程跑通、把证据链留全比在超大集群上跑一堆没人看的实验有价值得多。AI工程考量的从来不是“谁算力大”而是“谁交付得稳定”。4. 模型上线部署链路与推理优化4.1 FastAPIDocker把模型包成一个标准服务模型训练完之后最重要的一步是把它变成一个可以被业务调用的服务。我推荐的最轻量、最可靠方案是 FastAPI Uvicorn Docker。FastAPI 的优势是自带请求参数校验、自动生成OpenAPI文档、性能也不错对AI服务来说完全够用。一个标准的模型服务结构大概长这样server/ app.py # FastAPI 入口 model_loader.py # 模型加载与预热 inference.py # 前处理/推理/后处理 schemas.py # 请求/响应模型 requirements.txt Dockerfile我在app.py里的最低必要配置启动事件中加载模型并将模型对象放在全局变量里。不要在每次请求时去加载模型否则延迟会高得离谱。用Pydantic定义请求Schema保证输入合法性比如文本长度限制、数值范围校验不要指望下游模型能处理乱七八糟的输入。包一层可观测中间件记下每次请求的耗时、模型版本号、输入长度分布。Dockerfile 里的关键点基础镜像尽量用官方python:3.10-slim如果你需要GPU推理则用带CUDA的镜像把requirements.txt先复制进镜像并安装依赖再复制代码。这会利用Docker Layer缓存改动代码时不会每次都重装依赖。启动命令用uvicorn app:app --host 0.0.0.0 --port 8080 --workers 2。worker数量建议先设为CPU核数再压测调整。提示千万不要把训练时用的整个虚拟环境或模型Checkpoint直接塞进生产镜像。镜像里只放推理必需的东西模型导出文件如ONNX或TorchScript、预处理配置、后端依赖。镜像越小启动越快出问题面也越小。4.2 推理延迟优化能省一点是一点上线之前一定要压测不压测你根本不知道这个服务能扛多大流量。我在压测中发现的一个典型问题模型本身推理只需要几毫秒但Python端前处理和JSON序列化却花了上百毫秒导致整体延迟不可接受。总的来说推理优化有几个层级的思路输入输出层能批量推理就批量推理。单条请求过来时可以把多条请求攒一小段时间比如攒10条或50ms再统一过一次模型吞吐能提升好几倍。但要权衡延迟不是所有场景都能接受攒批。模型编译层PyTorch 可以用torch.compile()或导出成ONNX后用ONNX Runtime跑。ONNX Runtime在CPU上的加速通常很明显尤其在Transformer结构上。简单任务里导成ONNX后推理开销能降低30%-50%强烈建议试一下。量化层INT8量化对显存和速度都有帮助代价是精度损失。一个折中的做法是用FP16精度推理损失很小速度也能提升。生产环境里最好做量化前后的对比评估不要默认“量化没损失”。缓存层对重复性高的请求比如相同文本查相同内容可以用LRU缓存或者Redis缓存结果。注意缓存key的规范化避免因空格或全半角差一点导致缓存完全失效。这一段的实操心得是先压测再优化。用locust或wrk打一下看P95延迟和吞吐找到瓶颈再动手。别一上来就搞TensorRT很多场景把FastAPI处理层优化一下比折腾推理引擎收益大得多。4.3 服务治理版本、灰度与回滚模型是要迭代的所以服务从第一天起就要考虑多版本的问题。我见过最原始的方式直接改代码把新模型路径替换掉重启服务。这种做法一旦新模型有严重线上问题想回滚都不知道旧文件还不在。正确做法是模型文件带上版本号放到对象存储或NAS镜像目录里比如model/mt5_sentiment_v3.onnx。路径里带版本号而不是都用model.onnx覆盖。应用支持通过环境变量指定加载哪个版本比如MODEL_VERSIONv3。这样升级时只需要改Kubernetes的环境变量配置就可以平滑切换版本。线上保留至少一个旧版本路径万一新版本出问题立刻把环境变量切回去。整个过程不修改代码、不重新构建业务逻辑只做配置变更。更稳妥的做法是灰度发布先切5%流量到新版本服务观察一段时间指标没问题再加到50%、100%。如果团队已经有网关或服务网格用它们的路由能力实现如果没有也可以先做“影子流量”——把线上请求复制一份打到新版本服务上比对新旧版本输出差异但不影响真实业务。服务治理这部分最容易被算法团队忽略但对运维和业务连续性至关重要。一个不起眼的“模型版本管理”能把故障恢复时间从小时级降到分钟级。5. 线上监控与持续迭代5.1 模型在线上跑偏了怎么及时知道模型上线不是终点而是持续运营的起点。我吃过最大的亏就是模型上线后两周没盯然后业务方跑过来说“最近效果怎么明显变差了”。我一看需求的数据分布早就变了模型还在用老逻辑硬扛。线上的监控指标我分成两类系统指标CPU、内存、GPU显存、请求量、延迟P50/P95/P99、错误率。这部分用PrometheusGrafana就能解决配合告警规则。我建议最优先盯两个错误率超过阈值比如5%和P95延迟突增。模型指标预测结果分布、空结果率、平均置信度、特征分布偏移。这部分要结合业务来看。比如一个交易风控模型上线后平均分从0.3漂到0.7那就说明特征分布变了或者有异常数据进来需要触发人工排查。更专业的做法是记录每次请求的输入特征快照和预测结果按天或者按小时做统计存入数据库或者数据仓库。当天的特征均值、方差和训练集特征均值、方差如果出现大幅度偏差就说明发生了数据漂移。我自己的监控告警设置白天每5分钟检测一次最近1小时的数据分布变化如果PSI超过某个阈值比如0.2立刻发告警到企微/钉钉群。宁可误报多点也不要漏报。5.2 数据回流与自动重训的门槛监控发现问题之后最理想的流程是把线上badcase回流到标注池由人工标注或算法辅助修正扩充训练集然后重训模型验证通过后重新发布。这就是数据闭环。但自动重训没有想象中那么简单。我团队里最早尝试“每周自动重训一次”结果新模型上线后效果反而更差了——因为新数据本身有偏自动标注质量参差不齐直接把模型带偏了。从那以后我总结出自动重训必须满足的几个门槛有足够高质量标签。自动标注或弱监督标签必须经过采样抽检抽检准确率低于90%就不会直接用。有稳定的评估集。不能用一个持续变化的评估集来评判模型好坏否则指标的波动会让你分不清是模型变好了还是评估集变严了。有明确的发布标准。新老模型做离线对比必须在关键指标上不差于老模型比如F1不降、badcase数量不增才能进入灰度。有快速回滚能力。自动重训发布后如果线上指标异常要能一键回滚到上一个稳定版本。最终我把“自动重训”降级为“半自动重训”系统自动采集数据、自动触发训练、自动生成评估报告但最终是否发布由人确认。既保留了闭环的效率又加了一道人为把关的风险阀。这套流程跑顺之后我的模型迭代效率比之前手工处理高了一倍不止。6. 我踩过的坑与实操清单6.1 几个典型翻车现场聊聊我记忆特别深、也特别有代表性的几个坑。很多问题在网上基本搜不到系统性的解决方案都是一点点踩出来的。坑一训练脚本在本地能跑一上GPU服务器OOM。原因是本机显存大Batch Size开得很高换到小显存机器直接爆。后来我把Batch Size、显存占用做成配置项并用torch.cuda.max_memory_allocated()观察显存峰值在训练脚本里加自动Batch Size检测超了就自动降配而不是崩溃。坑二换了机器模型推理结果完全对不上。排查一圈发现是sklearn版本不一致导致的预处理结果不同。从那以后预处理逻辑全部固定版本并且把关键预处理步骤输出成SavableArtifact比如归一化参数、词表映射由模型服务统一加载不依赖训练时的全局状态。坑三模型服务上线后每天凌晨出现大量超时。查了半天发现是日志库在凌晨做切分阻塞了事件循环。这是典型的“系统性问题被模型问题掩盖”。后来把日志写入改成异步并且独立进程导出日志服务本身才稳定。坑四灰度发布一刀切全量切过去后新模型在某个流量段上疯狂输出低质量结果。解决方案就是前面说的灰度影子对比先让新模型“无流量”在线上一段时间比对输出稳定后再放量。6.2 给准备动手的人的checklist如果我现在要带领一个新团队从零搭建AI工程体系我会按下面这张清单推进每项都是低成本高收益的[ ] 项目根目录有environment/锁住Python依赖和Docker基础镜像。[ ] 训练脚本支持传入数据版本号并在输出日志中记录数据目录的哈希。[ ] 每次实验都能在MLflow或同类系统中找到完整记录参数、指标、代码commit、数据版本、产物。[ ] 模型导出为稳定的推理格式TorchScript/ONNX生产环境不直接加载训练Checkpoint。[ ] 推理服务用FastAPI封装加载模型预热Pydantic校验输入中间件记录延迟。[ ] 用Docker构建生产镜像镜像尽量小启动命令固定。[ ] 压测完成知道服务的P95延迟和最大吞吐能力。[ ] 模型路径带版本号支持环境变量切换版本和快速回滚。[ ] PrometheusGrafana监控系统、模型指标配置基础告警规则。[ ] 设计好数据回流路径哪怕是人工收集badcase也要有稳定的通道。[ ] 制定模型发布规范离线对比→灰度→全量→回滚预案每条都要可执行。我自己在实际操作中有一个很深的感受AI工程的本质就是把不确定性变成确定性。模型有不确定性是正常的但环境、数据、版本、监控这些环节的不确定性是可以通过纪律和工具消除掉的。你每补上一个环节半夜被叫起来的概率就小一点。这大概就是“从零开始做AI工程”最直接的回报。最后再分享一个小技巧团队里如果只有你一个人懂这套流程一定要把每一步的操作文档写下来哪怕只是几行命令和注意事项。因为等你忙起来或者有新同事接手最怕的不是不懂算法而是不知道你当时是怎么把模型送上线的。文档不追求长篇大论能让人照着三步走到上线就够了。