news 2026/10/1 11:49:53

从零开始学AI工程:环境搭建到部署监控的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零开始学AI工程:环境搭建到部署监控的完整实践

做AI工程这一年多,我把市面上能踩的坑基本都踩了一遍。从最开始只会调包跑模型,到最后能独立把一套应用端到端落地,中间没有哪一步是可以跳过去的。今天就拿我自己的学习路线当例子,聊聊一个完全没有工程背景的人,是怎么从零开始把AI工程这条线啃下来的。

我默认你会Python基础,但没做过真正的工程化项目。这篇内容会带你拆解AI工程到底是什么、为什么不能直接上手框架就完事、环境怎么搭、数据怎么管、训练和推理怎么权衡、上线之后怎么监控。每一个环节我都配了实际操作和参数选择逻辑,你可以照着跑一遍,也可以只挑自己缺的部分看。

1. AI工程到底是什么,它和调模型是两码事

1.1 解决的不是"能不能跑",而是"能不能一直跑"

很多人对AI工程有个误解,觉得学会用transformers加载一个预训练模型,能出结果就算入门了。但真的入职或者做项目之后你会发现,能跑通一个demo和能支撑一个产品是两回事。AI工程的核心不是模型本身,而是围绕模型构建的一整套系统:数据怎么流转、训练资源怎么调配、推理服务怎么保证延迟和吞吐、效果怎么持续评估、出问题了怎么排查。我经常打的一个比方是:算法研究像做一道拿手菜,AI工程像开一家餐厅。菜谱可以固定,但餐厅要解决供应链、后厨动线、出餐速度、食品安全、顾客反馈,任何一个环节断了,店就开不下去。

从scratch学AI工程,其实就是先别急着碰高端框架,而是先把"餐厅运营"这些基础能力补上。你不需要从底层矩阵乘法手写一遍,但你需要知道数据从哪来、模型怎么训练、推理怎么部署、线上怎么评估,这几件事的先后顺序和依赖关系。

1.2 适合谁看,看完能得到什么

这套内容适合几类人:刚入行想做AI应用开发的同学,在算法岗想往工程方向转的工程师,以及团队里需要一个人把模型落地成服务的全栈型角色。看完之后你至少能回答这几个问题:训练环境和推理环境为什么必须分开、数据版本管理解决什么痛点、Flask/FastAPI部署和真正的推理服务差在哪、为什么上线之后准确率会变、日志和追踪到底记录什么。

我不会给你很多劝退压力,但有一点提前说清楚:AI工程的知识点很碎,涉及容器、网络、存储、模型、前后端多个领域,靠看文章是看不完的。最好的方式是搭一个最小闭环,比如本地把一个模型封装成服务,再接入监控,之后每一步都在这条链路上加东西。我踩过的大多数坑,都是在真实链路里暴露出来的,光看文档根本发现不了。

2. 从零起步:先把开发环境和依赖管理理清楚

2.1 为什么第一步是虚拟环境,不是选框架

我知道很多人会急着选PyTorch还是TensorFlow,或者纠结用LangChain还是直接用原生接口。但以我实际带人的经验,第一步应该解决的是环境隔离。AI项目依赖极其容易冲突,你手上同时有好几个项目,一个要numpy1.x,一个要numpy2.x,不隔离开几分钟就崩。我一开始图省事,把所有包都装在全局,结果某天升级了一个库,另一个项目的推理结果静默变了,排查了两天才发现是版本冲突。

所以在任何项目动工前,先建虚拟环境。我个人习惯用conda管理Python版本和底层库,再用venv做项目级隔离。conda的好处在于能处理一些非Python的系统依赖(比如cuda相关的包),venv轻量、跟项目走更干净。新建环境时顺手把Python版本定死,不要用默认的,AI场景建议3.10或3.11,太老的新库不支持,太新的有些算子还没编译好。

2.2 依赖锁定的实操细节

环境建好之后,第一件事不是pip install越大而全越好,而是需要的时候再装。但有一个例外——先把requirements.txt或pyproject.toml约定好。你每装一个包,都要把它记录进去。我见过太多项目,代码能跑,但你问他是哪几个版本,说不清。等到换机器部署,跑不起来才开始赌版本,极其痛苦。

好一点的实践是用pip-tools或uv这类工具做依赖锁定。pip freeze虽然直接,但会把所有传递依赖都锁进去,升级一个包动不动牵连一片。用pip-compile的话,你只需要维护requirements.in里直接依赖的版本上限,它自动把完整的锁定关系编译出来。比如你定义了transformers>=4.40,它会依据当前的解析结果锁定到具体某个4.4x版本,并且连带锁住tokenizers、safetensors这些子依赖。这样项目在任何机器上重建环境,行为都是一致的。

