ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

AI工程从零到落地:数据清洗、模型微调、评测与部署全链路实践

2026/10/4 11:50:16 拓冰建站 浏览量
AI工程从零到落地:数据清洗、模型微调、评测与部署全链路实践 搞人工智能工程最怕的不是没资料而是资料太多、太散。今天我想聊聊AI Engineering from Scratch这件事——从零开始把 AI 工程能力搭起来不是调一个 API、跑通一个 demo 就算完而是把数据、模型、评测、部署这条链路完整地走通并且能在真实业务里稳定跑起来。这篇文章适合两类人一类是从算法或研发方向转过来的工程师想系统补齐 AI 工程的短板另一类是已经在用现成 AI 服务、但是遇到问题只能到处搜答案的人。我会把从零开始的路线、关键环节的原理、踩过的坑和可直接抄的代码都放出来。1. 先搞清楚从零开始到底从哪开始1.1 一个容易被误解的起点很多人一说从零搭建 AI 工程第一反应是去学神经网络、学反向传播、把 Transformer 源码啃一遍。这个方向没错但它是研究路径不是工程路径。工程路径的重要区别在于你不一定要从数学原理推导出一切但你必须在拿到数据之后能快速形成一套构建—训练/调用—评测—部署—迭代的闭环。换句话说从零开始的本质不是从神经元开始而是从链条开始。我见过不少团队模型训练得挺像样但实际投入使用就崩线上请求一多就超时、badcase 没人能讲清楚原因、数据稍微一换效果就掉。这些问题都不是模型本身的问题而是工程链条断裂了。所以我的观点很直接AI 工程从零开始第一步不是写模型而是搭一条最简链路哪怕是最糙的版本。1.2 我走过的弯路先学框架再学原理 vs 先学原理再上手这个争议一直存在。我自己的教训是不要二选一而是按项目阶段反复横跳。最开始入手的时候我花了大半个月从基本的数学推导看到 Transformer 的 attention 公式结果一写代码还是各种报错。后来改成要用什么就学什么先拿 Hugging Face 跑通一个文本分类过程中倒回去看 embedding、tokenizer、loss function 的原理效率反而高很多。这个背后有一个很实际的原因AI 工程涉及的知识面太宽了你有 Python、有 PyTorch、有数据清洗、有模型推理优化、有服务部署如果每个都要先学原理再动手还没摸到门就已经放弃了。反过来先有一个跑得通的结果作为锚点再逐个击破不懂的环节你会更清楚哪些原理是必须的、哪些可以先放放。我个人推荐的节奏是70%的时间在做30%的时间在补原理。1.3 从零开始的能力地图真正把 AI 工程从零搭起来你得对照检查这几块能力能力模块解决什么问题最低要求数据处理喂给模型的东西干不干净、格正确能写清洗脚本、能做统计分析模型理解选什么模型、为什么选它熟悉常见架构和各自适用场景训练/微调让模型适应你的数据会配置训练脚本、能看懂 loss评测体系知道改完是变好还是变坏能定义指标、能跑回归部署上线让模型真正服务用户会做推理优化、能写服务接口监控迭代线上出问题能定位会查日志、能设计兜底逻辑这六块里最容易被忽略的是评测体系和监控迭代。很多人训练完跑几个测试例子觉得效果不错就上线了等到线上出问题才手忙脚乱。从零开始的正确姿势是在第一天就把评测和监控纳入设计范围而不是最后补。2. 核心细节解析与实操要点2.1 数据环节没有干净数据模型就是空转AI 工程里有一个很不性感、但决定成败的环节数据处理。模型再强喂进去的是脏数据产出就是垃圾。我习惯把数据处理拆成三步采集、清洗、构造样本。采集阶段要搞清楚数据的来源、格式、权限和更新频率。很多项目从零开始时根本没有现成数据集得自己去爬、去整理、去标注。清洗阶段要处理的常见问题包括重复内容、格式混乱、编码错误、标签噪声。构造样本是最需要领域知识的一步——你需要决定哪些信息放进 prompt、哪些做负样本、标签体系怎么设计。实操上我建议从一开始就用代码把这些流程固定下来不要用 Excel 手工搞。比如下面这个简单的清洗函数你可以根据自己的数据格式扩展import re import hashlib def clean_text(text: str) - str: # 去 HTML 标签 text re.sub(r[^], , text) # 统一空白字符 text re.sub(r\s, , text).strip() # 去除过短内容通常是噪声 if len(text) 10: return return text def dedup_by_hash(text: str) - str: return hashlib.md5(text.encode(utf-8)).hexdigest()数据这块我的经验是每做一步清洗都要统计一下过滤掉了多少、为什么过滤。如果清洗规则太激进会把有价值的样本误删太保守噪声又会污染模型。保持样本量和数据质量之间的平衡是数据工程的核心手感。2.2 模型环节选型、微调、调用的取舍模型选型是从零开始最容易被带偏的地方。很多人上来就挑参数量最大的模型觉得效果一定最好。实际测试下来小模型在很多垂直场景里完全可以打赢大模型而且推理成本低很多。选型要考虑的是任务复杂度、数据规模、延迟要求、硬件预算、团队维护能力。我做的第一个项目就吃过这个亏当时为了追求效果直接上了大模型微调结果一台单卡根本带不动被迫换小一号的模型反而发现小模型加更好的数据清洗之后效果差不多推理速度快了三倍。微调方案也要按情况取舍。如果你有几百条到几千条高质量标注数据可以用 LoRA 这类轻量微调方案成本低、速度快、迭代周期短如果你有几十万条数据而且任务场景非常专注才值得做全参数微调如果你本身用的是商用模型 API那更多要考虑的是 prompt 优化、few-shot 示例和 RAG 检索增强而不是自己训练。2.3 评测环节不被指标骗也不被例子骗评测是从零开始最容易做得看起来严谨、实际上没用的环节。常见做法是拿几个例子跑一下觉得差不多就上线。但 AI 系统的非确定性决定了你必须用统计学方式评估而不是用几个案例。我建议至少三层评测第一层是离线指标比如分类任务的准确率、F1生成任务的 BLEU、ROUGE以及一些自定义规则校验。第二层是badcase 分析把预测错的样本按错误类型归类搞清楚错误来源是数据、模型还是 prompt。第三层是线上回归把一小部分真实流量切给新模型对比业务指标。我特别想说一个观点指标只能告诉你哪里变了不能告诉你变了之后到底好不好。准确率涨了 0.5% 可能只是某个类别样本增多了真正的质量提升要靠 badcase 分析和业务反馈。所以评测体系里一定要保留人审的环节哪怕每周抽几百条人工看一遍都值得。2.4 部署与服务环节模型只是系统的一部分模型训练好、评测过关这只是万里长征走了一半。部署环节的坑往往比训练还多。你需要考虑接口延迟、并发量、显存占用、批量推理策略、缓存机制、降级方案。线上服务不是把模型加载起来就完事而是要做成一套有兜底能力的系统。我在生产环境里常用 vLLM 或者 FastAPI 封装推理服务并且做了批处理优化。核心思路很简单单条请求走一个模型 inferenceGPU 利用率往往非常低把多条请求攒起来一起塞给模型吞吐能提升好几倍。工程上这需要设置一个合适的 batch 窗口和最大pending 数量下面是一个简化的示例逻辑async def inference_batch(requests_queue, model, max_batch_size8, wait_seconds0.1): while True: batch [] # 攒够 batch 或等待超时后处理 while len(batch) max_batch_size: try: req await asyncio.wait_for(requests_queue.get(), timeoutwait_seconds) batch.append(req) except asyncio.TimeoutError: break if batch: outputs model.generate([r[prompt] for r in batch]) for req, out in zip(batch, outputs): req[future].set_result(out)部署还有一个常被忽略的问题依赖管理。我见过太多项目半年后想重新部署结果因为 Python 库版本冲突、CUDA 版本对不上折腾了两天还没跑起来。所以从第一天开始就用 Docker 锁定运行环境把训练的版本、依赖、随机种子全部记录清楚这能省掉后面非常多麻烦。3. 实操过程动手搭一个可复现的 AI 工程示例3.1 环境准备与项目结构纸上谈兵没意思我直接拿一个最常用的场景来走通全流程做一个电商评论的情感倾向识别并封装成可调用的服务。这个任务数据好找、业务价值直观、从零开始做闭环最合适。项目结构我是这样规划的ai_engineering_demo/ ├── data/ │ ├── raw/ # 原始数据 │ └── processed/ # 清洗后的样本 ├── src/ │ ├── preprocess.py # 数据清洗 │ ├── train.py # 微调训练LoRA │ ├── evaluate.py # 离线评测 │ └── serve.py # 服务封装 ├── config/ │ └── settings.yaml # 参数配置 └── requirements.txt这里的关键是代码、配置、数据、模型权重尽量分离。新人最容易犯的错是把所有东西堆在一个文件夹调试起来像在翻垃圾桶。把职责分清楚后面维护和换人会轻松很多。环境上用 Python 3.10 以上版本配合 PyTorch 和 Hugging Face Transformers还建议装一个 MLflow 或 WB 做实验记录。别嫌多这几个工具在整条链路里各自有不可替代的作用Transformers 负责模型加载和训练接口MLflow 负责实验对比vLLM 负责推理加速。3.2 数据构建代码原始数据是几万条电商平台的评论字段包括评论文本和星级评分。第一步是清洗和打标签。我一般把星级映射成三个类别1-2 星为负面、3 星为中性、4-5 星为正面。然后清洗文本去掉无效字符并对类别做一下分布统计import pandas as pd from collections import Counter df pd.read_csv(data/raw/comments.csv, encodingutf-8) def label_star(star: int) - str: if star 2: return negative if star 3: return neutral return positive df[label] df[star].apply(label_star) df[clean_text] df[comment].apply(clean_text) # 过滤清洗后为空的行 df df[df[clean_text] ! ] # 检查类别分布 print(Counter(df[label]))如果类别分布严重不均衡比如正面样本占 80%、负面样本占 3%后面训练时模型很容易把大部分样本都预测成正面评测指标看着还行实际线上没用。处理办法有两种一种是采样让各类别数量均衡一点另一种是在 loss 里对不同类别加权。新手建议先用采样因为简单直观。3.3 微调训练代码这个场景数据量不大纯用大模型 API 也能做但从工程上手角度考虑我选择用 LoRA 微调一个小型中文模型来感受完整链路。训练脚本大致是这个样子from datasets import Dataset from transformers import ( AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments, ) from peft import LoraConfig, get_peft_model, TaskType # 选择小型预训练模型控制成本 model_name your-chosen-base-model tokenizer AutoTokenizer.from_pretrained(model_name) def tokenize_fn(examples): enc tokenizer( examples[clean_text], truncationTrue, paddingmax_length, max_length128, ) enc[labels] examples[label_id] return enc train_dataset Dataset.from_pandas(train_df).map(tokenize_fn, batchedTrue) model AutoModelForSequenceClassification.from_pretrained( model_name, num_labels3 ) lora_config LoraConfig( task_typeTaskType.SEQ_CLS, r8, lora_alpha16, lora_dropout0.05, ) model get_peft_model(model, lora_config) training_args TrainingArguments( output_dir./logs, num_train_epochs3, per_device_train_batch_size32, learning_rate3e-4, evaluation_strategyepoch, save_strategyepoch, logging_steps50, ) trainer Trainer( modelmodel, argstraining_args, train_datasettrain_dataset, eval_dataseteval_dataset, ) trainer.train()这里有几个参数我要特意解释一下r8是 LoRA 的秩可以理解为微调时更新参数的规模太小效果差太大容易过拟合lora_alpha16是缩放系数经验上设成2*r是一个常见起点learning_rate3e-4比全参数微调的 5e-5 要高因为 LoRA 本身更新的参数量少需要快一点。这些数值不是拍脑袋定的都是我从实验里总结的相对稳妥的默认值你可以在此基础上微调。如果你觉得 Trainer 太黑盒也可以自己控制训练循环但核心还是那几件事定义优化器、前向传播、算 loss、反向传播、周期性评测。从小白到熟练我建议先用 Trainer 把流程跑通再考虑黑盒之外的自定义逻辑。3.4 评测与回归训练完就进入评测环节。我不建议只看 val accuracy而是把每一条预测结果和标签拉出来按类别计算准确率和召回率再做错误归类。代码可以写成这样from sklearn.metrics import classification_report, confusion_matrix val_preds trainer.predict(eval_dataset).predictions.argmax(axis-1) print(classification_report(y_true, val_preds, target_names[negative, neutral, positive])) print(confusion_matrix(y_true, val_preds))这里有个非常重要的点评测数据要和训练数据彻底隔离。很多人为了偷懒直接从同一批数据里切出 10% 当评测集不洗牌、不检查重叠结果就是模型背答案评测分数虚高。我推荐在数据构建阶段就按时间、用户或者内容去重切分确保评测样本是模型没见过的。回归测试也要尽早自动化。把一批固定的测试样本几百条保存下来每次改完 prompt 或者重新训练后都跑一遍记录指标变化。这样做的好处是任何改进都是一个可追踪的实验不会今天改完觉得挺好下周又觉得不行却说不清是哪天改的。3.5 服务封装最后一个环节是把模型变成可用服务。我直接用 FastAPI加载微调后的 LoRA 权重提供POST /predict接口。代码如下from fastapi import FastAPI from pydantic import BaseModel from transformers import pipeline app FastAPI() model_path ./final_model classifier pipeline( text-classification, modelmodel_path, tokenizermodel_path, device0, ) class CommentItem(BaseModel): text: str app.post(/predict) def predict(item: CommentItem): result classifier(item.text)[0] return {label: result[label], score: result[score]} app.get(/health) def health(): return {status: ok}一个容易忽略的事上线前要测一下空输入、超长输入、无意义输入这三个边界情况。很多 AI 服务在正常输入下表现很好一遇到空字符串或者超长文本就崩。我在服务里加了一层输入校验超过长度直接截断空文本返回一个默认兜底结果绝不把异常抛给调用方。如果并发量上来了建议把服务请求放进队列用批处理做推理再对结果做异步返回。这块涉及的东西不少但核心思想就是模型很贵不要让它等单个请求要让一批请求等模型一起处理。4. 常见问题与排查技巧实录4.1 训练显存爆了怎么办跑模型最常见的问题就是CUDA out of memory。我的排查顺序是先看是不是 batch size 太大调小一半试试再看是不是序列太长截断 max_length如果还不行就上梯度累积把一个大 batch 拆成小 batch 的多次传播。量化也是降显存的好手段把模型精度从 FP16 换成 INT8 能省不少。如果这些都试了还是不够那就要考虑换更小的模型了。这里有一个心态问题不要觉得换小模型是妥协很多生产场景里小模型更实用因为延迟更低、部署更简单。4.2 生成质量不稳定文本生成类任务常见的问题是非确定性太强。同一个 prompt前后两次返回差别很大。原因通常是解码参数设置得太激进比如 temperature 太高。排查时先固定一个低一点的温度再把 top_p 控制住这两个参数共同决定输出的随机程度。如果你做的是客服回复、内容提取这类追求稳定的任务temperature 设在 0.1-0.3 通常比较安全。另外要区分不稳定和没学好两种情况。如果只有个别极端输入不稳定那多半是解码和兜底逻辑的问题如果大部分输入都乱答那就是模型本身能力不够需要换模型或者补充数据。别在一个坏模型上调参那是浪费时间。4.3 评测指标与线上体验不一致这个坑我踩过很多次。离线评测时 accuracy 很高线上用户反馈却很差。原因往往有两个一是评测集跟你真实线上分布不一致你拿的是旧数据或者整理过的数据但线上跑的是全量原始输入二是你的评测指标选错了比如分类模型的准确率无法反映出错成本的差异。解决办法是增加一条线上冒烟流程把新模型部署到测试环境切 5% 的线上流量过去跑 1-2 天用用户点击率、任务完成率这类业务指标来做判断。这一步虽然麻烦但它是 AI 工程从能跑到能用的关键分水岭。4.4 一些独家避坑经验列几条我拿真金白银换回来的经验训练前先打印数据的 shape 和几个样本确认标签映射没有串位。我犯过一次标签 ID 从 1 开始而模型期望从 0 开始的低级错误白白浪费了一次训练。所有随机操作固定 seed。数据采样的顺序、模型权重初始化、dropout这些都影响结果不固定 seed 你根本没法复现实验。微调后一定要做一次领域外数据测试。拿一些和训练数据差异很大的样本测一下看模型会不会能力退化。很多时候微调会让模型学窄只顾得上训练集里的模式把通用能力丢了。服务接口一定要加超时控制和缓存。AI 模型推理时间波动比普通接口大得多不加超时会让调用方一直阻塞加上缓存可以大幅降低重复请求的压力。4.5 常见问题速查表现象可能原因排查动作训练 loss 不降学习率太高/数据标签噪声大降低学习率、抽查标签验证集过拟合评测集与训练集重叠重新切分、按时间去重接口响应慢单条请求推理、GPU 利用率低加批处理、优化解码参数生成内容重复重复惩罚参数过低调整 repetition_penalty线上效果差但离线好评测分布不一致建线上回归、抽看 badcase5. 工具选型与学习路径建议5.1 选型原则能解决当前问题就行工具这个东西很多人陷入收集癖把一堆框架都装一遍最后真正用的就那么两三个。我的原则是不管工具多时髦只要能解决当下问题、社区活跃、文档够清楚就足够。项目早期用最简单的方案复杂度留到真正需要时再加。以框架为例Transformers是绕不开的因为它把几乎所有常见模型的加载、微调、推理接口统一了LoRA需要用PEFT库服务部署可以用 FastAPI 加 vLLM。这三个组合覆盖了大部分中小型 AI 工程需求。再往上就是训练分布式、自动机器学习、大模型编排之类的东西等真有需求再学别提前囤。5.2 从零开始的推荐学习顺序第一步跑通一个端到端例子哪怕是简单的情感分类。目标不是效果好而是把数据到接口这条链路走一遍。第二步把一个环节做深。比如把数据处理流程做得足够稳或者把推理服务压到更低的延迟。第三步建立自己的评测集和回归流程让每次改动都能被量化。第四步去啃原理比如 Transformer 结构、注意力机制、损失函数这时候你已经知道为什么要学了效率完全不同。这条路走下来你缺的不是知识和工具而是把知识串成系统的工程能力。AI 工程和写脚本的区别就在于写脚本是一次性的AI 工程是可维护、可复现、可迭代的。我个人在实际操作中最深的一点体会是不要因为某个模型或者框架很火就赶着用它。我见过太多项目因为切换新框架把已经稳定的线上服务拆了重做结果引入一堆不必要的风险。AI 工程的稳定性不是靠最新的东西堆出来的而是靠流程和评测堆出来的。哪怕从零开始只要你把数据、模型、评测、部署这条链路的每个环节都设计清楚每一步都有记录、有验证这个系统就能长期健康地跑下去。最后再分享一个小技巧每次实验之前先在项目里建一个experiments/目录把当时的配置、样本、结果全部存进去。踩过几次坑之后你会回来感谢这个习惯的。