ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零搭建AI工程体系:数据、训练、评估、服务与观测五层实战

从零搭建AI工程体系:数据、训练、评估、服务与观测五层实战 1. 从零搭建AI工程能力到底在搭什么很多人第一次看到“ai-engineering-from-scratch”这个标题脑子里冒出来的第一个念头是是不是又要手撸一个Transformer是不是得先把反向传播推一遍我一开始也这么想后来发现方向完全跑偏了。这个标题真正指向的不是让你从零实现一个模型而是让你从零搭建一套能跑通、能迭代、能交付的AI工程体系。模型只是其中一个零件真正吃功夫的是模型之外的那一整套东西。先把话说清楚AI工程和机器学习研究是两码事。研究关心的是“这个结构能不能把指标刷上去”工程关心的是“这套东西明天上线之后会不会崩、崩了怎么查、查到了怎么修、修完怎么验证”。你去看那些真正在生产环境里跑AI的团队代码里模型定义可能只占百分之十剩下百分之九十全是数据管道、特征存储、服务封装、监控告警、回滚机制。所以“from scratch”搭的不是模型是这套骨架。那这套骨架具体包含哪些东西我把它拆成五块数据层、训练层、评估层、服务层、观测层。数据层负责把原始数据变成模型能吃的格式训练层负责把参数调出来评估层负责判断这模型到底能不能用服务层负责把模型能力暴露给业务方观测层负责在出问题的时候告诉你哪里出了问题。这五块缺一块你的AI系统就是个玩具不是工程。适合谁来参考这篇内容如果你已经会写Python、调过几个sklearn或者PyTorch的demo但一到“要把这个东西做成一个能给别人用的服务”就卡住那这篇就是写给你的。如果你是完全零基础建议先把Python和基础的数据处理过一遍再回来不然有些工程上的取舍你体会不到痛。我见过太多人卡在“demo跑通了然后呢”这个阶段。demo跑通只证明模型能拟合不证明系统能交付。从demo到交付之间那条鸿沟就是AI工程要填的东西。下面我按我自己搭过几套系统的顺序把每一层怎么落地、坑在哪、怎么绕一块一块讲清楚。2. 数据层别急着建模先把数据管道焊死2.1 为什么数据层要第一个搭我踩过最惨的一次坑是模型在本地跑得好好的一上训练集群指标就掉。查了两天才发现本地读取的时候pandas自动把某一列推断成了float集群上因为文件顺序不同推断成了object模型吃进去的特征完全变了。这件事让我彻底明白数据管道不稳定后面所有工作都是沙上建塔。所以from scratch的第一步不是import torch是把你数据的来源、清洗、切分、版本管理这四件事定下来。来源要明确是数据库、对象存储还是日志文件清洗要明确哪些字段丢、哪些字段补、缺失值怎么填切分要明确训练验证测试的比例和切分依据版本管理要明确每次训练用的是哪一版数据。这四件事任何一件含糊后面复现实验就是噩梦。2.2 数据版本管理的最小可行方案很多人一听“数据版本管理”就想到上DVC或者Pachyderm其实起步阶段没必要那么重。我的做法是每次数据清洗产出一个parquet文件文件名带上日期和内容哈希比如train_20240512_a3f9.parquet同时在一个manifest.json里记录这次清洗用的脚本版本、输入文件列表、输出行数、字段列表。训练脚本启动时先读manifest把哈希写进实验记录。这样任何一次训练都能追溯到具体是哪份数据。这个方案土但管用。等数据量上来了、多人协作了再迁移到专业工具也不迟。关键是先有这个意识而不是等出了问题才补。2.3 特征处理里最容易埋雷的三个地方第一个是时间泄漏。比如你用“用户过去30天消费总额”做特征但计算这个特征的时候不小心把预测当天之后的数据也算进去了离线指标会好得离谱上线就崩。防的办法是所有时间窗口特征必须显式指定截止时间代码里加断言确保窗口右端点不超过样本时间。第二个是类别特征的编码一致性。训练时把类别映射成0到N的整数上线时来了一个训练集里没见过的新类别直接报错或者映射成-1。我的做法是预留一个unknown槽位所有未见类别都映射到它同时打日志记录方便后续补数据。第三个是数值特征的归一化参数。训练时算的均值和方差必须存下来上线时用同一套参数做变换。我见过有人上线时重新算了一遍归一化结果分布对不上模型输出全乱。这个参数要和模型文件一起版本化不能分开管理。2.4 数据质量监控要放在管道里不是放在人眼里数据管道跑起来之后不能靠人定期去看。要在管道里加检查点行数波动超过阈值告警、关键字段缺失率超过阈值告警、数值分布偏移超过阈值告警。这些检查用简单的统计量就能做不需要复杂的工具。我一般会在清洗脚本末尾加一段校验把结果写进日志异常时直接让管道失败而不是让脏数据流到训练环节。提示数据管道的失败要“响亮”宁可训练任务起不来也不要让脏数据静默通过。静默通过的数据问题排查成本是显式失败的十倍以上。3. 训练层把实验当工程做而不是当玄学调3.1 训练脚本的骨架应该长什么样一个能用于工程的训练脚本结构上必须包含这几段配置加载、数据加载、模型构建、训练循环、验证循环、检查点保存、指标记录。每一段都要能被单独替换而不是揉成一坨。我习惯用一个config.yaml管所有超参脚本里不出现任何硬编码的数字。这样换一组参数不用改代码实验对比也清晰。配置加载这块我强烈建议用dataclass或者pydantic做一层校验。你写learning_rate: 0.001字符串进去训练到一半才报错不如启动时就校验类型。这个习惯能省掉大量低级调试时间。3.2 随机种子这件事工程上必须较真研究里随机种子可能无所谓工程上不行。同一个配置跑两次结果不一样你就没法判断是改动生效了还是随机波动。我的做法是在脚本入口固定Python、NumPy、框架的随机种子同时把cudnn的确定性开关打开。这会牺牲一点速度但换来的是可复现。等你要对比两个方案的时候这点速度损失完全值得。还有一个细节数据加载的shuffle也要固定种子否则每个epoch的数据顺序不同指标波动会被误认为是模型问题。这个坑我在早期项目里踩过白白调了一周参数。3.3 检查点策略别只存最好的那个很多人只保存验证集指标最好的那个检查点这在实际工程里不够。你需要至少保存三类最新检查点用于断点续训、最佳检查点用于最终交付、定期快照用于回溯。最新检查点每个epoch覆盖最佳检查点按指标更新定期快照每N个epoch存一份带时间戳的。为什么要定期快照因为有时候最佳检查点是在过拟合之后才出现的你事后想回到中间某个状态做分析没有快照就回不去。存储成本不高但排查问题时价值很大。3.4 训练日志要结构化不要printprint(loss:, loss)这种日志人看还行机器没法分析。工程上要用结构化日志每条记录是一个JSON包含step、epoch、loss、lr、指标、耗时。这样你可以直接把日志导进分析工具画曲线也可以写脚本自动检测异常。我用过的方案里最轻量的是直接写JSONL文件每行一条不需要任何额外依赖。日志里还要记录环境信息代码版本、数据版本、依赖版本、硬件信息。出问题的时候这些信息能帮你快速定位是代码变了、数据变了还是环境变了。3.5 分布式训练什么时候该上我的建议是单卡能跑完一个epoch在可接受时间内就别上分布式。分布式带来的调试复杂度、通信开销、故障率在中小规模下完全不划算。等到单卡跑一个epoch要几个小时、且你已经把单卡性能压榨到极限了再考虑上多卡。上多卡的时候第一个要确认的是数据切分是否正确。我见过有人用了分布式但数据没切分每张卡都在跑全量数据等于白搭。第二个要确认的是梯度同步是否正常指标是否和单卡一致。这些验证做完再谈加速。4. 评估层指标好看不等于能用4.1 离线指标和业务指标之间的鸿沟模型训练完AUC 0.95看起来很漂亮。但业务方问的是这个模型能帮我减少多少人工审核量能提升多少转化率这两个问题离线指标回答不了。所以评估层要做的第一件事是把模型输出翻译成业务语言。我的做法是在评估阶段就引入业务侧的样本比如人工标注的一批真实case看模型在这些case上的表现。同时和业务方一起定义一个“可接受阈值”比如准确率低于多少就不能上线。这个阈值要在训练之前就定好而不是训练完再拍脑袋。4.2 评估集要分层不能只有一个总数一个总体的准确率数字掩盖的信息太多了。你需要按关键维度分层看新用户和老用户、高频和低频、不同地区、不同设备。某个分层上表现特别差上线后就会在那部分用户身上出问题。我一般会做一个分层评估表每个分层一行列出样本量、指标、置信区间。样本量太小的分层要标注出来避免过度解读。4.3 置信区间和显著性检验工程上也要看两个模型指标差0.5%是真的有提升还是随机波动这个问题不搞清楚你会把噪声当成改进。简单的做法是bootstrap重采样算置信区间如果两个模型的置信区间重叠那这个差异就不显著。这个计算不复杂几十行代码就能实现但能帮你避免很多无效迭代。4.4 评估要自动化不能靠人跑每次改完模型手动跑评估脚本迟早会漏。要把评估做成流水线的一环训练结束自动触发评估评估结果自动写入实验记录指标不达标自动标记。这样你打开实验管理界面一眼就能看到哪些实验达标、哪些不达标不用一个个去翻。5. 服务层把模型变成别人能用的东西5.1 模型服务的基本形态模型服务最朴素的形态就是一个HTTP接口收JSON请求返回JSON结果。但要做好要考虑的东西不少请求校验、批量推理、超时控制、并发限制、优雅降级。我见过太多服务因为没做请求校验收到脏数据直接崩掉因为没做超时控制一个慢请求拖垮整个服务。请求校验这块用pydantic定义请求体结构字段类型、范围、必填项都写清楚不合法直接返回400不要让它进到模型推理环节。批量推理这块如果单次请求量小但QPS高可以把短时间内的请求攒一批一起推理吞吐能提升好几倍。超时控制这块给推理设一个上限超了就返回降级结果不要让请求无限等待。5.2 模型版本切换怎么做才安全新模型上线不能直接替换。我的做法是新模型先以影子模式跑也就是线上流量同时打到新旧两个模型但只返回旧模型结果新模型结果只记录不返回。跑一段时间对比两者差异确认新模型没问题再切流量。切流量也要灰度先切1%观察指标再逐步放大。这个流程听起来麻烦但能避免“新模型上线导致线上事故”这种最坏情况。我经历过一次没做影子直接切结果新模型对某个特征的处理有bug线上错误率飙升回滚花了半小时。那半小时的损失比做影子模式多花的时间大得多。5.3 特征一致性线上线下必须对齐这是AI工程里最经典的坑离线训练用的特征和线上推理时算的特征对不上。原因可能是计算逻辑不同、数据源不同、时间窗口不同。防的办法是把特征计算逻辑抽成一个共享模块离线和线上都调这个模块。如果做不到共享至少要用同一批样本做一致性校验离线算一遍、线上算一遍对比差异。我一般会在上线前跑一个一致性测试取1000条线上真实请求分别用离线和线上管道算特征逐字段对比。差异超过阈值的字段要重点排查。这个测试能拦住大部分特征不一致问题。5.4 降级方案要在上线前就准备好模型服务不可能永远可用。依赖的数据源挂了、模型文件损坏了、流量突增打满了这些情况都要有应对。降级方案可以是返回默认值、走规则兜底、或者直接返回错误让上游处理。关键是这个方案要提前定好、提前测试而不是出事的时候临时想。6. 观测层出问题的时候能快速定位6.1 监控指标要覆盖哪些维度模型服务的监控至少要看四个维度延迟、吞吐、错误率、模型指标。延迟看P50、P95、P99不要只看平均平均值会掩盖长尾问题。吞吐看QPS和并发数。错误率要区分是请求错误还是推理错误。模型指标看输出分布是否偏移比如分类模型各类别占比是否和训练时一致。这四个维度任何一个异常都可能是问题的信号。我一般会设两级告警警告级和严重级。警告级发通知严重级直接打电话。阈值根据历史数据定不要拍脑袋。6.2 日志、指标、追踪三件套怎么落地日志记录离散事件指标记录连续数值追踪记录请求链路。三件套配合使用排查效率最高。日志用结构化格式指标用Prometheus这类工具采集追踪用OpenTelemetry这类标准。起步阶段不用全上但日志和指标是最低要求。我排查过一次线上问题模型输出突然变得很奇怪。看指标发现延迟正常、错误率正常但输出分布偏移了。看日志发现那段时间数据源换了格式某个字段从字符串变成了数字模型吃进去的特征变了。如果没有输出分布监控和结构化日志这个问题可能要查很久。6.3 模型漂移检测的简单做法模型漂移是指线上数据分布和训练数据分布逐渐偏离导致模型效果下降。检测方法不复杂定期拿线上最近一批样本算特征分布和训练分布的差异常用PSI或者KL散度。差异超过阈值就告警提示需要重新训练。这个检测要自动化按天或者按周跑。不要等业务方反馈效果变差了才去查那时候损失已经产生了。6.4 事故复盘要形成闭环每次线上问题解决后要写复盘问题现象、排查过程、根因、修复方案、预防措施。预防措施要落到具体的监控项或者流程改动上而不是一句“下次注意”。我见过太多复盘写完就归档同样的问题反复出现。复盘的价值在于把经验固化成系统能力而不是写一篇文档。7. 把这五层串起来一个最小可用的AI工程骨架7.1 目录结构建议project/ configs/ # 配置文件 data/ # 数据管道脚本 features/ # 特征计算共享模块 training/ # 训练脚本 evaluation/ # 评估脚本 serving/ # 服务代码 monitoring/ # 监控配置 experiments/ # 实验记录 manifests/ # 数据版本清单这个结构不复杂但每一块职责清晰。新人进来能快速找到对应代码不会所有东西堆在一个目录里。7.2 从零到跑通的最短路径第一步写数据清洗脚本产出带版本的数据文件。第二步写训练脚本能读数据、能训练、能存检查点、能记日志。第三步写评估脚本能算分层指标、能输出报告。第四步写服务代码能收请求、能推理、能返回结果。第五步加监控能看到延迟、错误率、输出分布。这五步走完你就有了一个最小可用的AI工程骨架。这个骨架不完美但能跑通完整链路。后续所有优化都是在这个骨架上迭代而不是推倒重来。我见过太多人想一步到位搭一个完美系统结果卡在某个环节迟迟跑不通最后不了了之。先跑通再优化这个顺序不能反。7.3 几个我踩过的坑你可以直接避开第一个坑过早引入复杂工具。一开始就上Kubernetes、上特征平台、上实验管理平台结果光配置环境就花了两周业务代码一行没写。我的建议是先用最朴素的方案跑通等遇到具体瓶颈了再引入对应工具。第二个坑忽略依赖管理。训练环境和服务环境依赖版本不一致导致模型加载失败。用requirements.txt或者poetry锁定版本训练和服务用同一套依赖。第三个坑不做端到端测试。数据管道、训练、评估、服务各自测试都通过串起来跑就报错。要有一个端到端的冒烟测试用少量数据跑完整链路确保各环节衔接正常。第四个坑文档缺失。系统搭完只有作者知道怎么跑作者一休假系统就没人敢动。关键流程要写文档配置项要写注释新人能照着文档跑通。注意AI工程的核心不是模型多先进而是系统多可靠。一个AUC 0.85但稳定运行的系统价值远大于一个AUC 0.95但三天两头出问题的系统。8. 关于迭代节奏和团队协作的一点个人体会搭这套东西的过程中我最大的体会是AI工程的迭代节奏和纯软件开发不一样。纯软件可以小步快跑每天发版。AI系统因为涉及数据、模型、服务多个环节每次改动的影响面更大需要更谨慎的验证。但也不能因此就几个月不发版那样业务方等不起。我的做法是数据管道和服务层的改动走常规发布流程模型更新走影子加灰度流程。两条线分开互不阻塞。数据管道改了不影响模型服务模型更新也不影响数据管道。这样既能保持迭代速度又能控制风险。团队协作上数据、训练、服务最好由不同的人负责但接口要定义清楚。数据产出什么格式、训练消费什么格式、服务需要什么输入这些契约要提前定好写成文档。接口定了之后各方可以并行开发不用互相等。还有一点实验记录要共享。谁跑了什么实验、用了什么配置、结果如何团队里所有人都能看到。这样避免重复劳动也能让好的经验快速传播。我用过最简单的方案就是一个共享的表格每次实验加一行。工具不重要重要的是有这个习惯。这套骨架我前后搭过三遍每一遍都比上一遍精简。第一遍什么都想上结果复杂度失控。第二遍砍掉一半还是觉得重。第三遍只保留最核心的五层反而跑得最顺。所以如果你刚开始搭我的建议是从最简版本开始遇到问题再加东西不要一开始就追求大而全。
返回列表