2.3 CUDA和GPU环境的判断

做AI工程早晚要碰GPU。如果你本机没有NVIDIA显卡或显存不够(我见过8G显存跑7B模型直接爆的),不要硬刚,直接用云GPU实例或者Colab先练手。问题在于,GPU环境最大的坑是驱动、CUDA、PyTorch三者的版本匹配。你看着PyTorch官网一条命令装上去了,但不能用,多半是CUDA版本没对上。

快速检查办法:先跑nvidia-smi看驱动的Driver版本和支持的最高CUDA版本,再跑python -c "import torch; print(torch.version.cuda)"看PyTorch实际编译用的CUDA版本,两者不需要完全一致,PyTorch自带的CUDA runtime可以低于驱动支持的最高版本,但不能反过来。我踩过一次是驱动太老,PyTorch编译的是CUDA 12.1,结果所有模型加载都报"sm_90 not compatible",老老实实退了驱动才解决。新手别去折腾源码编译CUDA算子,先保证官方wheel能跑起来,比什么都重要。

3. 数据先行:没有干净的数据,模型就是空中楼阁

3.1 数据链路设计,比模型选型更优先

项目里最容易犯的错是一上来就微调模型,数据用临时脚本随便处理一下。我不止一次因为数据问题返工:训练时loss降得很好,一上真实场景效果稀烂。后来复盘发现是训练集分布和线上分布严重不一致,比如训练数据里用户输入都是规规矩矩的句子,但线上用户输入全是口语和错别字。

AI工程里的数据处理,核心是建立一条可回放、可追踪的链路。原始数据、清洗脚本、清洗后数据、样本切分、增强策略,每一环都要能追溯。我会在项目开始就定义一个数据目录结构,raw、interim、processed分别放原始、中间、最终的数据,再配一个DATA_README.md记录每份数据的来源、采集时间、清洗规则。听起来像文档功夫,但在你调试模型效果异常的时候,能省下大量时间。

3.2 数据版本管理怎么落地

数据集和代码一样需要版本管理,但Git对大文件不友好。我试过几种方案:DVC最常用,它不直接存数据,而是存数据的元信息和远程存储地址,用的时候拉取对应版本。如果你的团队用云对象存储,DVC配S3或者OSS很顺。另一个更轻量的办法是按日期加commit hash给数据目录命名,比如data_20250112_a3f2c1,配合一个映射表记录每个数据版本对应的代码版本。这个方法没有额外工具成本,但需要团队自律,我小项目一般用这个,大到多人协作我才会引入DVC。

清洗和增强要注意一个原则:每一步都要可逆或至少可对比。不要在图省事的心态下直接把整份数据覆盖,哪怕你心里认为清洗逻辑肯定不会错。我用过一个sentencepiece做中文分词,运行时报OOV,排查了两小时发现是之前的清洗脚本把部分标点转成了全角,分词器词表里只有半角标点。这种问题只有保留中间产物才能快速定位。

3.3 样本切分和评估集的学问

很多教程会告诉你训练集、验证集、测试集七二一切分,但在真实AI工程里,更关键的是时间切分和分布切分。如果你的数据是按时间顺序产生的(比如日志、用户行为),乱序随机切分会让模型偷偷看到"未来"的数据,线下指标虚高,上线就现原形。我处理这类数据时,严格按时间切窗口:前70%训练,中间15%验证,最后15%测试。如果数据来自多个渠道或场景,还要保证每个场景在三个集合里都有代表,防止模型只在某类数据上有效。

另外,测试集和验证集不要用同一份,也不要让它们在清洗、增强期间被模型以任何形式看到。听起来是常识,但实际操作中因为复用处理脚本导致测试集泄漏的情况我见过太多。泄漏的直接后果是线上评估完全失真,你自信满满地上线,然后用户告诉你效果很差。

4. 模型训练:效果和容错的平衡

4.1 从预训练模型出发的微调管线

纯从零训练一个大模型的成本不是个人能承担的,现在讲from scratch,更多指把自己的工程链路从零搭起来,而不是从随机权重开始训。我用得最多的路径是拿开源底座模型(比如Qwen、Llama的指令版本)做微调。微调前先确认三件事:基座许可证允许商用、中文能力满足场景基础要求、显存或预算能支撑推理和训练的最低配置。

