尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

AI工程化从零起步:数据、基线、评估、部署与监控全链路指南

AI工程化从零起步:数据、基线、评估、部署与监控全链路指南 前阵子帮一个创业团队做技术评审有个片段印象很深。团队里每个人都能把Transformer的注意力机制讲得头头是道PyTorch也玩得很顺可真到要交付一个能用的系统时问题全浮上来了数据散落在各自电脑里模型的加载方式只有本人知道线上效果一波动没人能说清是模型漂移还是数据变了。这其实指向一个很普遍的事实——ai-engineering from scratch难点从来不在AI算法而在工程。如果你正在做第一个AI项目或者打算把实验室里的模型变成一个实际可用的服务这篇文章就是给你写的。它不会复述深度学习教材而是讲清楚从零启动一个AI工程时第一步该做什么、六个核心环节怎么串、最常踩的坑在哪、以及如何用一周时间搭出一个可上线的文档问答系统。全文没有虚构全部来自我过去几年反复做过、拆过、补救过的项目经验。1. 从零到底零在哪先搞清三种起点与三条补课路线1.1 为什么什么都会的团队反而做不出产品算法能力强和工程交付能力强是两个维度的事情。一个人能把模型训练脚本跑起来不代表他能管理一个模型的完整生命周期。工程能力至少包含四块数据处理与版本管理、模型从训练到部署的链路设计、服务上线后的稳定性和可观测性以及基于反馈持续迭代的评估机制。这四块缺任何一块项目都会卡在某个环节反复返工。很多团队demo做得又快又漂亮真正走到每天稳定服务几万次请求这一步就崩了原因不是模型选得不好而是工程地基没打。我常打一个比方跑通模型像是给自己做一顿饭工程化是开一家店。开店要考虑每天稳定出菜、客人排队不崩、食材供应链可靠、菜品口味能持续调整这些事和会做一道拿手菜完全是两种技能。1.2 三种起点和三条补课路线from scratch不代表所有人都要从线性代数开始学。我见过的真实起点大致分三类每一类的补课路线完全不同。起点类型已有能力最缺的能力优先补什么技术管理者业务认知、预算和资源调度对AI工程链路没有手感定不了里程碑和验收标准先理解链路各环节依赖关系学会用风险驱动的方式排期算法工程师模型训练、调参、论文复现服务化、稳定性、数据迭代等工程化经验补推理部署、监控告警、bad case复盘的闭环常规研发团队后端、前端、运维基本功扎实对模型训练和评估体系的陌生补数据准备、模型选型、评估方法和推理优化技术管理者最容易犯的错是照搬传统软件项目的排期方式把模型训练当成一个可以精确预估的常规开发任务。实际上模型效果有很强的不确定性正确做法是先做一个小规模验证确认数据和方案方向对了再投入资源扩量。否则就容易出现团队闷头训了两个月上线效果却不如一个简单规则系统的情况。算法工程师独立做项目时最常见的坑是模型训练完就撒手不管。他们会花很多精力调模型结构、换损失函数却不愿意花半天时间把模型封装成接口、补上日志和监控。可对业务方来说效果下降1个点看不到服务超时5秒钟人人都会感觉到。算法能力是起点工程化习惯才是决定项目能不能持续运行的关键。常规研发团队接AI能力时最大的门槛反而是不知道模型效果怎么评估。服务端、前端、运维的基建都很成熟做常规功能轻车熟路一到AI就慌了因为AI的输入输出不像传统接口那样确定。这个团队最该先补的不是训练大模型而是怎么建立回归测试集、怎么判断一个bad case是修还是忍这套评估方法一旦上手后面接入任何模型都顺。1.3 五分钟自测先定位自己在哪一段不确定自己属于哪一类的话用下面几个问题自测基本能定位短板。你能独立把一个训练好的模型部署成HTTP服务并且设置好超时、重试和并发上限吗线上效果忽然变差你能否在半天内判断是数据漂移、模型退化还是服务故障你的数据是否有一键重建的流程换个新机器别人能不能跑出和你一样的结果你的项目是否有固定的评估集每次模型或提示词改动都能在几小时内看到对比结果吗如果四个问题里有三个以上答不上来那你的问题不在AI理论深度而在工程闭环。后面的内容就是针对这个缺口展开的。2. AI工程链路六件套数据、基线、训练、评估、部署、监控2.1 数据与标注第一道分水岭数据环节决定一个AI项目能走多远这一点怎么强调都不过分。很多项目死在建模之前因为数据根本没准备好格式不统一、标签互相矛盾、样本重复严重、缺失值处理草率。花几周时间处理数据换来后续模型训练和评估的确定性这笔账怎么算都值。起步阶段先定义数据schema把每条样本的字段固定下来比如文本分类至少要包含text、label、source、collected_at这几个字段。清洗规则列成清单逐条执行去重、去HTML标签、过滤空样本、统一编码、纠正明显错别字。洗完之后做一次分布统计看看类别是否均衡、文本长度是否有异常、来源渠道是否过度集中这些统计结果会直接影响你后面的训练策略。训练集、验证集、测试集的划分建议从801010起步但测试集必须是独立且贴近真实分布的。什么意思呢我踩过一个实际的坑某个分类任务的数据集里存在大量完全重复的样本我按随机比例划分后验证集和训练集里各有一半重复内容导致验证分数虚高。后来去掉重复样本再重新切分模型的真实水平才暴露出来。所以切分之前一定要先按内容做去重否则你评估的每一条指标都可能失真。如果项目涉及人工标注一定在正式标注前做标注规范培训和一致性检查。让两个人标注同一批样本计算一致率低于0.8就说明规范描述不清楚需要先修改标注手册再继续。标注一致率直接决定了训练数据的噪声水平噪声太大再好的模型也学不出稳定的规律。2.2 先跑出下限基线方案的作用我见过的AI项目里最容易犯的错误就是一上来就训练大模型。其实正确顺序是先跑一个最简单、最笨但能跑通的基线比如关键词匹配、统计规则或者直接用现成模型API接一下把下限打出来。基线方案的价值在于给后续所有优化提供一个可对比的参照物。我之前做一个客服问答项目先做了一套基于关键词匹配的检索式回答F1做到0.55然后才微调模型最终做到0.78。如果没有这个0.55的基线团队根本说不清楚模型到底提升了多少也没法判断投入算力做微调是否值得。更关键的是基线方案往往能暴露数据里的基础问题。规则系统效果差差在哪些样本上是问法太多样化还是知识库里根本缺少对应内容这类分析可以直接指导你后面是应该补充数据还是应该换更强的模型而不是蒙着头把模型越训越大。2.3 训练与微调资源规划与checkpoint策略训练阶段首先要学会算显存账。虽然具体占用取决于模型结构、batch size和序列长度但可以按一个大致的经验法则估算用混合精度训练一个参数规模为N的模型显存需求大约是2N字节以上其中主要开销来自模型参数、梯度和Adam优化器的状态。用这个粗算7B参数模型的开销已经超过14GB再加上激活值单卡24GB只能小batch起步。batch size炸显存时不必急着换大卡梯度累积是更省钱的解法。设gradient_accumulation_steps4相当于每4步做一次参数更新等效batch size放大了4倍。注意使用BatchNorm这类依赖batch内统计量的层时要谨慎Transformer结构基本不受影响。同时混合精度训练一定要开现代训练框架里基本一行配置的事能省接近一半显存。checkpoint策略是另一个容易被忽略的细节。建议周期性保存模型权重同时把optimizer state一起保存这样中断训练后可以恢复到保存点的状态继续跑而不是从头再来。保存格式用主流框架的标准格式模型和tokenizer分开存避免加载时因为版本不一致报错。日志系统也要跟上每轮的loss、验证指标、学习率曲线都记录哪怕只是本地一个JSON文件。2.4 评估体系不只靠准确率过活单一指标没法支撑AI项目的长期迭代。我习惯建立三类指标任务指标、稳定性指标和成本指标。任务指标就是准确率、F1这类衡量效果好坏的数值稳定性指标衡量多次运行输出的方差同一个输入问三遍得到三个不同答案说明系统不可控成本指标记录延迟、token消耗、GPU占用AI系统的成本往往是持续性的不比一次性训练投入便宜。评估集的构建是评估体系的地基。围绕业务真实场景准备几十到几百条典型样本形成一个固定回归集。每次改动模型、提示词或数据处理逻辑都跑一遍回归集对比新增的bad case和提升的case数量。没有这套机制你所谓的调优其实是在碰运气。bad case的复盘机制更重要。每周固定把线上错误样本汇总起来按错误类型打标比如是模型没找到正确答案检索结果不对用户问法超出预设范围然后针对性补数据和调逻辑。这个机制是AI效果增长真正的引擎很多时候忙了一周效果不涨不是努力不够而是复盘没有形成闭环。2.5 推理部署怎么把模型变成服务模型再强不能对外提供服务就没有实际价值。一步到位的做法是用FastAPI这类轻量框架做接口封装模型加载一次常驻内存通过HTTP对外提供调用。下面是最小可用示例。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class ChatRequest(BaseModel): question: str history: list [] app.post(/chat) def chat(req: ChatRequest): answer call_llm_with_context(req.question, req.history) return {answer: answer}这只是骨架实际部署时要补上的东西包括请求超时设置、失败重试策略、并发上限、请求日志和鉴权。线上环境如果追求极致性能会用Triton这类专门的推理服务器但对多数项目来说FastAPI加适当的并发控制已经够用。如果模型是要给外部用户直接用的建议走异步接口用户提交后返回任务ID生成完成后再轮询取结果避免长时间占用连接。推理优化还要考虑是否量化。量化的目标是把模型压小、跑快但对效果的影响必须实测评估。低比特量化如INT8配合校准集通常能接受盲目用低比特量化可能让效果明显退步这部分在第3章展开讲。2.6 线上监控上线才是一切的开始很多团队把模型上线当成终点其实恰恰是起点。线上环境的数据分布和训练集总有差异用户行为还会实时变化不监控就无从知道系统何时会退化。基础指标先盯这几项QPS、p95延迟、错误率、GPU利用率和推理token数。QPS和延迟反映服务能力错误率反映稳定性GPU利用率帮你看资源是否浪费token数直接和成本挂钩。数据漂移检测可以做但不需要太复杂定期对比线上输入的长度分布、关键词频次和训练集的差异就能发现问题。用户反馈层一定要埋点哪怕只是一个简单的回答是否有帮助的按钮都是宝贵的数据反馈信号。告警规则可以简单粗暴一点p95延迟超阈值、连续多个请求失败、输入长度分布突变都发告警。真正好的AI系统不是上线后效果永远不变而是效果变了你能第一时间知道并定位原因。3. 五个高频工程坑从加载报错到并发被打爆3.1 checkpoint加载时报key mismatch先分清missing和unexpected坑的场景很典型你训练了一个模型隔了一周重新加载结果报了一堆key mismatch。新手第一反应是模型坏了其实问题通常出在三处加载的state_dict和模型结构对不上保存时混入了分布式训练的前缀或者模型结构改过但checkpoint是旧的。排查链路不难关键在于先分清missing和unexpected。import torch model build_model() raw torch.load(checkpoint.pt, map_locationcpu) state model.state_dict() missing set(state.keys()) - set(raw.keys()) unexpected set(raw.keys()) - set(state.keys()) print(missing:, sorted(missing)) print(unexpected:, sorted(unexpected))missing是指新模型里有但checkpoint里没有的键说明checkpoint对应的旧结构少了一些层通常是把某些层冻结或结构变更了。unexpected相反说明checkpoint里有新模型不需要的键常见原因是保存时用了DataParallel或DistributedDataParallel权重名多了module.前缀。修复方式也很简单加上module.前缀或去掉前缀再做键映射。补充一个小经验加载时优先考虑用strictFalse把缺失的键单独处理避免一次报错导致全部状态加载失败。3.2 一调大batch size就OOM显存溢出是训练阶段最让人烦躁的问题。很多人第一反应是换更大的显卡但大多数情况下并不需要。首先用torch.cuda.max_memory_allocated()看显存峰值确认到底是哪步把显存顶爆了。通常OOM的元凶有两个batch size过大或者序列过长。序列方向的浪费经常被忽视一篇文章长短差异悬殊padding到同样长度时短文本浪费的大量显存是隐形的。修复优先级很明确先开混合精度训练一般能省一半左右的显存然后减小batch size并配合梯度累积来恢复等效batch大小再给输入序列设置合理的最大长度超长的部分用截断策略。如果还是不够再考虑CPU offload或换更小的模型。我不建议一上来就用gradient checkpointing它虽然省显存但会拖慢训练速度能靠前两步解决就别上它。3.3 量化之后效果明显变差量化压缩模型体积、提升推理速度但效果变差不是必然结果多数时候是量化方式选错了。动态量化对激活值的处理比较粗糙对某些任务损失就大静态量化需要一组校准集来统计激活值的分布校准集选得没有代表性量化后的效果自然崩。另外per-tensor和per-channel两种粒度的效果差异也很大通常per-channel能保留更多精度。排查链路是这样的先在量化前后跑同一批测试样本逐条对比输出分布的差异确定损失集中在哪些类型的输入上再检查量化策略如果是静态量化就重新准备更有代表性的校准集混合多种来源的真实请求最后可以考虑只量化部分层比如把耗时大户的矩阵乘层量化其余层保持高精度往往能在体积和效果之间取得平衡。量化这件事策略比工具重要。3.4 并发一上来GPU排队长到天边推理服务的性能瓶颈和训练不一样。GPU本身是串行计算的多个并发请求同时到达时如果没有合理的排队和调度机制后面的请求就只能等着p95延迟直接爆炸。这个坑的症状很典型单个请求延迟正常并发稍微一多就超时看起来像是服务挂了其实只是队列堵死了。排查时先看GPU利用率如果长期接近100%且请求排队数持续上升说明容量确实到了极限。修复思路按性价比排序第一加缓存重复问题直接命中缓存答案能挡掉相当比例的请求第二做限流超出容量的请求直接返回提示或排队避免系统全面崩溃第三启用批处理推理把多个请求合并成一个batch喂给模型吞吐量能明显提升最后才考虑加副本或换高性能GPU。花大价钱扩GPU之前先问问自己缓存做到位了吗。3.5 输出忽好忽坏用户没法信任你大模型推理的随机性是个老问题。同一个问题问三遍答案风格和内容都不稳定业务方和用户都会觉得系统不可靠。这个问题的根因通常是生成参数里temperature没有设置为0或者是提示词和模型版本在线上被悄悄换过又或者是看似无关的输入分布变化影响了生成质量。修复要做的三件事第一线上推理的temperature统一设为0必要时固定随机种子把非确定性降到最低第二提示词模板和模型版本要纳入版本管理任何改动必须先跑回归集再上线第三对输出做模式校验比如规定答案必须包含某个字段、必须是JSON格式解析失败就自动重试一次或走兜底逻辑。我处理过很多次效果飘忽的反馈排查到最后往往是某个临时调试时改过的参数没改回来版本管理和参数固定能规避掉这类大量低级问题。4. 一周从零搭出一个可上线的文档问答系统4.1 每天做什么七天排期表想验证自己有没有掌握前面说的链路最直接的方式就是做一个完整项目。以文档问答系统为例我给一个可复用的七天排期工作强度适中每天大约四到六小时。天数目标交付物Day 1-2数据准备与切割清洗后的文本库、chunk文件、数据统计报告Day 3检索服务搭建Embedding接口、向量库、检索脚本top_k可调Day 4生成服务接入提示词模板、大模型接口封装Day 5API封装与会话管理FastAPI服务、请求日志、会话上下文管理Day 6评估与调优回归集、对比测试、参数调整记录Day 7部署与监控Docker镜像、服务上线、日志和基础指标监控这个排期前端两天最难熬很多人急着想跑模型结果发现数据不够干净、chunk切得不合理检索质量上不来。前两天的数据功夫越扎实后面几天的调优就越省力这个顺序不要颠倒。4.2 工具选型的取舍选型阶段最容易让人纠结我直接给出几组实测下来比较稳的搭配。先看Embedding模型。追求效果和速度平衡BGE系列的中文表现不错有不同规格可选数据敏感度不高的话也可以直接用云端Embedding API省掉本地GPU占用。向量库方面原型阶段用Chroma最快一行pip安装、本地文件存储进入生产则建议换Qdrant或Milvus支持更完善的过滤和水平扩展。大模型这一环的选择要么接大厂的API效果稳定、成本可控要么本地部署开源模型比如Qwen系列数据完全在内部但需要准备GPU资源和推理服务。环节快速验证方案生产级方案Embedding云端API或BGE小模型BGE中大规模模型或微调后的embedding模型向量库ChromaQdrant或Milvus生成模型大厂API本地部署开源模型或私有化API提示词模板的设计也有讲究。文档问答系统建议的模板结构是系统指令 检索到的上下文片段 历史对话 当前问题。上下文片段要标注来源让模型知道自己在引用哪些文档回答时可注明出处可追溯性非常重要。4.3 成本账本地部署还是调API预算敏感的项目这个账一定要先算清楚。我按一个中小型内部工具的量级估算了一个对比表给个大致感觉具体数字随市场价格浮动。方案月度成本区间适合场景全云端API几百到一两千元按token用量计快速验证、数据不敏感、用量不大混合方案千元级加上少量GPU开销需要一定数据控制希望保留生成效果弹性全本地部署每月数千到上万元GPU云主机或自购硬件数据敏感、合规要求高、用量大对多数团队来说第一版用全云端API把链路跑通是最划算的。等确认了业务价值、摸清了调用量再决定要不要上本地部署。很多人一上来就想买GPU服务器结果数据量还没到那个量级钱先烧了不少。工程化有一个很重要的原则用最少的资源验证最大的风险。5. 从跑通到能上线工程化的三个转变5.1 可观测性让每个环节都留痕工程化思维和脚本思维最大的区别就是能不能回答现在系统发生了什么。日志里要有请求ID一条请求从进入服务到完成检索、生成、返回的全链路每个环节都打印时间戳和状态。结构化日志比纯文本日志更有用JSON格式的日志可以直接被采集工具解析后续排查问题时效率高得多。服务指标按标准接入Prometheus这类监控体系自定义指标也不复杂请求总数、错误计数、耗时直方图、token消耗量。这些指标配合告警规则构成了系统的仪表盘。没有仪表盘的AI系统就像蒙眼开车效果好不好全靠用户投诉才知道。5.2 可回滚模型、提示词、数据都要有版本传统开发讲究代码版本管理AI工程里要管住的东西更多模型权重、提示词模板、数据处理脚本、评估集全部都要有版本。每一次改动都对应一个可描述、可对比、可回滚的版本记录这是AI工程化的核心习惯。我实际工作是这么做的数据处理之前把原始数据按日期快照训练脚本固定依赖环境训练产物按实验名加时间戳命名提示词模板写进配置文件而不是散落在代码里。模型服务化上线时每份模型权重对应一个版本号线上出问题可以在几秒内切回上一个版本而不是手忙脚乱地找备份。5.3 代码结构从脚本到代码库的进化一个人的脚本项目所有代码堆在一个notebook或一个py文件里勉强能跑。一旦要多人协作或长期迭代代码结构一定要分层。我习惯的项目目录大概是这样的data层负责数据采集、清洗、切分和版本管理model层负责模型定义、训练和评估serve层负责推理服务、API封装和并发控制config层集中放所有可调参数。目录划分不用太复杂关键是让换数据换模型换服务这三件事互不干扰。这里给一个结论性的建议工程化不必一步到位但至少从第二个版本开始就得按这个方向走。第一版可以糙、快、能用第二版再不上工程规范后面每迭代一次都要付更多的返工代价。5.4 回到开头什么才是真正的from scratch做了这么多项目之后我越来越觉得from scratch的真正含义不是从零开始搭技术栈而是从零开始建立一套能持续迭代的方法论。你第一天拿到的数据是零乱的第一版模型是粗糙的第一轮评估结果可能是难看的——这些都不重要重要的是你有没有一条管道能把零乱的变成规整的把粗糙的变成可调优的把一次性的变成可持续的。我个人体会最深的一条经验是工程化不需要发生在项目开始之前而应该伴随着第一个可用版本同步长出来。先允许自己做出一个跑通但粗糙的v0.1然后逼自己在v0.2之前把数据、模型、服务、监控的骨架全部立好。这样每次迭代都踩在确定性的地基上而不是每次都在重新发明轮子。真这么坚持下来的项目没有一个被烂尾的。
返回列表