
一提到 ai-engineering from scratch很多人脑海里的第一反应是找个开源模型拉点公开数据集写个训练脚本盯着 loss 曲线慢慢降下来然后就没有然后了。这不是 AI 工程这是算法实验。真正的 AI 工程是一条从数据采集开始一路延伸到模型上线后长期监控和迭代的完整链路。我这两年带过几个从零起步构建 AI 能力的项目最大的感触是从零开始搭一套 AI 工程体系难的根本不是模型结构而是数据、训练、服务、监控这四层怎么咬合在一起。这篇文章就是围绕AI 工程从零搭建这个主题写的适合三类人刚接手 AI 项目但还没想清楚全貌的开发人员、已经在做算法但想补工程化短板的工程师、以及公司里被要求搭一套 AI 能力的团队负责人。我会把整个链路拆开每一层讲清楚为什么这么做、实操时怎么落地、以及我踩过的坑。目标是让看完的人能照着这份思路从一个最简单的二分类任务开始走通自己的第一条 AI 工程链路。1. AI 工程到底在工程什么1.1 先分清三件事算法研究、应用开发、AI 工程很多人把 AI 相关的活儿混为一谈但这三类工作的目标完全不同。算法研究的产出是论文和模型结构创新核心指标是在 benchmark 上的准确率应用开发是调现成的 API 做业务封装核心指标是功能和稳定性AI 工程则是自己搭建从数据到模型再到服务的整套链路核心指标是这条链路能不能稳定运行、快速迭代。AI 工程之所以难是因为它同时面对三个挑战。第一个是数据是活的今天的数据分布和三个月前的数据分布可能已经完全不一样了模型会悄悄变质第二个是模型本身是个黑盒传统软件工程里逻辑是显式写出来的而模型的决策路径是学习出来的出了问题你没法直接 debug第三个是生成和验证的失衡训练阶段跑一次实验可能花几小时甚至几天上线前一刻才发现问题返工成本极高。我见过太多团队算法同学把模型训到 95% 的准确率兴高采烈地交给后端集成结果一上生产环境推理延迟超过业务要求两倍或者线上数据格式和训练时对不上准确率直接崩到 60%。问题不在模型本身而在没人把从训练环境到生产环境这条路上的工程问题想清楚。1.2 from-scratch 和全托管方案怎么取舍既然全托管 AI 平台比如直接用 AutoML 或者托管的模型服务能省掉一堆事为什么还有人愿意从零搭建我自己的判断标准有四个定制深度、数据主权、成本可控、能力沉淀。全托管方案的优点是快但代价是定制受限模型架构、推理优化、特征变换逻辑都锁死在平台能力边界内。数据主权这块更敏感很多行业的业务数据根本不允许离开自己的服务器更别说喂给外部平台。成本上全托管按调用量计费业务量起来之后是一笔不小的固定支出而自建的话一张 3090 或者 A10 能扛住相当规模的推理负载长期分摊下来反而省钱。但也要说句公道话不是所有场景都适合从零搭。业务急着上线、团队没有 AI 基础、数据存量几乎没有这三种情况建议老老实实用托管方案先跑起来等技术积累够了再逐步迁移。从零搭建的正确时机是你已经明确知道用现成方案解决不了我的问题的时候。1.3 一条完整的 AI 工程链路长什么样一条从零搭建的 AI 工程链路大致包含六个环节数据采集、数据清洗与标注、特征工程、模型训练与实验管理、模型服务化、监控与持续迭代。六个环节不是线性的而是首尾相接的环模型上线之后产生的真实预测数据又变成下一轮训练的数据输入。这六个环节里数据相关的工作通常占到整个项目周期的 60% 以上但最容易被低估。很多团队立项时只问用什么模型很少有人先问数据在哪里、质量怎么样、怎么持续供应。如果数据问题没解决后面模型和服务做得再好也是空中楼阁。这个判断我建议所有准备做 AI 工程的团队在立项阶段就要想清楚。2. 从零开始的第一道坎先把数据基础设施搭起来2.1 别急着找模型先把数据管道跑通数据管道是一切的起点。很多从零起步的项目死不是死在模型上而是死在数据上要训练了才发现日志字段缺失、标签对不上、不同批次的数据格式不统一。我现在的习惯是任何 AI 项目启动的第一周不做模型、不跑实验就只做一件事把数据从原始位置稳定地、增量地抽到一个统一的地方形成可查询的数据集。数据采集要解决两个问题来源接入和格式统一。结构化数据通常直接接业务数据库或者数据仓库日志类数据建议走消息队列保证实时性和可回溯性图片、文本这类非结构化数据则需要单独的对象存储加元数据库。格式统一这件事看起来简单实际很烦同一个用户等级字段有的来源叫 level有的叫 user_level有的是字符串L1有的是整数 1不在入口处洗成统一格式后面每个环节都要受这个罪的。增量更新机制是数据管道里最容易漏的一块。全量同步在数据量小的时候没问题但数据量上来之后每天全量跑一遍既慢又浪费存储。更合理的方式是设计增量抽取窗口每天只处理新增和变更的数据同时用离线任务定期做全量对账两边的数据量对不上时能尽早发现。2.2 数据版本管理数据集也要能回滚写过业务代码的人都知道代码要版本管理但很多 AI 项目里数据集是没人管版本的。今天拉一版数据、明天又改了几个字段训练出来的模型你根本说不清楚它吃的是哪一版数据复现实验几乎不可能。数据版本管理就是要把数据集变成可以回滚、可以对比、可以追溯的单元。轻量级方案是用 DVC 这类工具把数据集的元信息和存储位置记到 Git 里每次数据变更提交一个新版本。重量级方案是直接上数据湖方案把数据以 Delta 格式管理起来支持 ACID 事务和时间旅行想查某个时刻的数据状态都能直接查到。具体选哪个取决于团队规模和数据量我个人的建议是先上 DVC成本低、学习曲线平缓等团队成熟之后再看有没有必要换数据湖。注意数据版本和代码版本一定要绑定。实验记录里既要记录代码的 commit hash也要记录数据集的版本号。否则某一天你想重新跑一遍实验发现自己既不知道用的哪段代码也不知道用的哪版数据实验管理就成了一句空话。2.3 特征不一致AI 工程里最经典的坑特征工程阶段最大的坑不是特征怎么构造而是训练和推理时的特征计算不一致。训练时你很随意地在 Python 脚本里算出最近 7 天购买金额均值上线后这个特征变成了线上 Java 服务里另一个计算逻辑两边就差了几个小时的窗口对齐方式结果就是离线指标非常漂亮线上效果一塌糊涂。解决思路是所有特征计算逻辑统一收口。训练时用特征计算模块算特征线上推理时也通过服务调用同一份特征计算逻辑或者干脆把所有特征预先计算好存入特征库训练和推理都从特征库里取值。开源方案里 Feast 是比较常见的特征存储选择支持实时特征和批量特征的统一管理。但如果团队体量还小我建议先别上重家伙把特征计算逻辑封装成一个公共模块、强制两端复用就能解决 80% 的坑等规模起来再引入特征存储。2.4 标注成本比想象中大管理比工具更重要数据标注往往是项目预算里最容易被低估的一项。很多人以为标注就是雇几个人点屏幕实际上标注质量直接决定了模型天花板。一个二分类任务标注一致性低于 90%模型准确率想上 95% 就非常困难因为标签本身的噪声已经进入了你无法清除的地带。标注工具的选型开源方案里 Label Studio 和 CVAT 都够用。但工具永远不是核心问题核心问题是标注规范。我吃过教训的项目问题出在标注指南写得含糊——判断图片中是否有违规内容不同的标注员对违规的理解南辕北辙。后来改成必须给正例和反例各配 10 张参考图并明确边界情况怎么处理一致性立刻上来了。质量抽检不能省。最基础的做法是让两个标注员标注同一批数据计算一致性指标比如 Cohens KappaKappa 低于 0.7 就要回头讨论规范问题。标注不是一锤子买卖每隔两周抽检一次比较标注员和审核结果的分歧率及时发现标注员状态下滑或者规范理解偏差。3. 训练实验——模型不是训出来的是被试出来的3.1 实验管理是刚需不是锦上添花做 AI 工程和做算法研究的区别在于工程化场景下做实验是有成本的。一次训练可能跑几小时甚至几天如果实验记录做得不好你根本不知道哪个组合跑出过最好结果下次调参又得从头再来。一个几十次实验跑过去能用的记录寥寥无几时间就全浪费了。实验管理至少需要记录五类信息数据版本、代码版本、超参数、评估指标、模型产物路径。我用 MLflow 解决这件事每次启动训练自动记录这五类信息跑完之后所有历史实验都可以在一个界面里横向对比。关键是这个过程要自动不能指望工程师手动填表格人一旦开始手动记录就会漏。实操心得实验命名规范很有必要。我自己的规则是模型架构数据版本关键超参缩写例如 bert-large-ds_v3-lr3e5。这样光看实验名就能对那次实验有个基本预期而不是满屏的 exp_001、exp_002。3.2 评估指标别只看准确率业务指标才是终点初学者最喜欢盯着准确率但准确率在样本不均衡时非常骗人。假设你的任务只有 5% 的正样本一个啥也不学、永远预测负样本的模型准确率也有 95%。所以分类任务至少要同时看精确率、召回率、AUC 和 PR-AUC回归任务看 MAE 或 RMSE 之外还要看误差分布是否集中。更重要的原则是评估指标要跟着业务目标走。比如你做的是客服工单自动分类模型指标再漂亮如果转人工率没有下降对业务来说就没有任何价值。我会在实验记录里同时写清楚这次实验对应的业务假设是什么等模型上线之后回来验证假设成不成立形成一个闭环。数据泄漏是评估环节最阴险的问题。常见的泄漏路径有三种特征泄漏训练时用到了未来的信息、样本泄漏训练集和测试集有重合、数据预处理泄漏用全量数据算归一化参数后再切分。我一个朋友做时序预测因为不小心用了未来窗口的均值做特征回测结果好到离谱上线后立刻被打回原形。规避办法其实很简单特征计算严格只用历史窗口数据切分先按时间切再算预处理参数交叉验证要保证同一批数据不会同时出现在训练集和验证集里。3.3 训练资源策略先从单卡开始再想分布式很多项目从起步就想上多卡分布式训练我个人建议先忍一忍。单卡把实验跑通、把超参的大致范围试出来效率往往是最高的。多卡分布式训练带来的通信开销、梯度同步、调试复杂度对早期探索阶段是纯负担。等模型结构和数据规模确定下来再迁到 DDP 做多卡扩展一两天就能完成。训练过程中最值得花时间调的是学习率和 batch size。学习率太高模型不收敛太低收敛慢batch size 太大会导致收敛不稳定。我的习惯是先固定 batch size用对数尺度扫描学习率观察 loss 变化趋势找到一个收敛快且稳定的区间再做精细调节。混合精度训练FP16在 NVIDIA GPU 上是默认项训练速度能提升 40% 到 80%几乎不损失精度前提是记得开动态损失缩放。4. 模型服务化——能不能上线全看这一层4.1 训练产物模型要变成服务不是挂个 HTTP 接口就完事模型训练完成后只是一个二进制产物离能扛线上压力的服务还差好几步。最基础的要求是模型加载和推理请求处理要分离不能每个请求来了都重新加载模型否则延迟会高到没人能忍。更合理的做法是服务启动时预加载模型到内存/显存推理请求只做前处理、推理、后处理三件事。另一个容易被忽略的坑是依赖隔离。训练环境里的依赖是一整套 PyTorch 全家桶推理服务如果也照搬镜像体积会非常大、启动很慢、攻击面也大。建议推理阶段把模型导出成 ONNX 格式或者直接用 TensorRT推理代码只依赖 ONNX Runtime 或者 TensorRT 库镜像体积减小一大半推理速度还能提升。下面是一个用 FastAPI ONNX Runtime 搭建推理服务的最小骨架这个结构可以套用到大多数分类、检测任务上import onnxruntime as ort import numpy as np from fastapi import FastAPI, Request app FastAPI() # 启动时加载一次全局复用 session session ort.InferenceSession(model.onnx, providers[CUDAExecutionProvider, CPUExecutionProvider]) input_name session.get_inputs()[0].name def preprocess(raw_text: str) - np.ndarray: # 这里做 tokenizer、padding、转换成模型输入格式 pass def postprocess(logits: np.ndarray) - dict: # 把 logits 转成业务需要的输出结构 pass app.post(/predict) async def predict(request: Request): payload await request.json() input_arr preprocess(payload.get(text, )) outputs session.run(None, {input_name: input_arr}) return postprocess(outputs[0])这个骨架的要点是模型在 app 启动时加载一次之后只是反复执行 session.run避免重复加载的开销。业务代码只跟 preprocess 和 postprocess 打交道模型内部交换格式被隔离在这两个函数里以后换模型或者换引擎不会污染业务逻辑。4.2 推理性能优化batch 是最大的免费午餐我在好几个项目里发现推理性能最大的瓶颈往往不是模型本身而是没有做好请求的 batch 聚合。GPU 是个吞吐型计算设备单个请求过去和 32 个请求一起过去GPU 利用率差别巨大。不做 batch 的话一张 A10 可能每秒只能处理 100 个请求做了动态 batch 之后可以轻松到几百甚至上千。动态 batching 的实现方式如果是自研服务可以维护一个请求队列每隔一小段时间窗口比如 20 毫秒内的请求攒成一个 batch 一次性喂给模型。这么做的复杂度主要在前处理的 batch 化不同请求的输入长度不一样需要 padding 到同一条 batch 内最大长度后端 pad、前端也要对应处理。标准化方案可以考虑 NVIDIA Triton Inference Server它原生支持动态 batching 和多个模型框架PyTorch、ONNX、TensorRT。我现在的实践是 Triton 做模型推理层外面再套一层业务服务做前处理和后处理。这样分工的好处是推理层用 Triton 撑吞吐和并发业务层可以自由演进而不用动模型的加载和调度逻辑。量化是另一大类提升手段。INT8 量化可以把模型体积缩小到原来的四分之一推理速度提升 2 到 4 倍代价是精度有小幅损失。要不要做量化我的判断标准是如果 FP16 的推理延迟已经满足业务需求就没必要承担量化带来的精度风险只有当延迟或成本成为瓶颈时才用量化去换性能。量化之后一定记得做离线和线上的精度对比不能只看单条样本效果。4.3 模型上线流程要想清楚不然回滚都是麻烦从开发到上线有三个环节很多人会漏掉。第一是模型注册与版本管理推上线的模型要有清晰的版本号、对应的数据版本和训练实验 ID否则出了线上问题你都不知道这是哪个训练实验的产物。第二是容器化的可复现性Dockerfile 要固定基础镜像版本和依赖版本不能每次构建都拉最新依赖。第三是回滚预案不是出问题了再说而是在发布前就要定义好检测到线上指标异常如何快速切换到上一个版本。我在线上部署时的做法是把模型产物和相关依赖打成一个镜像镜像 tag 用模型版本号推到镜像仓库后通过修改部署配置滚动更新实例。一旦发现线上指标异常直接把部署配置回滚到上一个 tag几十秒内就能完成切换。这套流程配合自动化告警能极大减少故障持续时间。5. 上线之后才刚开始监控与持续迭代5.1 模型会变质数据漂移是最大的隐形杀手模型上线之后最危险的事不是系统崩溃而是模型悄悄变离谱了。真实业务的数据分布会随着时间推移而变化用户结构变了、市场需求变了、甚至季节不同都会影响数据分布。你可以想象成一家餐厅大厨还是那个大厨菜谱还是那个菜谱但食材供应商换了一批口味完全不同的原料做出来的菜自然就不是那个味了。数据漂移分两类一类是特征漂移feature drift指模型输入特征的分布发生变化另一类是概念漂移concept drift指特征和标签之间的映射关系变了。前者可以通过监控特征的均值和分位数变化感知后者更难检测通常需要定期人工抽样评估。轻量级的漂移检测方法是用 PSIPopulation Stability Index计算特征分布的变化幅度。PSI 小于 0.1 表示分布稳定0.1 到 0.25 之间表示有变化需要关注大于 0.25 表示显著变化模型大概率需要重新训练。另一个基于统计检验的方法是 KS 检验比较训练窗口数据和近期数据的分布差异是否显著。这些方法哪一个都不复杂难点在于你要在模型上线那天就部署好这套监控而不是等出问题之后才后悔。5.2 监控指标三层配齐业务、模型、系统一个都不能少监控体系要分三层来配。业务层指标是离业务最近的效果指标比如推荐场景的点击率、分类场景的准确率、生成的用户采纳率模型层指标是输出分布和置信度分布比如预测为正样本的比例、输出分数的均值和方差系统层指标是延迟、吞吐、GPU 利用率和显存占用。很多团队的监控只盯着系统层GPU 利用率一直很高就觉得万事大吉结果业务效果早就崩了。三层指标要联动起来看系统层判断服务健康度模型层判断模型行为是否异常业务层判断最终效果是否达标。我用 Prometheus 采集指标Grafana 做可视化告警规则分两级一级是系统可用性跌破阈值比如 P99 延迟超过 500ms需要立即响应二级是业务指标连续几个时间窗口下滑超过某个比例进入评估是否需要重训的流程。告警阈值不好拍脑袋定我自己的经验是先上线后观察两周拿到真实的指标分布以后再设定阈值。初始阈值要宽松一些宁可多收告警也不要漏掉跑一段时间后根据告警数量和实际事故的相关性持续收紧。5.3 持续迭代的节奏定期重训与按事件重训模型上线后不迭代等于慢性死亡。持续迭代通常有两种节奏定期重训和按事件重训。定期重训是每隔固定周期比如每周或每月用最近的数据重新训练一轮模型按事件重训是检测到某种特征变化或者业务指标下滑时触发重训。我的建议是两者结合定期重训兜底事件触发防急性恶化。重训过程中要特别注意一个新坑如果只把重训当成最近数据喂进去再跑一遍容易导致模型的灾难性遗忘模型在新数据上表现好但旧场景的能力明显退化。更稳妥的做法是重训时同时混入一部分历史数据保持新旧数据的合适配比让模型在适应新分布的同时不忘旧能力。上线新模型前推荐先跑影子模式新模型和旧模型同时在线预测但新模型结果只记录不生效。收集足够量的对比数据后评估新模型是不是真的在各项指标上优于旧模型觉得没问题再切换流量。这个流程能避免一次次上了线才发现新模型不行的尴尬。6. 常见问题与排查技巧实录问题现象可能的根因排查思路与解法离线指标很高线上效果很差训练和推理特征不一致数据分布漂移线上数据格式和训练时不同先检查特征计算两端是否完全一致再对比训练数据和线上数据的分布差异GPU 利用率一直很低请求量不够batch size 太小数据加载成为瓶颈增大单次推理 batch用动态 batching 聚合短时间窗口内的请求检查数据加载是否同步阻塞模型服务内存/显存持续增长存在资源泄漏可能每次请求创建了新 session 或者没有正确释放显存缓存检查推理服务是否维护了全局的 session 而非每次新建周期性监控显存占用曲线重训后模型在某些业务场景效果下滑灾难性遗忘新数据和旧数据配比不当重训时混入一定比例的历史数据评估时按业务场景分层看效果漂移告警频繁触发阈值设置过严业务本身就存在周期性波动先分清是真实漂移还是周期性规律周期性场景比如周末效应要在阈值设计时排除推理延迟偶尔飙高波动可能来自冷启动、并发争抢或 GC 停顿预热模型到稳定状态后再接流量限制推理线程数观察系统层的延迟分位数而非平均值排查问题的时候最重要的是不要急着改代码。先把训练到推理的链路捋一遍确认哪一层的数据发生了不一致再把监控指标调出来看趋势确定问题是突发的还是渐变的。这两个判断往往能帮你把排查范围缩小一半以上。另外一个我经常犯过的错误是只在模型指标异常时回头看数据平时懒得做数据资产的常规体检。后来我养成了每周花半小时看一遍关键特征的分布图、漂移指标和抽样样本的习惯很多问题在变成事故之前就被拦住了。这一步成本很低价值却很高。7. 从零开始的正确路径先跑通最小闭环再扩展复杂度说了这么多如果你现在正准备从零搭一个 AI 工程我建议的路线是这样的选择一个简单的二分类任务比如文本垃圾识别、图片有无违规内容用公开数据或者自己攒一小批数据从数据清洗、特征工程、训练实验、模型服务化到监控部署完整地走一遍端到端的流程。这个过程中你会踩到所有前面提到的坑但它们都会发生在可控的范围内。跑通最小闭环之后再逐步把复杂度加进来换更大规模的数据、上多卡训练、引入特征存储、把监控阈值调细。每一步扩展都有明确的动机而不是为了炫技而堆技术。我自己见过太多一开始想搞大全套结果半年过去还困在基础设施搭建的团队。AI 工程不是基建比拼是能不能持续产出业务价值的较量。从一个点突破比铺一个大摊子更容易见效。如果你真的决定要走了第一个晚上可以先只做一件事把那个最不起眼的日志管道搭好。因为所有后续的数据分析、特征工程、监控系统全都建立在数据能不能稳定、有序地流进来这个地基上。地基稳了上面的楼才有机会盖高。