微调工具有很多,很多新手一上来就上全量微调,折腾LoRA的时候又觉得效果不够好。我的建议是:小规模数据(几千条)先试LoRA或QLoRA,这样显存占用低、训练快,而且不容易灾难性遗忘。如果你有几十万条高质量数据,并且算力充足,再考虑全量微调。LoRA的关键参数是秩(rank),我一般从8开始尝试,在验证集上对比效果,如果欠拟合再往上加到16或32,并不建议一开始就追求高秩,那是拿稳定性换表达力。

4.2 训练脚本里的关键设置

训练过程中最容易被忽略的是随机种子和梯度累积步数。固定种子(比如42)是为了实验结果可复现,虽然GPU算子有一些不确定性,但至少能把变化控制在可理解范围内。梯度累积是为了弥补batch size太小的问题,比如你想模拟batch size为32的效果,但显存只够8,那就累积4步再更新一次参数。这个参数直接影响训练稳定性,别把梯度累积和batch size之间的关系搞错——累积步数等于等效batch size除以单步batch size。

另外,不管用什么框架,训练日志必须包含每一轮的loss、学习率、显存占用和吞吐量。我习惯把日志直接输出成结构化的JSON行,每一行记录step、loss、lr、gpu_mem_mb、tokens_per_sec等字段。后续无论是画曲线还是定位某一步崩溃,都有据可查。别只print,print的信息分散且难以二次分析。

4.3 训练中途崩了怎么办

AI训练崩溃非常常见,最常见的几种:显存不够、数据加载异常、loss变成NaN。显存不够就调小batch size或开梯度累积。loss变NaN先检查学习率是不是太高,其次检查数据里有没有无穷值或缺失值,特别是做文本特征时某些字段为空没处理干净,会导致embedding结果异常。我遇到过一次很有意思的崩溃:不是训练代码的问题,是数据量太大把磁盘写满了,checkpoint保存失败后继续训练,模型输出全乱。后来我在训练脚本里加了磁盘余量检测,低于阈值提前终止并告警,这类问题就再也没遇到过。

5. 推理与部署:把模型变成真正的服务

5.1 FastAPI封装和性能参数选择

模型训练好之后,下一步是部署。最基础的方案是FastAPI写一个HTTP接口,内部加载模型,接请求、跑推理、返回结果。单机demo这么玩没问题,但如果你想上生产,有几个细节必须调整。

首先是模型加载方式。默认情况下每次启动都会从磁盘加载模型,几百MB到几个GB的权重,加载一次可能几十秒。生产环境建议用内存或共享缓存方式预热,进程启动后立即加载模型,而不是首个请求来了才加载。其次是并发控制,GPU推理时显存是共享的,来的请求太多同时跑会互相挤占。最简单有效的方式是设置一个信号量或队列,控制同一时刻推理的并发数。我一般按显存余量动态算上限,比如单卡24G,模型本身占用14G,每个请求峰值约4G,那上限就是2个并发,留一点余量。

5.2 流式输出和长文本请求的处理

如果做的是对话或生成类应用,流式输出几乎是刚需。客户端希望看到字一个一个蹦出来,而不是等十几秒拿到整段。FastAPI可以用StreamingResponse,内部把模型的token逐个yield出去。这里有一个隐藏问题:如果生成过程很长,客户端的连接很可能断开,接口层要能感知并停止生成,否则后台一直在跑无效推理。

处理长文本请求时,输入长度受模型上下文窗口限制。超长输入要么截断,要么做滑动窗口或摘要压缩。截断策略也有讲究,不要只截尾部,很多关键信息在中间或结尾。我一般会把文本按结构分段,头尾保留、中间用抽取式摘要压缩,再拼接成可接受的长度。这个策略比粗暴截断在真实效果上强不少。

5.3 Docker镜像打包和依赖瘦身

部署环节里,Docker是绕不开的。一个典型的问题是镜像体积过大,基础镜像+Python+CUDA库+模型依赖,动辄四五个GB。体积大不仅占磁盘,拉取和启动也慢。我的经验是分阶段构建:第一阶段装完整依赖和编译工具,第二阶段只拷贝编译好的包和代码。另外,优先使用官方精简镜像,比如python:3.11-slim作为基础层,CUDA相关的库如果推理时不需要就不装。还有一个容易忽视的点——镜像内不要打包模型权重文件,模型体积动不动几个GB,应该通过挂载外部存储或初始化容器专门下载。这样代码版本更新时不用重新拉几个GB的镜像。

6. 上线前的效果评估与回归测试

6.1 评估集、人工评测和线上AB

模型在测试集上指标好看,不代表线上就能直接上。我的习惯是至少做三层评估:第一层是自动化指标(BLEU、ROUGE、准确率等),快速判断有没有崩;第二层是人工评测,随机抽几百条真实输入,按多个维度打分,判断体验是否达标;第三层是灰度上线后做AB对比,把小流量切到新模型上,和旧版本比线上指标和用户反馈。

