ARTICLE DETAIL

资讯详情

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

从零搭建AI工程体系:从训练到部署的完整实践指南

从零搭建AI工程体系:从训练到部署的完整实践指南 1. 这个标题到底在说什么很多人第一次看到ai-engineering-from-scratch这个项目名第一反应是又要学AI了然后可能就划走了。但我可以明确告诉你这个标题真正想表达的不是让你去啃Transformer源码也不是让你调个MNIST手写识别就算完事而是如何在没有任何现成AI基础设施的前提下一个人从零开始搭起一套能落地的AI工程体系。从我接触到的实际情况来看身边至少一半的人卡在了会用API和能做工程之间那条巨大的鸿沟里。你用OpenAI的接口写个聊天机器人那不算AI工程你在Colab里跑通一个扩散模型也不算AI工程。真正的AI工程是你把模型、数据、算力、推理服务、评测、监控、成本控制这些东西全部串成一条完整链路并且在生产环境里能稳定跑起来。这个项目值得关注的点在于它锁定的是from scratch这个视角。也就是说不依赖任何公司的内部平台、不假设你有现成的MLOps团队、甚至不默认你有GPU集群。你要解决的是最基础的问题环境怎么搭、数据怎么管、实验怎么跟踪、模型怎么部署、效果怎么评估、线上怎么观测。这些问题单独看都不难但把它们组合在一起并且一个人搞定就是另一回事了。如果你正在做AI应用开发或者你所在的团队连个正经的MLOps流程都没有又或者你就是想搞清楚一个AI项目从零到上线到底要走多少步那这篇内容会给你一条清晰得多的路径。我尽可能把每一步为什么要这样做、常见的坑在哪里都说清楚方便你直接照着做或者结合自己的场景去改。2. 项目结构设计与整体思路拆解2.1 从能跑的脚本到可维护的工程之间缺了什么先说我观察到的普遍现象。很多自学AI的人作品集里躺着一堆notebook每一个都能跑通每一个也都止步于能跑通。为什么因为notebook天然不适合做工程。你的数据读取路径是写死的模型参数是随手调的训练日志散落在输出单元格里至于推理接口、评估脚本、监控逻辑根本不存在。而完整的AI工程应该包含这样几层东西数据层数据采集、清洗、版本管理、实验层环境隔离、参数追踪、结果对比、服务层模型加载、推理接口、并发处理、评估层离线评测、回归测试、线上指标监控、运维层日志、告警、成本监控。这五层看起来复杂但你从零开始搭的时候每一步都有非常成熟的开源工具可以用难点不在于工具本身而在于知道什么时候该引入哪个工具。这个项目名里最关键的一个词是engineering它强调的不是算法创新而是工程化交付能力。一个模型哪怕效果再惊艳如果推理延迟波动大、并发一高就超时、出错时候没有日志可查那它在生产环境里就是不可用的。这就像一个厨师能做出米其林级别的菜但出餐速度忽快忽慢厨房流程一团糟餐厅照样开不下去。2.2 为什么从零开始意味着要从最小闭环做起我做这类项目时最忌讳的一件事就是一开始就想搭一个终极版的MLOps平台。Kubeflow、MLflow、Airflow、Feast这些工具全家桶一股脑全上最后光调试这些工具之间的配合就耗掉几周时间真正的模型工作一点没推进。所以我的核心思路是先跑通一个最小闭环再逐层加厚。最小闭环长这样——你有一个数据集一个训练脚本一个最简单的FastAPI推理服务然后你把服务跑起来发一个请求拿到结果。就这么简单。全程你只需要一台能联网的电脑甚至不需要GPU。为什么一定要从最小闭环开始因为AI工程的特殊性在于它的瓶颈往往不在单个环节而在环节之间的衔接处。你训练脚本里数据预处理的逻辑跟推理服务里数据预处理的逻辑是不是一致训练时长尾样本的分布跟线上实际请求的分布是不是一致这些衔接问题不跑通一次全流程是根本暴露不出来的。跑通最小闭环之后再逐层扩展给数据加上版本号给实验加上参数记录给推理服务加上并发和超时控制给评估脚本加上自动化回归。每一步扩展都是独立的出了问题也容易定位。这种先通后优的做法是我在所有工程实践里验证过无数次的节奏。3. 环境准备与工具链选型3.1 硬性基础Python环境管理到底该怎么搞不管你用什么框架Python环境永远是第一道坎。我见过太多人因为环境冲突浪费掉整整一天。这里我直接给你一套我自己用下来最省心的方案。首先抛弃直接把依赖装进全局环境的做法。不管你是用conda还是venv都建议给每一个项目建独立环境。我当前用的组合是pyenv管Python版本 uv管虚拟环境和依赖。uv是目前解析依赖速度最快的工具可以平替pip而且它能生成锁文件确保你在三个月后重装项目时依赖版本跟现在完全一致。具体操作简单说一下。装好pyenv之后一条命令就能装指定版本的Pythonpyenv install 3.11.8然后在项目目录里初始化虚拟环境并用uv装依赖uv venv uv pip install -r requirements.txt这里有个容易被忽略的细节requirements.txt里面一定要锁死传递依赖的版本而不是只锁直接依赖。为什么因为很多底层库的版本号是互相牵制的比如numpy和torch之间就有严格的版本匹配关系。你不锁传递依赖今天装出来的环境和三个月后装出来的环境可能完全是两个世界到时候排查问题你会排查到怀疑人生。3.2 模型训练的最小硬件方案与框架选择对于from scratch这个定位我不建议一开始就上多卡分布式训练。单张消费级显卡完全够用。你如果是做NLP一张24GB显存的卡可以跑大多数开源模型的全参数微调比如7B级别的模型用LoRA方式或者13B以上模型用QLoRA。你如果是做CV一张卡做分类、检测、分割的数据集实验也绰绰有余。框架选择上我推荐直接学PyTorch不要绕道。为什么因为现在整个开源生态基本都围绕PyTorch展开HuggingFace的transformers、diffusers、Peft以及各种推理框架全部默认支持PyTorch。你实在遇到底层算子需要优化的时候PyTorch的社区和海量教程也能帮你更快找到答案。顺便提一下依赖安装的一个坑。如果你的机器有NVIDIA显卡装PyTorch的时候千万别直接用默认的PyPI源它会给你装CPU版本白白浪费你的显卡。要这样装uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121cu121代表CUDA 12.1版本你得先看下自己显卡驱动的CUDA版本用nvidia-smi查右上角就有。装错版本也不会报错但训练速度会慢到让你怀疑人生而且这种问题特别隐蔽很多人排查了很久都没想明白为什么自己的GPU利用率是0%。3.3 数据管理一开始就想到版本问题很多人做项目时数据管理是最被忽视的环节。文件夹里躺着data_final_v2.csv、data_final_v3.csv、data_final_v3_real.csv这种奇葩命名过了一周自己都分不清哪个是哪个。这里我不推荐一上来就上DVC这类重量级工具因为它需要配置远程存储对个人项目来说有点杀鸡用牛刀。我的建议是养成两个习惯就好第一数据文件用日期或版本号命名比如news_20250401.parquet第二在实验记录里写下你用的是哪个版本的数据。做到这两点你至少规避掉80%由数据混乱引发的问题。如果你的项目数据量开始变大超过几个GB建议把数据从CSV换成Parquet格式。Parquet是列式存储读写速度比CSV快好几个数量级而且天然支持压缩同样是100万行数据Parquet文件可能只有CSV的三分之一大小。4. 模型训练的工程化改造4.1 训练脚本应该拆成哪几个模块还是那句话不要写一个几千行的单文件训练脚本。单文件写到后面改一个参数都像在拆炸弹。我更推荐的目录结构是这样的src/ ├── data.py # 数据集加载与预处理 ├── model.py # 模型定义 ├── train.py # 训练主循环 ├── evaluate.py # 评估逻辑 └── config.yaml # 所有超参数这样拆的好处是每个模块的职责单一改数据逻辑不会影响模型结构调参也不会动到训练代码。特别是config.yaml用YAML而不是命令行参数管超参数最大的优势是可复现。你跑完一个实验配置文件就是一份完整的记录里面包含了学习率、批次大小、epoch数、模型参数等所有关键信息。命令行参数太容易漏记了可能你跑完实验就忘了当时用了什么学习率。4.2 训练过程怎么盯损失曲线和日志是关键训练模型时如果只看终端打印的loss数值你会错过很多关键信息。我的习惯是至少盯三样东西训练损失曲线、验证损失曲线、学习率变化。损失曲线能告诉你很多信息。训练损失持续下降、验证损失也下降说明训练正常训练损失下降但验证损失开始上升说明过拟合两个都不降可能是学习率设置不对也可能是数据预处理有问题。这些判断必须靠可视化曲线才能快速察觉只看数字列表你根本看不出来趋势。可视化工具我用的是TensorBoard或者WandB个人项目我反而推荐TensorBoard因为它完全本地运行、不需要注册账号一条命令就能启动tensorboard --logdir./runs在训练脚本里只需要增加几行代码即可记录from torch.utils.tensorboard import SummaryWriter writer SummaryWriter(log_dirf./runs/experiment_v1) for step, batch in enumerate(train_loader): loss train_one_step(batch) writer.add_scalar(train/loss, loss, step)4.3 第一次全参数微调与LoRA我推荐先学哪个如果你要微调大语言模型我强烈建议第一个项目就跑一遍LoRA低秩微调。为什么因为全参数微调不仅显存开销大而且对数据量和调参技巧要求都很高。一个很小的学习率设置失误就可能导致模型灾难性遗忘把原本的通用能力毁掉。LoRA的做法是冻结原始模型的全部参数只训练额外加入的低秩适配器。这就像在原来的神经网络边上插了几个小插件训练成本大幅降低效果很多时候跟全参数微调差不了太多。代码上用HuggingFace的Peft库十几行就能搞定from peft import LoraConfig, get_peft_model lora_config LoraConfig( r8, lora_alpha16, lora_dropout0.1, biasnone, task_typeCAUSAL_LM ) model get_peft_model(model, lora_config)这里r8是低秩矩阵的维度lora_alpha16是缩放系数这两个参数的比值大概决定了LoRA在最终模型中的影响权重。我的经验是r设8起步效果不够再加到16、32但r过大会增加过拟合风险而且推理时还是会有一点额外开销。微调完成后你保存的模型文件比原始模型小了好几个数量级一个7B模型的LoRA权重往往才几十MB这在工程交付上非常友好。5. 推理服务的构建与部署5.1 FastAPI是纯推理服务的最佳起点模型训练完它还是一个静态的产物你得把它变成能对外提供服务的东西才算是真正完成了工程这一步。这就像你做了一道菜放在后厨没人看得到必须端到餐桌上客人才能吃。我推荐用FastAPI来做推理服务的骨架它是目前Python生态里性能最好、开发体验最舒服的Web框架原生支持异步和自动生成API文档。一个最基础的模型推理服务大概长这样from fastapi import FastAPI, HTTPException from pydantic import BaseModel app FastAPI() class PredictRequest(BaseModel): text: str class PredictResponse(BaseModel): label: str confidence: float app.post(/predict) async def predict(req: PredictRequest): # 这里调用模型推理 label, confidence inference(req.text) return PredictResponse(labellabel, confidenceconfidence)注意一点模型在服务启动时加载一次之后所有请求共享同一份模型实例千万不要在每次请求时重新加载模型那会直接把服务拖垮。5.2 推理服务的并发与延迟到底怎么调很多人写完推理服务本地测试一两个请求觉得挺快就以为完事了。结果一上生产环境并发量稍微上来延迟直接飙升到不可接受。核心原因是他们没有理解并发模型的差异。FastAPI本身是异步框架但如果你的模型推理是同步的比如PyTorch的model(input)默认就是同步操作那么请求实际上是排队处理的。异步框架只能帮你避免I/O等待比如等待数据库查询、等待下游API返回但它不能让一个死循环或一个GPU推理并行执行。要让服务真正支持并发推理你有几条路可以走。最简单的是给服务挂上多个worker进程用uvicorn启动时可以指定uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4每个worker进程是独立的承载着同一个模型的独立副本这能充分利用多核CPU或者多块GPU。但要注意多个worker意味着显存占用翻倍你得算清楚显存能不能扛得住。另一个思路是引入消息队列把推理请求先丢进队列由单独的后台消费者进程去消费并调用GPU推理这适合推理耗时长、无法靠增加worker解决的场景。5.3 服务上线前必须要测的几个指标我这里给你一份我自己项目里一定会跑的测试清单单请求延迟P99注意不是平均延迟P99意味着最差的那1%请求的表现平均延迟再好看也掩盖不了长尾问题。并发压力测试用locust或wrk模拟并发用户观察TPS峰值、延迟拐点出现在多少并发。错误率压测时统计5xx和超时请求的比例系统要在高负载下仍然保持低错误率。显存和内存占用持续请求一段时间后观察资源占用是否稳定有没有内存泄漏。这些测试的核心目的是找到系统的真实瓶颈。很多时候瓶颈不在模型本身而在数据预处理、序列化、网络传输这些外围环节。把这些瓶颈提前测出来比上线后收到告警再救火要省心得多。6. 评估体系的搭建让模型效果可证明6.1 一张静态的测试集和一套评估流水线是两码事模型训练完了随便跑几个测试样本看效果觉得看起来还行这不能叫评估。真正的评估体系是一套可重复运行的流水线它能在每一次模型更新、每个候选模型之间给出可量化的对比结论。最小可用版本的评估流水线应该包含一个固定的测试集、一组统一的评测指标、一段自动跑评测的脚本。测试集要尽早从训练集里分出来而且可以故意往里面放一些典型的困难样本比如用户最有可能遇到的极端情况。以后每次训练出新模型只需要跑一遍评测脚本就能得到一组指标用来跟历史版本做对比。我建议把评估脚本固化到项目的根目录比如命名成eval.py跟train.py平级。因为评估不是一次性工作你后续每迭代一版模型都要跑一遍它。把它当成项目的一等公民来对待而不是临时写个脚本用完就扔。6.2 离线指标与线上表现之间为什么会存在鸿沟很多人会困惑一个问题离线测试分数看起来很高为什么一上线上用户的反馈还是不行这里要理解离线指标与线上真实表现之间天然存在偏差。原因也不复杂。离线测试集是从历史数据中抽样出来的它反映的是过去而线上请求代表的是未来。用户的需求在不断变化测试集却是一个固定的快照。另外离线评测往往只看单一维度指标比如准确率但线上用户感知到的是完整的交互体验包括响应速度、输出格式是否符合预期、极端输入时的容错表现等。我个人的做法是两套指标并行离线跑标准分线上再做抽样人工抽检。抽检时不要只看模型回答得正确与否还要看答案的可读性、安全性、稳定性以及面对不同表达方式的同一问题时是否会出现答案矛盾。这些维度很难用自动化指标涵盖但它们在工程交付中的重要性往往不低于准确率。7. 运维与调优的实操复盘7.1 推理日志里该记哪些字段我在运营AI服务时踩过最大的一次坑是线上用户反馈服务异常但日志里什么都查不到因为当时只打了请求来了和请求处理完两条log完全不够定位问题。后来我把日志字段标准化形成了一套固定模板请求ID每次请求生成唯一ID方便串联上下游日志模型版本号当前服务加载的是哪个版本模型输入大小与摘要比如文本长度、图片分辨率推理耗时毫秒级返回状态成功、超时、还是抛异常异常堆栈出错时的完整追溯信息这套日志模板的威力在于它让你有能力做回溯排查。当线上出问题时你能从一条日志串起整个过程快速定位是模型推理慢、还是上游数据传输出问题、还是服务被杀导致请求丢失。7.2 成本监控token用量是一笔隐形开销如果你用的是付费API或者自己托管大模型成本监控就不能忽略。很多人在开发阶段完全不管token消耗上线之后看着账单才知道心疼。但实际上成本控制应该从设计阶段就开始。一个简单的做法给服务的日志加上prompt_tokens和completion_tokens字段每天统计一次总消耗和人均消耗。这样你能直观看到哪些功能接口在吞噬预算然后决定是优化prompt、减少冗余字数还是把调用频率降下来。另外模型输入长度要设置上限防止用户发超长文本把你的budget一次性烧光。7.3 上线后性能变慢最常见的三个原因服务部署完之后性能不能一劳永逸。我遇到过几次昨晚还挺好但今天突然变慢的情况排查完基本是下面这几种原因第一个原因是模型更新没有做AB对比。新模型可能效果更好但在推理耗时上却明显增加了如果你没有做AB测试用户就会不知不觉地享受到更慢的服务。第二个原因是并发用户自然增长。服务刚上线时一天只有几百请求跑得很轻松上线一个月后日均请求破万之前压测时掩盖的瓶颈就会集中爆发。第三个原因是日志和监控拖慢了主流程。日志写文件、指标上报这些操作如果在主线程里同步执行在高并发下会显著增加请求延迟。解决方法是把这些旁路操作改成异步或者单独丢到后台线程处理。8. 新人最容易掉进去的十个坑一路看下来你会发现AI工程核心其实就这几件事环境、数据、训练、部署、评估、监控。但每一项都有新手容易踩的坑我这里整理一份速查表给你可以收藏着慢慢看。问题领域典型问题我的建议环境搭建依赖版本冲突导致无法复现用uv锁文件锁定全部依赖版本数据管理训练/评估数据混用训练集、验证集、测试集严格分离数据预处理训练与推理时的预处理逻辑不一致把预处理逻辑封装成同一个函数训练监控只盯着loss数值不看曲线用TensorBoard/WandB可视化训练过程模型保存只保存最终模型不保存配置文件配置文件与模型权重同时存档推理服务每个请求都重新加载模型服务启动时一次性加载模型到内存并发处理没压测就上线用locust做至少100并发持续测试评估体系只看离线指标不看线上反馈离线指标抽样人工质检双轨并行日志规范日志信息不足无法排查固定请求ID、模型版本、耗时等字段成本控制上线后才发现token消耗巨大日志记录token用量设立成本告警9. 实际动手路线一周搭建一个完整的AI服务如果你看完前面这些内容心里大概有了概念但不知道从哪里开始。我直接给你一个七天路线图照着走一遍你就拥有一个端到端的AI工程样板。第1天搭环境装好Python、PyTorch、FastAPI跑通一个最简单的模型训练demo确保GPU可用。第2天准备一份小型数据集并划分好训练/测试集写数据加载和预处理代码做一次完整训练记录损失曲线。第3天学习LoRA微调在一个开源小模型上完成微调保存LoRA权重和配置文件。第4天用FastAPI搭建推理服务加载微调后的模型写好可预测的API接口本地联调通过。第5天做压测用并发工具模拟至少100路请求记录延迟分布和错误率。第6天搭建自动化评估脚本把测试集过一遍输出量化指标。第7天完善日志、添加基本监控告警写下项目README和部署文档总结踩过的坑和解决方案。七天走下来你获得的不是一个玩具项目而是一套完整的、可扩展的AI服务工程框架。之后的迭代都是在这个骨架上增减模块而已。我个人在实际操作中的体会是AI工程最大的门槛从来不是某个具体的技术点而是全局视角——你要能在头脑里同时装着链路中的每一个环节并且理解它们之间的相互影响。这需要时间和实践积累但一旦你完整地从头到尾做过一次这套能力就会非常牢固地长在你身上。
返回列表