ARTICLE DETAIL

资讯详情

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

AI工程从零到一:完整路线图、核心原理与生产化实践

AI工程从零到一:完整路线图、核心原理与生产化实践 我建了一个公开路线图项目叫 ai-engineering-from-scratch名字很长但核心就一句话把 AI 工程这件事从零到一完整讲清楚。这个仓库里没有“读完你就月薪三万”的噱头只有我这些年从算法岗做到 AI 平台工程岗、从只会跑 notebook 到负责线上推理系统的真实经验。今天这篇不打算写一堆理论而是把这个项目的设计思路、路线结构和我在实操中踩过的坑完整拆一遍。适合三类人看想转行做 AI 工程的后端开发、刚入行的算法实习生以及所有“只会调 API”但对模型内部一头雾水的朋友。市面上教你“上车”的教程太多了有教调接口的有教三天跑通大模型的但很少有人讲清楚从数据到模型、从模型到服务、从服务到监控这条完整链路到底该怎么走。我见过太多人学完一堆课最后连一个完整的模型项目都交付不了问题恰恰出在“从零到一”中间的断层。这篇文章就是把这个断层补齐。1. 内容整体设计与思路拆解1.1 为什么我坚持“从零开始”而不是“从框架开始”这年头入门 AI 的第一反应都是找个 PyTorch 教程跑一遍跑通之后就觉得自己会了。但等你真在项目里遇到 loss 不降、显存爆掉、线上效果比离线差一大截这些问题时你会发现自己跟这个框架之间隔着一堵墙因为你根本不理解它在替你做什么。所以我在路线图里把“从零开始”定义成“从第一性原理出发”。你会调用model.fit()不算会你能解释清楚这一个 fit 内部到底在拟合什么才算会。比如损失函数为什么存在、一次反向传播的梯度是怎么流动的、为什么 batch size 太大反而收敛不好这些听起来基础但恰恰是排查问题的底层地图。整个路线图的第一个动手任务不是装 PyTorch而是用 NumPy 手写一个线性回归再手写一次梯度下降。代码量不大但当你能把 loss 对权重的导数一步步推出来、写出来后面再用 PyTorch 训练大模型你会非常清楚它在哪些环节帮你省事、哪些环节又可能在给你制造麻烦。这种“先懂原理再碰工具”的做法比一上来就啃几百页框架文档靠谱得多。1.2 这个路线图想解决什么实际痛点我接触过不少带着奇怪卡点来找我的朋友总结下来最典型的五类问题第一类是“学过但不会做”。课程看了很多paper 也读了一些但轮到自己去处理一份真实 dataset 时连第一步清洗该干什么都想不清楚。第二类是“训练完不知道怎么交付”。模型在 notebook 里跑得挺好领导一问“什么时候能上线”瞬间不知道怎么答因为保存模型、写推理接口、打包容器这些环节压根没练过。第三类是“上线了不知道怎么看”。接口是通了但没人知道模型预测质量好不好、什么时候该重训属于典型的“上线即失联”。第四类是“出了问题无从排查”。loss 不降说加数据显存炸了说换显卡永远是头疼医头脚疼医脚没有一套系统性的排查思路。第五类是“团队协作混乱”。谁的实验跑过什么参数、线上跑的到底是哪一版模型全靠聊天记录三个月后想复现一个旧实验比登天还难。ai-engineering-from-scratch 这套路线图就是围绕这五个痛点设计的每一个阶段都要求你交付一个可运行、可验证的产物而不是“学完知识”就完事。1.3 整体路线五个阶段一张表我在项目里把学习路径拆成五个阶段每个阶段都有明确目标和产出物你可以对照着看自己卡在哪一环。阶段核心主题关键内容产出物Phase 0编程与数学基础Python、NumPy、Pandas、线性代数、概率能熟练处理表格数据Phase 1传统机器学习线性模型、决策树、随机森林、评估指标训练并评估一个完整基线模型Phase 2深度学习与 TransformersPyTorch、训练循环、分词器、微调微调一个小型预训练模型Phase 3数据工程与特征工程数据清洗、样本设计、防泄漏、特征存储一套可复现的数据处理流水线Phase 4模型服务化与部署ONNX、FastAPI、Docker、GPU 推理一个可访问的模型 APIPhase 5监控与持续迭代日志、漂移检测、A/B 评估、重训机制一套监控看板与更新流程看着是不是很清楚但要注意这五个阶段不是串行学完才叫完成。正确的做法是先用 Phase 1 和 Phase 2 的最小技能跑通一个端到端小项目再用 Phase 3 到 Phase 5 去加固它。先跑通再做扎实这是我反复强调的原则。2. 核心细节解析与实操要点2.1 数据工程决定模型上限的第一块基石太多人觉得 AI 工程就是调模型但以我的经验真实项目里 70% 的时间都在跟数据打交道。模型选择再花哨也弥补不了数据的脏、乱、缺、漏。一个老生常谈但极其重要的结论是模型的效果上限由数据决定模型只是逼近这个上限。我在做一个用户流失预测项目时就栽过大跟头。用验证集评估AUC 高达 0.99我一度以为自己要发 paper了结果上线后真实效果比随机猜好不了多少。排查了很久发现是因为我把一条“用户已经流失之后”才产生的营销触达记录当作特征放进了训练集模型学会了“看到营销触达就是流失用户”这在离线数据里是“正确答案”但在线上预测时这种特征还没发生根本取不到。这就是典型的目标泄漏。所以我在路线图的 Phase 3 里专门加了一节课怎么系统性地检查数据泄漏。核心动作有三个训练集和测试集之间做交叉查重按时间顺序的业务数据必须按时间切分不能随机切所有特征必须确认在预测时刻是“已知的”。这三条做到至少能躲开我当年踩的那个巨坑。2.2 模型训练与调试的最小必备知识训练模型这件事技术细节多如牛毛但真正决定你能不能把这个项目做完的是几个最小必备知识点。第一个是损失函数的选择分类问题优先交叉熵回归问题用 MSE 这类距离损失第二个是优化器绝大多数情况 Adam 都能对付但要理解学习率意味什么第三个是梯度流动方向理解网络层之间为什么会有梯度消失或爆炸第四个是过拟合信号训练 loss 持续下降但验证 loss 开始反弹时就是典型的过拟合。我自己有个习惯训练一开始就画三条曲线训练 loss、验证 loss、学习率变化。很多人只盯着训练 loss等到最后才发现验证集一塌糊涂。记住一个判断规则如果训练 loss 和验证 loss 都在高位不动先看学习率和数据顺序是不是没做 shuffle如果训练 loss 在降但验证 loss 在涨不要急着加数据先考虑正则化、early stopping、dropout 这些手段如果两个 loss 都震荡剧烈十有八九是 batch size 太小或学习率太大。这套排查顺序写进路线图之后帮很多人省了至少一个月的瞎折腾。模型调试不是玄学是一套有顺序、有假设、能验证的工程方法。2.3 评估指标的坑离线指标不等于业务指标新手最容易犯的一个错误是把离线准确率当成一切。我给你举个极端例子垃圾邮件分类任务里 99% 是正常邮件1% 是垃圾邮件。如果你无脑把所有邮件都判为“正常”准确率直接就是 99%看起来漂亮极了但实际业务上等于没做。这时候要看的不是 accuracy而是 precision查准率和 recall查全率甚至要看混淆矩阵里每一类错误带来的业务成本。我见过很多团队的评估标准是“模型效果不错”但仔细一问“不错”是按什么指标定义的没人说得清。所以在路线图里我特意强调任何模型项目在开工之前必须先写下一句可量化的成功标准。比如“把垃圾邮件误判率从 5% 降到 2%同时保持正常邮件拦截率不超过 0.1%”。这句话写清楚了后面所有调参和模型选择才有方向。还有一点容易被忽略离线评估的分布和线上真实分布经常不一致。训练数据是今年一月的线上来的是三月的分布早就变了。所以离线指标只能作为参考真正的裁判永远是线上业务指标。2.4 部署从 notebook 到服务的最后一公里模型训练完只是完成了一半部署是另一半。很多人第一次把模型部署成 API 时会直接从训练脚本里复制出一大坨代码把Trainer对象整个 import 进来结果接口还没跑起来先下载了一堆模型权重。正确的做法是推理代码必须和训练代码彻底解耦。训练代码负责“产出模型权重”推理代码只负责“加载权重 前向计算”。我在路线图里推荐的部署组合是模型导出 ONNX接口用 FastAPI容器用 Docker推理用 ONNX Runtime。这套组合的学习成本很低性价比却极高。为什么用 ONNX因为它能把模型从 PyTorch 里解放出来小而快跨平台部署非常方便。对于一个小型文本分类模型导成 ONNX 之后在 CPU 上的推理速度通常能提升一倍以上。另外部署不是把代码扔给运维就结束了。你需要定义输入输出 schema、设置健康检查接口、配置资源上限、记录请求日志。这些细节我在第三节的实操部分会展开讲。2.5 监控与反馈闭环模型上线只是开始模型上线那一天不是项目的终点而是运维的起点。我见过太多模型上线三个月后预测分布早就偏得没边了团队却毫无察觉直到业务方投诉“最近结果怎么这么不准”才开始排查。监控要抓的核心指标至少有这几类接口层的延迟、吞吐、错误率模型层的预测分布变化业务层的最终效果指标。其中预测分布变化最容易被忽略但往往最先出问题。有一个便宜且有效的做法记录每次请求的输入文本哈希、模型版本、预测结果和延迟每天算一下预测类别的比例一旦发现分布偏移超过阈值就触发告警。在路线图里我还专门强调一个概念模型没有“上线即永逸”这回事只有持续更新。离线要维护一套重训流水线线上要留好反馈数据采集的入口。哪怕一开始只是每天导出一份预测日志也比什么都没有强得多。3. 实操过程与核心环节实现3.1 选一个恰到好处的练手项目说再多理论也不如亲手干一个项目。在 ai-engineering-from-scratch 里我建议的第一个完整项目是文本情感分类用 IMDB 电影评论数据集判断一条评论是好评还是差评。为什么选这个第一数据公开好拿不用自己吭哧吭哧爬半天第二文本数据不需要复杂的特征工程很多坑可以直接暴露在数据清洗和模型评估环节第三计算资源友好微调一个小模型在普通开发机上也能跑第四业务含义清晰好评差评一眼就能评估。如果你更偏好结构化数据也可以把用户流失预测作为替代但文本分类的全链路练习价值会更高因为后面做更复杂的 NLP 应用时这套流程可以直接复用。3.2 基础版从零手写逻辑回归练手感我的要求很反直觉第一个模型不准用 sklearn不准用 PyTorch就用 NumPy 手写。代码很简单我来展示核心部分。import numpy as np def sigmoid(z): return 1 / (1 np.exp(-z)) def predict(X, w, b): return sigmoid(X w b) def train(X, y, lr0.1, epochs100): num_features X.shape[1] w np.zeros(num_features) b 0.0 for epoch in range(epochs): p predict(X, w, b) grad_w X.T (p - y) / len(y) grad_b np.mean(p - y) w - lr * grad_w b - lr * grad_b return w, b每一行都值得你反复看。sigmoid的作用是把线性输出压到 0 到 1 之间变成概率grad_w X.T (p - y) / len(y)这一步是从交叉熵损失推导出来的梯度表达式它的形态简洁得惊人——预测概率减去真实标签再乘上特征矩阵转置。当你亲手算出这一步、写出这行代码再回头去看任何机器学习框架里的逻辑回归就会发现它不再是黑盒。这个练习的价值不是工程价值而是认知价值。它会让你彻底理解梯度下降我们不是在“调参”而是沿着损失函数的负梯度方向一步步往下走直到找到一个损失足够低的位置。3.3 进阶版用 Hugging Face 微调一个小模型流程跑通、手感建立之后就可以进入现代深度学习工作流了。我们用 DistilBERT 在 5000 条 IMDB 数据上微调一个情感分类模型这是整个路线图里最关键的“现代范式”体验。from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments import datasets train_ds datasets.load_dataset(imdb, splittrain[:5000]) test_ds datasets.load_dataset(imdb, splittest[:1000]) tokenizer AutoTokenizer.from_pretrained(distilbert-base-uncased) def tokenize(examples): return tokenizer(examples[text], truncationTrue, paddingTrue) train_ds train_ds.map(tokenize, batchedTrue).select_columns([input_ids, attention_mask, label]) test_ds test_ds.map(tokenize, batchedTrue).select_columns([input_ids, attention_mask, label]) model AutoModelForSequenceClassification.from_pretrained(distilbert-base-uncased, num_labels2) training_args TrainingArguments( output_dir./results, num_train_epochs2, per_device_train_batch_size16, eval_strategyepoch, save_strategyepoch, logging_dir./logs, ) trainer Trainer(modelmodel, argstraining_args, train_datasettrain_ds, eval_datasettest_ds) trainer.train()注意几个细节。第一paddingTrue会把序列补到 batch 内最大长度truncationTrue控制超长文本截断两个参数缺一不可。第二我把数据量限制在 5000 条和 1000 条是为了让训练时间控制在几分钟级别你完全不需要在练手阶段就上全量数据。第三建议你自己试一下不同的num_train_epochs、学习率和 batch size这会让你直观感受到超参对最终效果的影响。关于序列长度我可以多说一句DistilBERT 默认最大长度是 512但 IMDB 评论大多不超过两百字所以实践里我通常把max_length256甚至 128。序列长度减半显存占用几乎等比例下降而精度损失很小。256 个 token 能覆盖绝大多数评论信息了。3.4 导出 ONNX 并用 FastAPI 搭一个推理服务模型微调完成之后下一步就是把它从 PyTorch 里“解放”出来。我建议导出成 ONNX 格式这样推理阶段不再依赖完整版 PyTorch模型体积更小、启动更快、部署更干净。from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch model AutoModelForSequenceClassification.from_pretrained(./results/checkpoint-500) model.eval() tokenizer AutoTokenizer.from_pretrained(distilbert-base-uncased) dummy_input tokenizer(this movie is great, return_tensorspt) torch.onnx.export( model, (dummy_input[input_ids], dummy_input[attention_mask]), sentiment_model.onnx, input_names[input_ids, attention_mask], output_names[logits], dynamic_axes{input_ids: {0: batch}, attention_mask: {0: batch}}, opset_version14, )导出之后用 FastAPI 包一层 HTTP 接口代码非常短from fastapi import FastAPI from pydantic import BaseModel from transformers import AutoTokenizer import onnxruntime as ort import numpy as np app FastAPI(titlesentiment api) tokenizer AutoTokenizer.from_pretrained(distilbert-base-uncased) session ort.InferenceSession(sentiment_model.onnx, providers[CUDAExecutionProvider, CPUExecutionProvider]) class Item(BaseModel): text: str app.post(/predict) def predict(item: Item): inputs tokenizer(item.text, return_tensorsnp, truncationTrue, paddingTrue) logits session.run(None, {input_ids: inputs[input_ids], attention_mask: inputs[attention_mask]})[0] prob 1 / (1 np.exp(-logits[0][1])) return {label: pos if prob 0.5 else neg, confidence: float(prob)}这个接口做的事情很清楚拿到文本走同一个 tokenizer 转成张量交给 ONNX Runtime 推理把 logits 转成概率最后返回标签和置信度。别小看这个简单的服务它已经具备了一个生产级推理服务的基本骨架。后面要加鉴权、限流、监控都是在这个骨架上扩展。我在项目里专门提醒过一个点在线服务的 tokenizer 版本必须和训练时保持一致。否则词汇表一变同一句话可能被切分成不同的 token预测结果就会莫名其妙地飘。3.5 补上实验跟踪和 Docker 部署从第一个实验开始我就建议你用 MLflow 记录每次训练的配置、指标和产物。这习惯越早养成后面越省心。import mlflow mlflow.autolog() with mlflow.start_run(): trainer.train() trainer.evaluate()mlflow.autolog()会自动记录超参数、loss、评估指标以及模型文件你什么都不用手动写。启动mlflow ui就能在浏览器里看到每一次实验的记录三个月后还能精确复现某一次实验用的代码版本和数据版本。部署环节我用一个极简 Dockerfile 把服务打成镜像FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]构建镜像后运行容器时一定要记得加资源限制这是我强烈建议的习惯操作docker build -t sentiment-api . docker run --rm -p 8000:8000 --memory4g --cpus2 sentiment-api给容器设置--memory和--cpus是防止模型推理或突发流量把整台机器拖垮。这个习惯越早养成线上事故越少。3.6 部署后的基础验证与观察接口起来之后先用 curl 打一发验证curl -X POST http://localhost:8000/predict \ -H Content-Type: application/json \ -d {text: this movie is fantastic}看到返回{label:pos,confidence:0.98}之类的结果服务就算通了。但我还会再多做一步压测。用 hey 或者 locust 简单打几百个请求看 P95 延迟和错误率。你会发现单个服务本地调用和多并发请求下的表现完全不同这一步能提前暴露很多资源瓶颈。如果你有 GPU推理时用CUDAExecutionProvider没有 GPU就老老实实用 CPU。一个小型 DistilBERT 模型在 CPU 上用 ONNX Runtime 做单条推理延迟通常在几十毫秒级别完全够用。不要一上来就觉得“AI 服务必须要 GPU”很多业务场景 CPU 就能扛成本还低得多。4. 工具选型与生产化细节我的真实对比4.1 实验追踪与模型注册选 MLflow 还是 WB市面上的实验追踪工具非常多我先把三个主流方案的利弊列成表工具优点缺点适用场景MLflow开源、可自建、实验模型注册部署一条龙UI 相对朴素中小团队、需要私有部署Weights Biases交互体验好、可视化强、团队协作方便免费版有限制、数据在 SaaS 端快速原型、学术研究ClearML开源、支持大模型训练管理部署略复杂已有基础设施的团队我给大多数中小团队的建议是从 MLflow 开始。理由很简单它一个工具覆盖了实验追踪、模型注册、产物存储三个需求而且只用pip install mlflow就能启动不需要额外花钱。模型注册这个概念很多新手不理解你把它想成“模型版本的 Git”就懂了每个模型版本有名字、标签、指标、文件路径线上要回滚时直接切版本不用翻聊天记录找你上传的第几个model_v7_final_real_final.pt。4.2 数据版本管理让实验真正可复现很多人训练模型只用一份 data.csv改来改去最后根本说不清楚当前模型是用哪份数据训练出来的。数据版本管理和代码版本管理同样重要。我常用 DVC 做数据版本管理核心流程很简单dvc init dvc remote add -d storage s3://your-bucket/dvc dvc add data/train.csv echo data/train.csv.dvc .gitignore git add data/train.csv.dvc dvc.lock git commit -m add training datadvc add会把数据文件的信息写进一个.dvc文件真正的数据文件推到远端对象存储里。Git 记录的是数据文件的哈希指针而不是数据本体。这样仓库不会因为大数据文件而爆炸同时你任何时候切到某个 commit都能用dvc pull把对应版本的数据拉回来。如果你做的是个人练手项目也可以偷个懒不引入 DVC但至少要养成习惯在目录或文件名里带上日期比如data_20240528.csv或者把数据文件放进 Git LFS。数据版本管理这件事平时感觉不到价值一旦要回溯某个实验结果时它就是你唯一的救命稻草。4.3 推理服务框架FastAPI、BentoML、Triton 怎么选我经常被问到“上线模型该用哪个服务框架”其实答案取决于你的团队规模和业务复杂度。方案优势运维复杂度推荐场景FastAPI ONNX Runtime灵活、轻量、上手快低个人/小团队接口逻辑简单BentoML内置部署编排、模型管理、插件丰富中团队已有一定工程能力Triton Inference Server高性能、多模型并发、动态批量高大规模 GPU 推理、多模型统一入口我的真实建议非常直接大多数团队不需要 Triton。Triton 的价值在高吞吐、多模型并发、以及 N 卡统一调度上但它对运维能力的要求也高出一大截。如果你只有两三个模型、日均调用量几十万次FastAPI 加 ONNX Runtime 是性价比最高的起点。等你真的有一天需要同时服务 10 个模型、每个模型都要求高吞吐时再迁移到 Triton 完全不晚。4.4 硬件规划与成本控制最后聊聊钱。训练和推理的成本控制是所有 AI 工程都绕不开的话题。先说推理小模型在 CPU 上跑完全可行不要逢模型就上 GPU。以文本分类为例把模型导出 ONNX 并量化成 int8模型体积能缩到原来的四分之一CPU 推理速度还能进一步上升。很多场景下用 int8 CPU 部署一年省下的服务器成本够你再招一个实习生。再说训练实验初期建议用小数据、小模型、多轮快速迭代锁定方案后再上全量数据和大模型。这能省下大量算力开销。如果你用云 GPU训练任务一定要保存 checkpoint并且定期把 checkpoint 同步到对象存储这样即使机器被回收也可以随时续跑不至于从头再来。5. 常见问题与排查技巧实录这部分把我在实操中踩过、也帮别人排查过的高频问题整理成速查表然后再逐个展开。问题现象常见原因排查方向快速修复训练 loss 不降学习率设置不当、数据未 shuffle、标签错位打印首个 batch 的输入输出检查调低学习率、开启 shuffle 并复检标签GPU 显存爆炸batch size 过大、序列过长、未用混合精度逐层打印激活显存减 batch、梯度累积、开 AMP离线分数极高但线上效果差数据泄漏、分布偏移检查时间泄漏和训练/测试交叉重复按时间切分、去重、重采测试集接口延迟超高模型过大、推理框架未优化压测看 P95、分析耗时分布导 ONNX、量化、加长超时与 batch本地跑通但容器里报错依赖版本不一致、环境缺少系统库对比 requirements 与镜像内版本锁定依赖版本、固定基础镜像5.1 训练 loss 不降或震荡这是新手问得最多的问题原因其实大多是同一个方向信息流断掉了。我的排查顺序固定是先看数据再学学习率最后看网络结构。先打印一个 batch 出来肉眼确认输入和标签是不是一一对应。我犯过的最离谱的错是 dataloader 忘了设置shuffleTrue模型每天按顺序学到一类样本loss 看似在降验证集却一塌糊涂。再看学习率有的教程给的默认学习率对别人合适但对你自己的任务可能太大或太小我通常把 learning rate 从1e-3开始往下扫。最后检查网络是不是激活函数用了 ReLU 导致死亡神经元或者输入特征没做归一化导致梯度计算异常。这个顺序能覆盖九成以上的“loss 不降”问题。5.2 GPU 显存爆炸显存炸了不代表你要马上换卡很多时候是使用姿势的问题。可以考虑的顺序是调小 batch size改用梯度累积来模拟更大的 batch打开混合精度训练显存占用能直接减半检查序列长度是不是被人为拉长了比如把 512 个 token 的模型硬喂 1024 的文本。对于一个小型 Transformer 模型显存占用的大头往往不是参数本身而是中间激活值和梯度它们跟 batch size、序列长度、层数几乎成正比。有个粗略的经验公式可以帮你估算训练一块模型需要的显存大约是推理的三到五倍推理时如果你能接受先用 CPU 加 int8 量化跑通业务再评估要不要上 GPU这是成本最稳的路线。5.3 离线分数高但线上效果差这个现象背后第一嫌疑就是数据泄漏。除了我之前说的目标泄漏还有两种常见情况时间泄漏和重复泄漏。时间泄漏最常见于时序业务你随机切分了数据集导致模型在训练时“偷看”了未来的信息重复泄漏则是因为同一实体在训练集和测试集里都出现过模型相当于“见过答案”。排查方法很直接业务数据按时间点切分并做一次 ID 级查重。另一种可能是采样偏差。比如你收集的训练数据来自某一类用户但线上流量画像完全不同。这种问题最有效的缓解办法是上线后做影子评估让新模型和旧模型同时接收线上流量记录各自预测结果和后续业务反馈来判断谁真的更好。5.4 推理延迟高接口延迟超标先量清楚时间都花在哪了。把一次请求的耗时拆成三段网络传递、tokenizer 处理、模型推理。大部分时候你都会发现瓶颈在模型推理。解决办法从便宜到贵排列导成 ONNX 并用 int8 量化通常能获得一到三倍加速如果还不行尝试减小序列最大长度这能直接降低计算量再不行考虑换更小的模型比如从 BERT 降到 DistilBERT最后如果业务允许把同一批请求合并成一个 batch 推理吞吐量提升非常明显。缓存也值得做。如果业务里有大量重复或相似查询Hash 一下输入文本命中缓存直接返回这是几乎零成本的优化。5.5 训练环境和推理环境不匹配这是我在生产环境见过最多的“幽灵 Bug”。某个模型在训练时好好的部署到容器里预测结果全变了。原因往往不是代码逻辑而是依赖版本不一致。最典型的是 transformers 库训练用的是 4.30 版本推理容器里装的是 4.40 版本中间某个 tokenizer 的默认行为变了同样的文本进去出来的 token 序列完全不同。解决办法只有一条路锁定版本。requirements.txt 里的所有关键依赖包名后面必须写上精确版本号比如transformers4.30.2、torch2.1.2、onnxruntime1.17.1。同时把训练和推理放进同一个基础镜像至少保证它们跑在同一个 Python 版本下。这些细节不会让你的模型变聪明但能让你在凌晨三点被线上告警电话叫醒的频率大幅下降。6. 最后分享三条我最深的体会说了这么多最后讲三件我在实际项目中体会最深的事。第一AI 工程的核心不是模型而是数据流和反馈流。你花一周调模型结构不如花一天把数据到模型的链路理顺、把线上反馈数据采集起来。模型只是这条流水线上的一个零件流水线不通换再好的零件都没用。第二基线模型永远是你最可靠的朋友。我每接一个新任务第一版永远是最简单的逻辑回归或者决策树。它不追求效果只负责把整个数据链路、评估链路、部署链路完整跑通。基线的效果就是你的下限后面换成大模型你能清楚知道提升到底来自哪里。第三从第一天起就写日志、记录实验。哪怕只是在本地跑一个几十行的脚本也顺手把参数、数据版本、结果指标记到 CSV 里。三个月后再回来看你会感激当时的自己。我见过太多人实验跑了几十次最后问“上次最好的效果是哪个配置”答案永远是最经典的三个字不记得了。如果让我现在回去重做这个项目我最想补的一课是检索增强生成RAG因为它是目前把大模型落地到业务场景最实用、也最容易踩坑的技术方向。这部分我已经在整理等方案稳定后会直接作为新章节更新到 ai-engineering-from-scratch 里。
返回列表