人工评测模板是我从几个项目里迭代出来的。每条样本至少标注:回答是否相关、是否流畅、是否有有害内容、是否遵从指令。用打分制(1到5分),不直接用"好/坏",因为两边模型差异很细微时,二值标注根本看不出差别。同时标注人不要只看模型答案,也要看参考答案和输入上下文,没有上下文的人工标注等于是在评判幻觉。

6.2 防止静默回归——回归测试集的重要性

AI模型每次更新,最怕的是"东边修好西边坏"。老版本能答对的问题,新版本突然答错了,而且自动化指标整体还是涨的,因为可能新版本在另一类问题上变得更强,把平均值拉高了。这时候你需要一个固定的回归测试集,里面包含历史上出过问题的样本、边界样本和典型用户输入。每次更新模型或改prompt,先跑一遍回归测试集,和上一次结果做diff。如果回归测试集里出现明显的badcase,就要谨慎评估是否上线。

我维护回归测试集的方式很简单但有效:每次线上出现badcase,我都会把它追加到回归集里,并写一行说明这个case是哪个版本、哪个场景暴露的。半年下来回归集可能就几百条,但它承载了你对模型的所有历史认知,比任何花哨的评估框架都实用。

7. 观测与监控:上线只是开始

7.1 日志里要埋哪些关键信息

AI服务上线后,最容易出的问题是"线上效果和预期不符",但你又不知道是哪一环出的问题。模型输入被改了吗?前处理逻辑变了吗?请求数据分布变了吗?要回答这些问题,日志必须记录下来。我的最低标准是:每条推理请求都记下输入原文、输出结果、模型版本、prompt版本、耗时、token用量、输入长度、输出长度。不需要全量存,但至少按比例采样(比如10%)配合全量错误日志,才能在事后做归因。

日志推荐直接输出为JSON格式,每个字段名固定,打点统一到同一个Logger里。这样后面接日志采集甚至搭建简单的检索分析系统时,成本都很低。另一个细节是加trace_id,每次请求生成一个唯一ID,前后端联调时直接拿这个ID查全链路日志,省去各种"你那边报了什么错"的扯皮。

7.2 指标监控和告警阈值怎么定

监控不仅看服务器资源(CPU、内存、显存),更要看业务指标。生成类服务至少应该盯这几个:请求量、P95/P99延迟、token输出速率、错误率、队列积压量、平均输出长度。延迟和输出长度强相关,所以只看P95延迟不全面,最好同时看每token延迟。如果P99延迟突然飙高,通常不是模型本身变慢,而是并发排队或GPU利用率打满。

告警阈值不要拍脑袋,要根据历史基线定。比如过去两周的平均错误率是0.5%,方差很小,那阈值设在1%或2%就合理。如果阈值设得太紧,比如比基线低一半,你会被大量误报骚扰到无感,最后真出了问题反而不看了。我知道做告警很容易犯完美主义,但告警的价值是让值班的人在人少的时间段快速决策,宁可少而精,不要多而烂。

7.3 长尾问题的排查套路

线上效果差,最经典的排查路径是:先确认输入和线上日志里记录的输入是否一致,再确认模型版本是否和预期一致,接着看有没有前处理或后处理的逻辑改动,最后再怀疑数据漂移。很多"模型突然变蠢"的案例,最终定位到的是上游字段格式变化,模型本身没动。

如果遇到单个样本输出异常,先手动复现:拿日志里的原始输入,在本地跑同一个模型、同一个prompt,看是否还异常。本地不异常,说明是运行环境或请求链路问题;本地也异常,那就是模型或prompt问题。这套排查思路非常朴素,但异常高效。我见过很多人在线上debug半天,却忘了先在本地把样本复现一遍。

8. 常见问题速查:我踩过的那些坑

问题现象可能原因排查与解决
训练loss下降但验证集效果差数据泄漏、分布不一致检查切分是否乱序、清洗过程是否混入未来信息
模型上线后效果明显变差线上输入分布漂移、前处理差异对比线上日志与训练集分布,逐段检查链路
推理延迟突然飙升GPU排队、显存不足、日志IO阻塞看P99与队列长度,检查并发上限设置
容器启动后模型加载失败内存不足、权重路径错误、版本不匹配检查启动日志和挂载路径,先本机验证一次
生成内容频繁重复解码参数温度太低或频率惩罚不足调高温度、添加重复惩罚,观察输出多样性
多卡训练时速度上不去数据加载成为瓶颈、通信开销大开pin_memory和num_workers,检查数据预取
中文输入乱码或分词异常编码不一致、词表缺失统一UTF-8,检查预处理是否规范化

