☰
AI工程从零到落地:数据清洗、模型微调、评测与部署全链路实践
2026/10/4 11:50:07 网站建设 项目流程

搞人工智能工程,最怕的不是没资料,而是资料太多、太散。今天我想聊聊"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 封装推理服务,并且做了批处理优化。核心思路很简单:单条请求走一个模型 inference,GPU 利用率往往非常低;把多条请求攒起来一起"塞"给模型,吞吐能提升好几倍。工程上这需要设置一个合适的 batch 窗口和最大pending 数量,下面是一个简化的示例逻辑:

async def inference_batch(requests_queue, model, max_batch_size=8, wait_seconds=0.1): while True: batch = [] # 攒够 batch 或等待超时后处理 while len(batch) < max_batch_size: try: req = await asyncio.wait_for(requests_queue.get(), timeout=wait_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 或 W&B 做实验记录。别嫌多,这几个工具在整条链路里各自有不可替代的作用: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", encoding="utf-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"], truncation=True, padding="max_length", max_length=128, ) enc["labels"] = examples["label_id"] return enc train_dataset = Dataset.from_pandas(train_df).map(tokenize_fn, batched=True) model = AutoModelForSequenceClassification.from_pretrained( model_name, num_labels=3 ) lora_config = LoraConfig( task_type=TaskType.SEQ_CLS, r=8, lora_alpha=16, lora_dropout=0.05, ) model = get_peft_model(model, lora_config) training_args = TrainingArguments( output_dir="./logs", num_train_epochs=3, per_device_train_batch_size=32, learning_rate=3e-4, evaluation_strategy="epoch", save_strategy="epoch", logging_steps=50, ) trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, ) trainer.train()

这里有几个参数我要特意解释一下:r=8是 LoRA 的秩,可以理解为微调时更新参数的规模,太小效果差,太大容易过拟合;lora_alpha=16是缩放系数,经验上设成2*r是一个常见起点;learning_rate=3e-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", model=model_path, tokenizer=model_path, device=0, ) 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
线上效果差但离线好评测分布不一致建线上回归、抽看 badcase

5. 工具选型与学习路径建议

5.1 选型原则:能解决当前问题就行

工具这个东西,很多人陷入"收集癖",把一堆框架都装一遍,最后真正用的就那么两三个。我的原则是:不管工具多时髦,只要能解决当下问题、社区活跃、文档够清楚,就足够。项目早期用最简单的方案,复杂度留到真正需要时再加。

以框架为例,Transformers是绕不开的,因为它把几乎所有常见模型的加载、微调、推理接口统一了;LoRA需要用PEFT库;服务部署可以用 FastAPI 加 vLLM。这三个组合覆盖了大部分中小型 AI 工程需求。再往上就是训练分布式、自动机器学习、大模型编排之类的东西,等真有需求再学,别提前囤。

5.2 从零开始的推荐学习顺序

  • 第一步:跑通一个端到端例子,哪怕是简单的情感分类。目标不是效果好,而是把"数据到接口"这条链路走一遍。
  • 第二步:把一个环节做深。比如把数据处理流程做得足够稳,或者把推理服务压到更低的延迟。
  • 第三步:建立自己的评测集和回归流程,让每次改动都能被量化。
  • 第四步:去啃原理,比如 Transformer 结构、注意力机制、损失函数,这时候你已经知道为什么要学了,效率完全不同。

这条路走下来,你缺的不是知识和工具,而是把知识串成系统的工程能力。AI 工程和写脚本的区别就在于:写脚本是一次性的,AI 工程是可维护、可复现、可迭代的。

我个人在实际操作中最深的一点体会是:不要因为某个模型或者框架很火就赶着用它。我见过太多项目,因为切换新框架,把已经稳定的线上服务拆了重做,结果引入一堆不必要的风险。AI 工程的稳定性不是靠最新的东西堆出来的,而是靠流程和评测堆出来的。哪怕从零开始,只要你把数据、模型、评测、部署这条链路的每个环节都设计清楚,每一步都有记录、有验证,这个系统就能长期健康地跑下去。最后再分享一个小技巧:每次实验之前,先在项目里建一个experiments/目录,把当时的配置、样本、结果全部存进去。踩过几次坑之后你会回来感谢这个习惯的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询