很多人第一次接触 AI 工程,都是从"跑通一个模型"开始的。但跑通一个 Notebook 里的模型,和把模型变成一套稳定、可迭代、能上线的系统,中间隔着一条巨大的鸿沟。我在这个领域摸爬滚打这几年,最大的体会就是:AI 工程从来不是模型的问题,而是工程的问题。这篇内容就是围绕 "ai-engineering-from-scratch" 这条主线,把从零开始搭建 AI 工程能力的方法、踩坑和思考完整梳理一遍,适合那些已经有基础 Python 或机器学习经验,但还没真正把项目推向生产环境的人。
1. 先搞清楚:AI 工程和传统软件工程差在哪里
1.1 "能跑的脚本"和"能用的系统"是两回事
我见过太多团队,模型在 Jupyter Notebook 里跑得飞起,一到上线就崩。原因很简单:Notebook 里根本不存在并发、延迟、数据漂移、版本回滚、监控告警这些问题。写一个预测脚本只需要几十行代码,但把它变成生产系统,你需要处理请求排队、批量推理、结果缓存、异常重试、审计日志、模型热更新——这些在传统后端开发里都是基本功,但在 AI 项目里经常被忽略。
打个比方:你可以在厨房里做出一桌好菜,但开一家餐厅是另一回事。厨房只需要你一个人懂火候,餐厅需要你搞定供应链、排班、卫生标准、客户投诉。AI 工程就是把"会做菜"升级成"开餐厅"的全套能力。
1.2 三个本质差异:不确定性、数据依赖、迭代周期
AI 工程和传统软件工程有三个本质差异,理解了这三点,后面很多决策就顺理成章了。
第一是不确定性。传统程序是确定性的——同样的输入必然得到同样的输出。但模型不是,同样的输入可能因为版本不同、阈值调整、随机种子变化而输出不同结果。所以你不能只测"功能正确",还要测"分布合理"。
第二是数据依赖。传统软件的复杂度在于代码逻辑,AI 系统的复杂度很大程度在数据里。数据质量稍微波动,模型效果立刻下滑。所以 AI 工程里有个铁律:数据问题永远优先于模型问题。
第三是迭代周期。传统软件改动一行代码,几秒钟就能重新部署。AI 项目从数据标注、训练、评估到上线,可能是一周甚至一个月。这就逼着你必须做严格的版本管理和灰度验证,否则你不知道线上模型是变好了还是变差了。
1.3 从零开始的完整路径:先画地图再上路
结合我自己做过的大小项目,从零到一的完整路径大概是这样的:需求澄清与指标定义 → 基线评估与可行性验证 → 数据管道搭建 → 模型训练与迭代 → 离线评估 → 服务化部署 → 线上监控与回归。看起来跟标准流程没区别,但真正执行过的人会告诉你:每一步的坑都比想象中多,后面我会逐个拆解。
2. 选型是第一步,也是最容易翻车的一步
2.1 模型选型:基座模型、微调、还是从零训练?
这是所有人都会遇到的第一个决策。我的建议很简单:能不用大模型微调就不用;能微调就不要从零训练。从零训练一个像样的模型,需要的数据量、算力和调试成本,不是一般团队能承受的。
在实际项目里,我一般按这个优先级来决策:
- 先试试直接调用成熟的基座模型 API,用提示词工程解决问题。很多任务根本不需要微调,提示词写得好就够用了。
- 如果基座模型能力不够,或者有数据隐私要求必须本地部署,再考虑开源模型的微调,比如 LoRA 这种轻量方案。
- 只有当你面对非常特殊的领域、有大规模的数据、并且对延迟和成本极度敏感时,才考虑从零训练——实际上我从业到现在,真正从零训练的项目一只手数得过来。
2.2 技术栈选型:训练框架和推理框架怎么搭配
训练框架的选择相对成熟:PyTorch 基本是事实标准,Hugging Face Transformers 生态也几乎成了社区标配。但推理框架的选型更有讲究,因为同样一个模型,用不同的推理引擎,延迟和吞吐量可能差好几倍。
常见推理方案对比:
| 方案 | 优势 | 适用场景 |
|---|---|---|
| 原生 PyTorch/Transformers | 简单、改动小 | 原型验证、低并发内部工具 |
| ONNX Runtime | 跨平台、优化好 | CPU 部署、边缘设备 |
| TensorRT | GPU 极致性能 | 高并发、低延迟线上服务 |
| vLLM / Text Generation Inference | 专门优化大模型推理 | 大模型服务化、流式输出 |
我个人的经验是:不要一上来就追求最极致的性能方案。先用简单的方案把链路跑通,再根据压测数据决定要不要迁移到 TensorRT 或 vLLM。过早优化是 AI 工程里最常见的资源浪费。
2.3 资源和预算评估:一张表算清楚成本
选型的另一个关键维度是算力成本。很多人忽略了一个事实:GPU 的成本不止是购买价格,还有空闲率、利用率、运维成本。我通常用下面这张表来做预算评估:
| 项目 | 计算方式 |
|---|---|
| 训练总时长 | 数据量 × 轮数 ÷(单卡吞吐 × 卡数) |
| 训练成本 | 总时长 × GPU 时单价 |
| 推理成本/月 | QPS × 平均时延 × 24h × 30天 × GPU 时单价 |
| 显存需求 | 模型参数量 × 2(权重)+ 激活值冗余 |
| 扩容预估 | 按峰值 QPS 的 2~3 倍预留 |
这张表的核心价值不是精确算钱,而是逼你想清楚:这个项目到底是计算密集型还是吞吐量敏感型,你的瓶颈到底在哪。
3. 数据工程:AI 项目的隐形地基
3.1 数据获取与清洗的工程化方法
数据问题在项目初期最容易被低估。很多团队找几个实习生爬数据、手动清洗,最后模型效果差,也说不清是数据问题还是模型问题。我的做法是:把数据获取和清洗当成正式的工程模块来做,有版本、有校验、有日志。
具体来说,数据清洗必须解决这几个问题:
- 格式统一:时间字段、金额字段、ID 字段的格式必须一致,这个最简单但最容易被忽略。
- 去重去噪:同一实体出现多次,需要考虑是保留最新还是合并历史。
- 缺失值处理:是删除、填充还是单独建模,要按特征类型分别决策。
- 异常值识别:用统计方法(如 3σ、IQR)先初筛,再人工抽样确认。
3.2 数据版本管理:为什么 git 管不住数据集
很多团队用 git 管理代码,但数据集仍然拷来拷去,导致模型训练时用的数据和后来别人复现时的数据根本对不上。数据版本管理最轻量的方案是 DVC(Data Version Control)这类工具,它本身不存储数据,只记录数据文件的哈希值,真正的大文件可以放在对象存储或 NAS 上。
我的习惯是:每一次训练实验,都必须记录三个版本号——代码版本、数据版本、配置版本。三个信息拼起来,实验才具有可复现性。否则过两周你看到一份训练日志,根本不知道当时跑了什么。
3.3 标注流程怎么搭建
如果你的项目需要人工标注,这部分一定要尽早工程化。我的经验是:先写一份详细的标注规范文档,再找 2~3 个人各标一 50 条测试样本,计算标注一致性(Cohen's Kappa 或 Fleiss' Kappa),一致性低于 0.7 就说明规范还不够清晰。
标注工具选择上,开源方案可以看 Label Studio,轻量且支持多种标注类型。但工具只是载体,真正的关键是标注规范的版本管理——规范变了,标注的数据质量判断标准就变了,这直接影响模型评估的可信度。
3.4 数据质量评估的量化指标
很多团队直到模型上线才发现数据有问题。为了避免这种情况,我建议在数据管道里内置质量监控,每次数据更新后,自动计算以下指标:
- 字段缺失率
- 类别分布偏移度(对比训练集与线上数据的 KL 散度)
- 新类别出现比例
- 重复率
- 均值/方差漂移
这些指标不复杂,但能帮你提前发现"数据变了"这个信号,而不是等模型效果跌了才回头追查。
4. 训练与微调:跑通之后的漫漫长路
4.1 基线模型先跑通,再谈优化
我的铁律是:第一周的工作目标永远是把最简单的基线跑通,而不是追 SOTA。基线模型可以是规则的、可以是简单的线性模型,也可以是未经调优的预训练模型。它的作用是为后续所有改进提供一个参照系——如果微调后的模型连规则基线都跑不过,说明问题不在模型,在数据或任务定义。
4.2 微调方案:LoRA、全参微调怎么选
微调的选择本质上是在"效果"和"成本"之间做权衡。全参微调效果好,但显存需求高,训练时间长,而且每换一个任务就要重新训练一份完整模型。LoRA 这类参数高效微调方案只训练极少量的低秩矩阵,显存占用和训练时间都大幅降低,效果在大多数场景下已经非常接近全参微调。
我个人的选择标准是:数据量少于 10 万条、任务相对通用,优先 LoRA;数据量大、任务和原模型分布差异大,才考虑全参微调。另外注意,LoRA 训练时学习率一般比全参微调高一个量级,因为实际更新的参数量很少,学习率小了收敛太慢。
4.3 训练过程中的监控指标解读
训练日志里那些指标,很多人只会看 loss。但实际上你至少应该同时关注这几个:
- Train Loss / Eval Loss 的差距:差距过大说明过拟合,需要加大正则或数据增强。
- 每个 batch 的训练耗时:突然变慢通常意味着数据加载卡瓶颈,检查 dataloader 的 prefetch 设置。
- Grad Norm:梯度范数突然爆炸,通常是学习率过大或数据里出现了异常样本。
- 指标曲线的抖动:比如 F1 在训练过程中上下剧烈波动,多半是数据集太小或分布不均匀。
我的习惯是,每次训练都在本地起一个简单的可视化面板,把 loss、学习率、梯度范数、当前 epoch 的评估指标画在一起。中断训练时,快速定位问题出在哪个阶段,比看彩色图表更重要。
4.4 训练失败的常见原因与排查思路
我自己踩过最多的坑有三个:
一是学习率设置不当。transformer 类模型对学习率极其敏感,常见范围在 1e-5 到 5e-5 之间。我通常先用一个很小的步数做"学习率扫描",跑几个小实验,再确定主实验的学习率。
二是数据泄漏。训练集和验证集有重叠,导致评估指标虚高,上线就现原形。这个问题防不胜防,必须用哈希去重从源头掐断。
三是随机性和可复现性。即使设了随机种子,不同设备上的结果也可能不一致。我的做法是:既设固定种子,又在评估时多次采样取均值,降低单次随机波动的影响。
5. 模型部署:从 Notebook 到生产环境的那道坎
5.1 推理服务化的三种方案对比
部署方案没有绝对的好坏,只有适不适合当前阶段。
- 如果只是内部工具或低并发接口,直接用 FastAPI 包一层模型推理是最快的,几分钟就能跑起来。
- 如果要求高可用、自动扩缩容,就需要容器化,配合 Kubernetes 或云平台的托管服务。
- 如果要榨干 GPU 性能,就得用专门的推理引擎做优化,比如 vLLM 的 continuous batching,能显著提升吞吐。
我的建议是:先容器化,别急着上推理引擎。容器化解决的是环境一致和部署标准的问题,这部分是必须的;推理引擎优化是锦上添花,等压测证明有必要再动。
5.2 性能优化:吞吐、延迟、显存之间的博弈
部署阶段最让人头疼的就是性能调优。延迟、吞吐、显存,三者互相牵制,你必须先明确业务优先级:是让单次请求更快,还是每秒处理更多请求?
以一个大模型文本生成服务为例,核心优化点有:
- 并发调度:连续批处理(continuous batching)可以在多个请求之间动态调配显存,显著提升吞吐量。
- KV Cache 管理:长文本生成时 KV Cache 占用主导显存,需要合理设置最大序列长度,超过就拒绝或截断。
- 量化:FP16 降到 INT8,显存减半,速度翻倍,但精度会有轻微损失。对于大部分业务场景,INT8 量化的损失是可以接受的。
我通常的调优顺序是:先压测得到当前性能基线,再量化看精度损失,再调并发配置,最后才考虑换推理引擎。不要跳步骤,否则你无法判断每项优化的真实贡献。
5.3 模型版本管理与灰度发布
模型上线后,一定会经历迭代。所以从第一天就要建立模型版本管理机制。我的做法非常简单:
- 每个模型版本有一个唯一的版本号,对应训练配置、数据版本、评估报告的完整记录。
- 线上同时部署新旧两个版本,按流量比例灰度切换,比如先切 5%,观察指标稳定后再逐步放大。
- 所有推理请求都带一个标识,记录走了哪个模型版本,方便事后分析对比。
这套机制不是锦上添花,而是保命用的。没有它,模型效果回退时你连快速回滚都做不到。
5.4 一个完整的部署实践
举个实际例子:我之前做一个文本分类服务,模型是一个微调过的 7B 参数开源模型。第一次直接裸用 PyTorch 部署,压测显示单卡只能支撑 10 QPS,延迟 1.2 秒,明显不达标。后来做了三步优化:
- 第一步,把模型量化到 INT8,显存从 16GB 降到 8GB,延迟降到 800ms;
- 第二步,引入批处理,把动态打满的请求合并推理,吞吐提升到 35 QPS;
- 第三步,换成 vLLM,利用它的 continuous batching,同样的单卡直接跑到了 90 QPS。
整个过程花了三天。如果一开始就盲目上 vLLM,可能半天就能达到效果,但如果完全不做优化,这个服务就上线不了。所以我想说的是:部署优化的节奏感很重要,不要为了用工具而用工具。
6. 提示词工程与 AI Agent:把模型能力变成业务动作
6.1 提示词工程为什么值得认真对待
很多人觉得提示词就是"写几句好话让模型听你的",但真正的提示词工程是一门系统方法论。我写过上千条生产级提示词之后,最大的感受是:好的提示词不是"文采好",而是结构化地定义任务边界、输出格式、判断标准和兜底策略。
我的提示词模板通常包含五部分:
- 角色定位:告诉模型它是什么角色、服务什么人。
- 任务描述:一句话说清楚要做什么。
- 输入格式:明确输入数据的结构和字段含义。
- 输出约束:指定输出格式(JSON、Markdown、纯文本)、字段类型、是否允许额外解释。
- 边界与降级:明确什么情况不许乱猜、不满足条件时给什么默认回复。
6.2 从单轮对话到多步 Agent 的架构演进
模型本身只能"生成文字",但业务需要的往往是"完成任务"。这里的关键是引入 Agent 模式:把复杂任务拆成多个步骤,每步调用模型做决策、调用工具做执行、观察结果再决定下一步。
我搭建过的 Agent 系统,基本架构是三层:
- 规划层:根据任务目标生成执行计划,可能是固定流程,也可能让模型动态规划。
- 工具层:封装好各类外部能力,比如查数据库、调 API、执行代码。
- 记忆层:记录上下文和中间结果,供后续步骤引用。
单轮对话做不好,就多轮拆解;一个 Agent 不够,就多个 Agent 协作。这是 AI 工程从"模型接入"走向"业务自动化"的必经之路。
6.3 函数调用(Function Calling)的设计要点
想让 Agent 真正干活,函数调用设计比提示词更重要。我总结出让 Agent 稳定调用工具的几条经验:
- 函数命名要自解释,参数不要用缩写。比如
search_order(order_id, start_date, end_date)比query(o, s, e)好得多,模型理解不了晦涩的参数名。 - 函数的描述用 by few-shot 的方式写清楚,最好给一两个使用示例。
- 每个函数的职责要单一,一个函数既查订单又算价格,模型很容易在理解上产生歧义。
- 严格校验工具返回的结果,Agent 拿到异常数据要继续兜底处理,不能让脏数据直达下游。
6.4 多 AI 协作的工作流设计
单个 Agent 的能力终究有限,所以现在越来越多的方案是多个 Agent 分工协作,比如一个负责拆解任务、一个负责检索信息、一个负责生成答案、一个负责质检。这种"多 AI 协作"的设计,本质上借鉴了软件开发的分工思想。
但多 Agent 协作的复杂度是指数级上升的——你需要处理消息路由、任务状态同步、异常转移与重复执行的问题。我的建议是:别一上来就搞多 Agent。先把单 Agent 跑稳,再分析瓶颈在哪一环,然后针对性地把那一环拆出去独立成另一个 Agent。渐进式演进,比一次规划一个大架构靠谱得多。
7. 评估、监控与回归:没有度量就没有 AI 工程
7.1 离线评估:把模型钉死在标准上
模型能不能上线,靠的不是感觉,是评估。离线评估的关键是测试集的构建——测试集必须能代表线上真实分布,不能和训练集重叠,且要包含边界情况。
我会为每个迭代版本准备三类评估样本:
- 历史真实请求:从线上日志里取样,这是最接近真实分布的。
- 人工构造的边界样本:涵盖容易出错的场景,比如空输入、生僻字、极端长度。
- 新版本对比旧版本的差异样本:专门看新旧模型在这些样本上的表现差异,判断改动是否引入了回归。
评估指标不能只看整体指标,还要分场景看。模型整体准确率 95%,但在某个用户群体上准确率只有 70%,这在生产环境里就是事故。
7.2 线上监控:数据漂移、反馈延迟与异常检测
模型上线后,离线评估就不能保护你了。你需要线上监控,至少覆盖三类信号:
- 输入漂移:线上请求分布和训练集分布是否偏移。数值特征看均值方差,文本特征看词频分布,类别特征看类别占比。
- 预测分布漂移:模型的输出分布是否异常,比如突然大量输出同一类结果。
- 业务反馈:用户的点击率、转化率、投诉率是否变化,这是最终的业务指标。
很多人问监控阈值怎么定,我的经验是:先拉取上线前 2~4 周的历史监控数据,用均值±3σ 的方式来设定告警阈值,然后根据实际告警频率不断校准。一开始宁可多告警,也不要漏报。
7.3 回归体系:让每一次改动都可追溯
AI 工程的迭代是常态,但每一次改动的效果必须可衡量。我的回归体系核心是一份"模型体检报告",每次新版本上线前都要跑一遍:
| 检查项 | 指标 | 新旧对比 |
|---|---|---|
| 整体效果 | Accuracy / F1 / 业务指标 | 新版本 ≥ 旧版本 |
| 分场景效果 | 关键子群体指标 | 不得显著回退 |
| 性能 | 延迟、P99、QPS | 不得显著恶化 |
| 稳定性 | 空输入、极长输入等边界 | 新版本 = 旧版本 |
| 安全合规 | 敏感内容拦截率 | 新版本 ≥ 旧版本 |
这套体检报告既是上线门禁,也是复盘依据。没有这套体系,你根本不知道线上效果的波动是模型引起的还是数据引起的。
7.4 AI 测试开发的实际操作
在 AI 工程里,测试开发和传统软件有很大的区别。你不能只写单元测试,还要会写数据测试、模型测试、评估测试。我自己的实践是:
- 数据测试:检查数据缺失率、重复率、类别分布是否在合理区间。
- 模型测试:用固定测试集计算指标,并把指标变化记录到表格里,超过阈值就阻断。
- 链路测试:模拟线上的全流程调用,从接口入口到模型推理到结果返回,确保没有断点。
- 回归测试:每次训练代码或提示词改动,都要跑一遍历史 case 库,防止改一处坏一处。
这套做法工作量并不小,但确实能把很多事故消灭在上线之前。我宁愿在测试上多花时间,也不愿意在线上出事故后花几倍时间救火。
8. 那些绕不开的坑与我的个人体会
8.1 我在实际项目中踩过的真实坑
第一个坑:一上来就追求端到端的大而全方案。我最早做一个项目时,想一步到位搞编排、调度、多服务联动,结果系统复杂到连排查问题都不知道从哪里入手。后来推倒重来,先做最简单的单体服务,一周跑通,后面再慢慢拆分,反而快得多。
第二个坑:模型评估只看整体指标。有一次我做的文本生成模型整体 BLEU 分数提升了,上线之后却发现对特定类型的问题回答质量大幅下降。后来复盘,就是因为离线评估没有拆场景看,没有覆盖该类型样本。
第三个坑:忽视数据版本管理。有一次同事训练模型时说"数据好像换了一版",结果所有调优结论都必须推翻重跑。从那以后,每次训练都用 DVC 记录数据版本,这个习惯挽救了之后无数次的排查时间。
8.2 对零基础起步者的最后建议
如果你正在从零开始搭建 AI 工程能力,我最后想说的是:
- 先做一个完整的、哪怕很小的项目,走完"数据 → 训练 → 部署 → 监控"全链路,比学习十个碎片知识点更有价值。
- 每次实验只改一个变量,否则失败了根本定位不到原因。
- 把评估和监控当成第一步就要建的模块,而不是最后补的功课。
- 不要在项目初期追求完美架构,先用最笨的方法跑通,再基于数据做改进。
我自己走到今天,最大的心得其实就一句话:AI 工程里的所有问题,最终都是工程问题。模型迭代快、框架更新快,但工程化思维、监控意识、可复现原则、回归测试习惯,这些慢变量才是真正决定一个 AI 项目能不能长期走远的关键。先把这些基础打牢,再谈模型效果的提升,你会少走很多弯路。