这类问题其实都有一个共同规律:先怀疑自己的系统,不要一上来就怪模型。模型通常不会"无缘无故"变差,变差大概率是有条件变化了,而条件变化的痕迹一定藏在日志里。

还有一条避坑经验我想单独说:写代码时多做防御性检查,不要假设数据永远是干净的。用户的输入可能包含不可见字符、超长文本、纯标点,模型服务对这些情况的处理方式应该明确,要么安全拒绝,要么走兜底逻辑,千万不要让它带着异常输入硬算。我见过一次线上事故,就是用户输入是一串特殊Unicode字符,前处理没拦住,导致推理进程OOM,整台机器上的服务雪崩。宁可代码啰嗦一点,也要把健壮性放在第一位。

9. 继续往前:这个项目还能怎么扩展

从零搭完这一整套AI工程链路之后,你手里其实已经握着一个可复用的"脚手架"。后续扩展的方向很多,我大致梳理三条线。

一是性能优化线。当前的推理服务能用,但吞吐和成本还有优化空间。可以从模型量化入手(如INT8、INT4),或者尝试vLLM这类高吞吐推理框架。改动带来的收益是实打实的:同样一张卡,吞吐可能提升一到两倍。但注意,量化后效果可能小幅下降,上之前要用回归测试集过一遍,不能只看跑分。

二是数据闭环线。把线上真实反馈回流到数据管理和模型迭代流程里。比如做一个用户反馈打标的小工具,把badcase标记后自动追加到回归测试集,再定期触发新一轮微调或训练。这个闭环一旦跑起来,你的模型会越用越贴合真实场景,而不是停留在开发时的人工数据集里。

三是多模型协作线。单一通用模型做不了所有事。更合理的架构是多个模型各司其职:一个模型做意图识别,一个做生成,一个做安全审核,再用一个调度层把它们串起来。这个方向对工程能力的要求会更高,但当你发现一个模型在特定任务上效果卡住的时候,多模型的编排几乎是必然的解法。

我自己在做这个扩展时最大的体会是:AI工程不像写算法题有标准解,它的进展是在"上线—发现问题—改进—再上线"的循环里一点点磨出来的。你不需要第一版就做出惊天动地的效果,但你要保证每一次迭代都是可观测、可对比、可回退的。迭代能力,才是AI工程最值钱的能力。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 11:49:37

AR模型+MED:轴承故障诊断中的振动信号预处理与包络谱分析

在旋转机械振动诊断的现场,最磨人的往往不是设备真的停了,而是故障已经发生,你却从振动数据里看不出来。滚动轴承早期损伤产生的冲击非常微弱,被转频谐波、齿轮啮合成分和背景噪声层层盖住,直接拿原始信号做FFT或者包络…

作者头像 李华
网站建设 2026/10/1 11:48:22

MySQL两阶段提交:redo log与binlog如何保证崩溃恢复一致性

面试里MySQL高频题排个序,"redo log 和 binlog 为什么要做两阶段提交"绝对能进前五。很多人能背出结论:先写 redo log,再写 binlog,中间借一个 prepare 状态兜底。但要追问一句"崩溃恢复时,MySQL 到底凭…

作者头像 李华
网站建设 2026/10/1 11:47:15

指令流水线是提高CPU性能的关键技术,通过将指令执行过程划分为取指、译码、执行、访存、写回等多个阶段

计算机系统基础主要涵盖计算机组成原理与体系结构两个层面。计算机组成原理研究计算机硬件各部件的内部结构和工作原理,包括运算器、控制器、存储器、输入设备和输出设备五大基本部件。其中,运算器负责算术运算和逻辑运算,控制器负责指令的取…

作者头像 李华
网站建设 2026/10/1 11:46:42

面试必考:synchronized与Lock如何选型?

图1是本文的封面, 它明确了题目的具体内容, 同时也揭示了以“对比”和“选型”为核心的主线。首先交代一下文章的属性, 这是一篇对经典题目的解析。这道题选自我的本地的历史面试资料, 具体的来源情况在文章末尾会有说明, 它与任何一家公司目前有没有招聘需求都没有关系。「 和…

作者头像 李华
网站建设 2026/10/1 11:46:41

InfoComm China二十周年:专业视听行业风向标与逛展指南

InfoComm China走到第二十届,我第一反应不是“二十周年庆”这个仪式感,而是“这展真的陪我们这行走了很久”。这些年做专业视听、做音视频集成,每年六、七月份跑北京成了固定动作,InfoComm China在我心里早就不只是一个展位拼盘&a…

作者头像 李华