首页 / AI教程 / 正文
AI教程

模型微调教程:零基础避坑,从LoRA配置到部署一次跑通

chuanbook chuanbook
发布于 2026 年 10 月 18 日
阅读 约22分钟
浏览 1
评论 0

我头一回接触“微调”这个词,是在一个做客服系统的朋友那里。他拿着一份几十页的产品手册问我,能不能让模型把这些内容全背下来,回答用户问题时别老跑偏。我当时的第一反应是——直接塞进提示词里不就行了?后来才发现,事情没那么简单。这几年我自己从折腾小模型到上手 LoRA,踩过的坑比走过的路还多。这一章我想把入门阶段最容易糊里糊涂的几个概念掰开聊聊,顺带把环境和数据这两件“脏活累活”讲清楚。很多人一上来就想训大模型,我觉得先搞清楚你在解决什么问题,比会敲几条命令重要得多。

1.1 模型微调是什么:与提示工程、RAG、全参微调的边界与选择

我经常被问到的一个问题是:“模型微调到底跟写提示词有啥区别?”打个比方,提示工程像是给一个刚入职的员工写工作手册,你得把要求一条条列清楚,他照着做;微调更像是在岗培训,让模型自己从大量例子里学会那种“手感”。提示工程不改变模型权重,成本低、见效快,适合任务边界清晰、输入格式稳定的场景。微调会动到模型参数,把领域知识或者特定风格“焊”进模型里,适合那些提示词怎么写都差口气的任务。

RAG 又是另一条路。它不在模型内部做改动,而是把外部知识库当成一本随时能翻的参考书,检索到相关段落再让模型基于这些内容作答。我做过的项目里,RAG 最适合知识频繁更新、需要引用出处的场景,比如法律咨询、内部文档问答。微调的强项在于“模式”的固化——输出格式、语气风格、推理路径这些靠检索很难兜住的东西。我自己的经验是:能用提示词解决就别上微调,需要外部实时知识就优先考虑 RAG,只有当模型必须“长”出某种稳定的行为模式时,微调才真正划算。

全参微调是微调里最“重”的那一档,把模型所有参数都放开训练。效果上限高,代价是显存和算力都要求极高,一个 7B 模型全参微调基本得按 A100 级别来算账。我早期试过一次,光配环境就折腾了两天,最后还是因为显存不够退回小模型。对绝大多数个人开发者和中小团队来说,PEFT 这类参数高效微调才是现实答案,LoRA 就是其中的代表,后面第三章会展开讲。选哪条路,我通常看三件事:任务需不需要改变模型的内在能力、数据量够不够撑起训练、预算允不允许反复试错。

1.2 常见微调任务与数据形态:分类、生成、指令跟随、领域问答

任务类型这件事,我吃过没想清楚的亏。有次接了个需求,对方说“帮我做个智能分类”,我拿到数据才发现,他们想要的是给出分类理由再判断,本质是生成任务套了个分类的壳。分类任务的数据形态很直白,一条文本配一个标签,训练目标是让模型输出正确的类别。这种任务通常数据量要求相对小,评测也简单,准确率、F1 就能说明问题。生成任务就麻烦一些,输入输出都是自由文本,比如摘要、改写、报告生成,评测往往得靠人工或者组合指标。

指令跟随是我觉得最值得投入的一类。它的数据是“指令 + 输入 + 期望回答”的三元组,核心目标是让模型学会听懂人话、按要求办事。这类数据做得好,模型泛化能力会明显提升,遇到没见过的指令也能应变得体。领域问答则更偏知识注入,数据形态是问题搭配标准答案,难点在于答案要准确且风格统一。我做过一个医疗问答的小项目,最头疼的不是训练,而是标注答案的口径不统一,同一个问题三个人写出三种说法,模型学出来自然四不像。

说句实在话,任务类型决定了你后面所有工序。数据怎么洗、指标怎么定、模型多大合适,全都跟着任务走。我在动手前会先做一件事:拿二十条真实样本,手动写出理想输出,再问自己“这种输出能不能用规则或提示词逼近”。能,就先别训。不能,再考虑微调。这个习惯帮我省下过不少冤枉的算力钱。

1.3 工具链与硬件评估:Transformers、PEFT、TRL、显存与成本估算

工具链这块,入门阶段其实不用贪多。Transformers 是地基,模型加载、tokenizer、推理这些基础操作都靠它,先把这套玩熟比什么都强。PEFT 是我日常用得最多的库,LoRA、QLoRA 这些方法它都封装好了,接口也算友好。TRL 偏向训练流程管理,SFT、DPO 这类训练范式它都有现成实现。我建议新手按“Transformers → PEFT → TRL”这个顺序来,别一上来就同时开三个坑。

硬件评估是个容易被低估的环节。我见过太多人兴冲冲下载了个 13B 模型,结果笔记本直接卡死。粗算显存有个经验公式:全参微调的显存大概是参数量乘上十几到二十倍字节,LoRA 能压到几倍,QLoRA 再往下降一档。7B 模型做 LoRA,24G 显存的卡基本够用;要是只有 16G,就得靠 4bit 量化或者减小 batch size 硬挤。云上按小时计费的话,我一般会先跑个几十步的小实验,看看显存峰值和吞吐,再决定租多久。

成本这事得算总账。显存只是一部分,数据标注、反复实验、推理部署都在烧钱。我自己有个土办法:先拿最小的模型跑通全流程,确认数据和脚本都没问题,再换成大模型。小模型跑一次可能就十几分钟,大模型一次几小时,试错成本差着数量级。别嫌小模型效果差,它验证的是流程,不是最终效果。

1.4 数据集构建与质量检查:数据格式、清洗、划分、标注与评测基线

数据是微调里最不性感、却最决定成败的部分。我见过的失败案例里,七成以上问题出在数据上,而不是模型或超参。格式上,我习惯统一成 JSONL,每行一条样本,字段名固定下来,后面写脚本、做转换都省心。指令数据一般是 instruction、input、output 三个字段,对话数据则是 messages 数组。格式统一了,清洗和检查才有得谈。

清洗这事儿,机器能干的先交给机器。去重、去空、过滤超长样本、检查编码乱码,这些用脚本批量过一遍。剩下的得人工看,尤其是答案质量。我通常会随机抽五十条逐条读,读的时候问自己两个问题:这条答案我愿意让模型学吗?它跟其他样本的风格一致吗?不一致的地方往往就是标注口径出了问题。划分数据集时,训练集、验证集、测试集要严格分开,同一来源的相似样本最好别跨集,不然验证集分数虚高,上线就露馅。

评测基线这事我吃过亏。有次微调完觉得效果不错,一对比原始模型才发现,人家本来就在这个任务上表现不差,我折腾半天提升了个位数百分点。从那以后我养成了习惯:动手前先测原始模型在验证集上的表现,记下数字当作基线。没有基线,你根本不知道自己是在进步还是在原地打转。标注环节也是同理,先标一小批做一致性检查,几个人标同一批数据,看看分歧大不大,分歧大的地方就是标准需要细化的地方。

1.5 入门学习路径与避坑指南:先跑通小模型、再迁移大模型

学习路径我特别想强调“先小后大”这四个字。很多人一入门就盯着 70B,觉得模型越大效果越好,结果环境配不起来、训练跑不动、报错看不懂,热情三天就耗光了。我的建议是拿 0.5B 到 1B 级别的小模型起步,显存压力小,一次训练几分钟就能出结果,你能快速把数据、脚本、评测这条链路走通。链路通了,换模型只是改个名字的事。

避坑这块,我列几个自己踩过的。第一个坑是对话模板没对齐,训练时用的模板跟推理时不一致,模型输出全是奇怪的符号,排查了大半天才发现是 tokenizer 的 chat_template 没设对。第二个坑是学习率照搬别人的配置,任务不同、数据量不同,学习率差别很大,我一般从 1e-4 到 2e-5 之间试。第三个坑是忘了设随机种子,两次跑出来结果对不上,还以为是代码有 bug。

还有个心态上的坑。微调不是万能药,有些问题根源在数据或者任务定义上,训多少轮都没用。我现在遇到效果不理想,会先回去翻数据,而不是急着调参。小模型跑通、基线测好、数据看几遍,这三件事做扎实了,后面的路会顺很多。入门阶段别追求一步到位,能把一个最小可用的流程跑起来,就已经赢过大多数人了。

我记得第一次真正把微调跑起来那天,盯着终端里滚动的日志看了快二十分钟。loss 从 2.3 慢慢掉到 1.1,心里那个美。结果第二天想复现一下,发现连上次用的学习率都记不清了,更别提对话模板改过哪一版。那次教训让我明白,从“能跑”到“能复现”,中间隔着的不只是几条命令,是一整套工程习惯。这一章我拿一个具体项目当线索,把数据准备、模型加载、训练管理、评测部署这几段路完整走一遍。走完你手里应该有一个别人能拿去重跑的实验,而不是一堆散落在 notebook 里的碎片。

2.1 实战项目选择与目标设定:业务场景、评价指标与验收标准

项目选择这事我吃过贪心的亏。最早我想做个“全能助手”,什么任务都往里塞,结果数据乱七八糟,评测也说不清好坏。后来学乖了,我选项目有个原则:场景要窄,价值要清晰。比如你在一家做智能硬件的公司,客服每天要回答大量“设备连不上网”的问题,这就可以做成一个意图分类加回复生成的微调任务。场景窄的好处是样本容易收集,评价指标也好定。

目标设定我会逼自己写下一句话:这个模型上线后要解决什么具体问题。拿上面那个客服场景举例,目标可以是“把常见连接问题的首次解决率从 60% 提到 80%”。有了这句话,评价指标自然就浮出来了——意图分类看准确率和召回率,回复质量看人工打分或者跟标准答案的相似度。指标定完还得设验收标准,比如“测试集准确率不低于 85%,人工抽检合格率不低于 90%”。没有验收标准,训练到什么时候算完全凭感觉,这是很危险的。

我还想提一个容易被忽略的点:业务场景里往往藏着很多“异常输入”。你在测试集里放的都是干净问题,上线后用户可能发来一句“我家猫把路由器咬了怎么办”。我现在的做法是在验收标准里加一条“对分布外输入的拒答或澄清率”,逼着自己提前想清楚模型遇到没见过的输入该有什么表现。这一条比单纯追准确率有用得多。

2.2 基座模型加载与训练配置:tokenizer、对话模板、超参数与日志

加载模型这件事,看着简单,坑却不少。我一般用 Transformers 的 from_pretrained 加载,模型名和 revision 都会写清楚,不用 latest 这种模糊标签。tokenizer 得跟模型配套,这个大家都知道。真正麻烦的是对话模板。我踩过最惨的坑是训练时用了一套模板,推理时忘了设,模型输出一长串奇怪的特殊符号。后来我养成了一个死规矩:把 chat_template 打印出来看一眼,跟训练数据格式化时用的模板逐字对照。

对话模板对齐之后,超参数配置我会单独写成一个 config 文件,而不是散在脚本里。学习率、batch size、梯度累积步数、warmup 比例、训练轮数,每项都配上注释说明为什么选这个值。我自己的经验值是这样的:LoRA 微调学习率从 1e-4 到 5e-5 之间起试,batch size 受显存限制就先设小再靠梯度累积补。有个细节很多人不注意,梯度累积步数会影响有效的 batch size,算 loss 的时候要心里有数。

日志这块我想多说两句。我见过太多人只打印 loss,其他什么都不记。我现在的做法是训练一开始就把所有配置写进一个 run_config.json,包括模型名、数据路径、随机种子、超参数、代码版本号。训练过程中每步记录 loss、学习率、显存峰值,每隔一定步数在验证集上算一次指标。这些日志统一存到实验目录下,命名带时间戳。听起来有点繁琐,等你要对比三次实验的时候,会感谢自己当初多写了这几行代码。

2.3 训练过程管理:loss 曲线、验证集、早停、checkpoint 与复现实验

loss 曲线是训练的仪表盘,但它会骗人。我遇到过一次训练 loss 一路降到 0.3,我挺高兴,结果验证集指标纹丝不动。回头一查,训练集和验证集有重叠样本,模型在背答案。从那以后我看 loss 曲线会同时盯两条线:训练 loss 和验证 loss。两条线一起降是好事,训练降验证不降甚至往上走,基本就是过拟合或者数据泄漏的信号。

验证集的用法也有讲究。我一般每训练一两百步跑一次验证,记录指标。验证指标连续几次不提升就触发早停,同时保存当时最好的 checkpoint。checkpoint 保存我习惯保留最近三个加上验证指标最好的那一个,磁盘空间允许的话再加上每个 epoch 的存档。这样万一后面发现评测脚本有 bug,还能回滚到之前的权重重新评。

复现实验是我现在最看重的一环。具体做法是固定随机种子,记录所有依赖包的版本,数据和代码都纳入版本管理。我有一次复现失败,排查了半天发现是数据加载时 shuffle 的顺序受多线程影响,换了台机器结果就对不上。解决办法是给数据加载器设 worker 数和种子。这些细节写出来显得琐碎,可正是这些琐碎决定了你的实验能不能被别人重跑出来。我现在的标准很简单:换一台干净的机器,照着 README 跑一遍,指标差距在合理范围内波动,才算复现成功。

2.4 模型评测与推理部署:自动指标、人工评估、合并导出与服务化

评测这件事我分成两层来做。自动指标负责快速筛选,人工评估负责把关质量。自动指标我常用准确率、F1、ROUGE 这类,具体看任务类型。它们的好处是快,训练完几分钟就能出结果,适合在多次实验之间做粗筛。局限也很明显,生成任务的自动指标跟人感受经常对不上,模型回答读起来别扭,ROUGE 分却挺高。所以自动指标过关之后,我一定会做人工评估。

人工评估我会设计一个简单的评分表,从准确性、流畅度、有用性三个维度各打一到五分,随机抽五十到一百条测试样本,找两三个人独立打分。打分之前先一起看几条样本对齐标准,不然每个人尺度不一样,分数没法用。这一步花时间,但能暴露出自动指标看不到的问题,比如模型学会了某种固定的开头句式,每条回答都“当然可以,我很乐意帮您”,读多了让人烦。

部署这块,我一般先把 LoRA 权重合并回基座模型,导出成标准格式,再用推理框架起服务。合并前记得在验证集上再跑一次,确认合并前后输出一致。服务化的时候我会加上超时和最大生成长度限制,防止某些输入让模型一直生成下去。上线初期先小流量灰度,盯着延迟和错误率,同时收集真实用户的输入样本,这些样本是下一轮迭代最宝贵的数据。

2.5 常见报错与调参清单:显存溢出、loss 异常、数据泄漏与过拟合

显存溢出大概是新手遇到最多的报错。我自己的排查顺序是这样:先看 batch size 能不能降,再看序列长度是不是设太长了,然后考虑开梯度检查点或者用 4bit 量化加载。有次我模型不大、数据也不长,还是爆显存,最后发现是验证阶段没关梯度计算,白占了一大块显存。这个坑很隐蔽,eval 的时候记得包一层 torch.no_grad。

loss 异常分两种。一种是 loss 完全不降,大概率是学习率太小或者数据格式有问题,我会先把学习率调大一个数量级试试,顺便打印几条格式化后的训练样本看看长什么样。另一种是 loss 突然变成 nan,常见原因是学习率太大、数据里有空样本或者梯度爆炸,我会加上梯度裁剪,检查数据里有没有空字段。这两种情况我都遇到过,排查起来其实不复杂,关键是别慌,一步步缩小范围。

数据泄漏和过拟合是一对难兄难弟。数据泄漏的表现是验证指标好得离谱,测试集一上就露馅。我的检查方法是在划分数据集时按来源分组,同一来源的样本只出现在一个集合里,再手动看几条验证样本有没有在训练集里出现过类似表述。过拟合的表现是训练 loss 很低、验证 loss 抬头,应对办法是加 dropout、减小模型可训练参数量、增加数据或者早停。调参这事我现在的态度比较克制,一次只改一两个变量,改完记录结果,不然最后都不知道是哪个改动起了作用。

我第一次听说 LoRA 的时候,以为又是个花架子。全参微调我也跑过,效果确实好,可那显存消耗和训练成本让我这种用消费级显卡的人直接劝退。后来硬着头皮把 LoRA 的论文翻了两遍,又拿一个小模型亲手试了一轮,才明白这东西火得有道理。它不碰原来的权重,只在旁边搭几个小矩阵,训练参数量能压到原来的百分之一甚至更少。这一章我打算把 LoRA 从原理到落地讲透,包括我怎么选参数、怎么调脚本、怎么判断效果,还有 QLoRA 这种省显存的玩法。中间会穿插一些我踩过的坑,有些坑挺蠢的,但我觉得说出来比藏着有用。

3.1 LoRA 原理与适用场景:低秩分解、r/alpha/target_modules 选择

LoRA 的核心思路用一句话就能说清楚:冻结基座模型的所有权重,在特定的线性层旁边注入两个小矩阵,用它们的乘积来模拟权重更新量。原来的权重矩阵是 d×k 那么大,LoRA 把它拆成一个 d×r 的矩阵乘一个 r×k 的矩阵,r 远小于 d 和 k。训练的时候只更新这两个小矩阵,推理的时候把它们的乘积加回原权重就行,不增加任何推理延迟。我第一次读懂这个设计的时候拍了下大腿,太干净了。

r 的选择是第一个要动脑子的事。r 是低秩分解的秩,越大表达能力越强,可训练参数也越多。我自己的经验是任务越接近基座模型原本的能力,r 可以越小。做风格迁移、格式调整这类任务,r=8 或者 r=16 通常够用。做领域知识注入、复杂指令跟随,我会把 r 拉到 32 甚至 64。alpha 这个参数控制 LoRA 更新量缩放,常见做法是设成 r 的两倍,也有人直接用 r。我试过 alpha 等于 r、2r、4r 几组配置,差距不算大,但 alpha 太小的时候学得慢,太大会让训练不稳。

target_modules 是我觉得最容易被低估的一项。默认很多人只对 q_proj 和 v_proj 加 LoRA,这确实能省参数。我做过对比,把 k_proj、o_proj、gate_proj、up_proj、down_proj 都加上,参数量涨了三四倍,可复杂任务的收敛速度和最终效果明显好一截。显存允许的话,我现在的习惯是覆盖注意力层和 MLP 层的主要线性层。有一种情况我会刻意收窄,就是数据量很小、任务很简单的时候,加太多层反而容易过拟合。

适用场景这块我想说点实在的。LoRA 特别适合我这种硬件有限、又想快速迭代的人。同一个基座模型,我可以训十来个不同任务的 Adapter,每个几百兆,换着加载就行,不用为每个任务存一份完整模型。不适合的场景也有,比如你要做词表扩展、要改模型结构,LoRA 就使不上劲了。还有一种情况是全参微调效果确实更好,数据量大、算力充足,那也没必要硬上 LoRA。工具是拿来用的,不是拿来供着的。

3.2 LoRA 微调详细步骤:环境安装、数据格式化、训练脚本与参数设置

环境安装这一步我建议单独建一个虚拟环境,别跟其他项目混。我常用的是 conda 建环境,Python 版本选 3.10 或者 3.11。核心依赖就几个:torch、transformers、peft、datasets、accelerate、trl。版本号我一般会锁死,写在 requirements.txt 里,尤其是 peft 和 transformers 的版本匹配,这块出过好几次兼容性问题,折腾了我一晚上。安装完先跑一个 import 测试,确认没有报错再往下走。

数据格式化是 LoRA 微调里最花心思的部分。我按任务类型分两种处理方式。指令微调的数据我组织成 instruction、input、output 三个字段,套进模型对应的对话模板里。对话微调的数据我写成多轮 messages 列表,每条带 role 和 content。格式化的时候我会把模板打印出来看,确认特殊 token 的位置对不对。有一次我忘了在输出末尾加 eos token,模型训练完不知道什么时候该停,生成的时候一直往外蹦字,这个坑挺典型的。

训练脚本我现在习惯用 peft 加 transformers 的 Trainer 来写,结构清晰,也方便改。关键参数我列一下自己的常用起点:学习率 2e-4,batch size 看显存,一般设 4 到 8,梯度累积步数补到有效 batch size 32 左右。lora_dropout 设 0.05 到 0.1,warmup 比例 0.03。训练轮数我一般从 3 轮起试,数据量少的时候加到 5 轮。优化器用 adamw_torch,混合精度开 fp16 或者 bf16,bf16 在支持的卡上更稳。

脚本里我会额外加几行代码,打印可训练参数占比。LoRA 训练的可训练参数通常在总参数的 0.1% 到 2% 之间,超出这个范围我会回头检查 target_modules 是不是设多了。还有一行是保存 tokenizer 和 chat_template,跟 Adapter 权重放在同一个目录。这个习惯是之前推理时模板对不上逼出来的,现在成了肌肉记忆。训练启动前我会先拿十条样本做一次前向,确认 loss 能正常算出来,再开始正式训练。

3.3 训练监控与效果分析:指标对比、消融实验、Adapter 管理与权重合并

训练启动之后我盯的东西比全参微调多一些。除了 loss 曲线,我会同时记录可训练参数的梯度范数,LoRA 层梯度爆炸的情况虽然少见,但不是没有,梯度裁剪我一般设 1.0。验证指标我沿用上一章那套流程,每两三百步跑一次,存最好 checkpoint。有一点区别是 LoRA 的验证 loss 有时候波动比较大,我会多看几个点再判断,不因为单次波动就停掉训练。

消融实验是 LoRA 调优里性价比很高的动作。我一般固定数据和训练步数,只改一个变量做对比。比如固定 r=16,比较 alpha 设 16 和 32 的效果。或者固定 alpha,比较只加 qv 和全加线性层的差异。每次实验记录在表格里,标清楚基座模型、数据版本、超参数和最终指标。这张表攒下来就是自己的经验库,下次遇到新任务能少走很多弯路。我最早懒得记,后来想复现某次好结果却找不到配置,才开始老老实实填表。

Adapter 管理是个工程活。我按任务名加日期加版本的规则命名目录,比如 customer-service-lora-20240512-v2。每个目录里放 adapter_config.json、adapter_model.bin、tokenizer 相关文件和一份训练配置。加载的时候从配置里读基座模型名,避免手动填错。多个 Adapter 可以共用一个基座模型,用 peft 的加载接口按名字切换,显存只占一份基座加各自的小权重,这个机制在多任务场景下特别省资源。

权重合并我会在验证集评测通过之后做。peft 提供了 merge_and_unload 方法,把 LoRA 权重加回基座,导出一个完整的模型。合并前我在验证集上跑一遍原始 LoRA 模型的输出,合并后再跑一遍,对比两者是否一致。有一次合并后输出完全乱掉,排查发现是加载 Adapter 时没指定正确的基座模型版本。合并后的模型文件大很多,但推理时不用再加载 peft 库,部署链路更简单。两种形态我一般都会保留,按部署环境选。

3.4 领域适配与多任务实践:指令微调、对话微调、QLoRA 显存优化

领域适配是 LoRA 最见功力的地方。我做过一个医疗问答的微调,基座模型是通用对话模型,数据是几千条医生回答整理成的问答对。指令微调的方式是把问题包成指令模板,让模型学会用专业语气回答。这里有个细节值得说,我在数据里刻意保留了一部分“我不确定”的回答,训练完模型遇到超出范围的问题会老实说不知道,而不是硬编一个答案。这种拒答能力在专业领域比多答对几道题更重要。

对话微调比指令微调复杂一些,因为要处理多轮上下文。我常用的做法是把整个对话历史拼成一条训练样本,只在最后一轮助手的回复上算 loss,前面的轮次 mask 掉。这样模型学的是“给定完整上下文该怎么回”,而不是每一轮都单独学。数据量不大的时候我会把长对话截断成几段,每段保留最近的几轮,截断处注意别把 user 和 assistant 的角色切乱。对话微调训出来的 Adapter 在多轮场景下明显更自然,不会答非所问。

QLoRA 是我显存吃紧时的救命稻草。它在 LoRA 基础上把基座模型量化成 4bit 加载,训练时反量化计算梯度,显存占用能降到原来的三分之一甚至更低。我用 QLoRA 在一张 24G 的卡上微调过 13B 的模型,batch size 设 2 加梯度累积,能跑起来。代价是训练速度慢一些,精度上会有轻微损失,但在很多任务上跟全精度 LoRA 的差距我实测在可接受范围内。配置上注意 bnb_4bit_compute_dtype 设成 bf16 或者 fp16,量化类型用 nf4,双重量化打开能再省一点显存。

多任务实践我会用多个 Adapter 并行训练或者顺序训练。并行训练是每个任务一个 Adapter,共享同一个基座,训练时按任务切换数据加载器。顺序训练是一个任务训完接着训下一个,好处是显存占用稳定,坏处是后面的任务可能覆盖前面学的东西。我现在的做法是顺序训练加定期在混合验证集上评测,发现某个任务指标掉了就回头调整数据配比。多任务这块没有银弹,靠的是多试多记。

3.5 发布与迭代:版本追踪、上线评估、效果回流与持续优化

发布这件事我从早期的手忙脚乱到现在有一套固定流程。每个要上线的 Adapter 我都会打一个 tag,写清楚基座模型版本、训练数据版本、超参数配置和验证集指标。模型文件、配置文件、评测报告放在同一个发布包里,存到对象存储或者模型仓库。上线前我会在预发环境用真实流量的一小部分跑一轮 shadow 推理,对比新旧模型的输出差异,确认没有退化再切流量。

上线评估我分短期和长期两层看。短期看延迟、错误率、拒答率这些工程指标,还有自动评测指标在线上样本上的表现。长期看业务指标,比如客服场景的首次解决率、用户满意度。这两层指标有时候会打架,自动指标涨了但用户不满意,这种情况我遇到过,原因是模型回答变长了,自动指标觉得信息量大,用户觉得啰嗦。所以人工抽检我会一直保留,每周抽一批真实对话打分。

效果回流是持续优化的关键。我在服务层加了一层日志,把用户输入、模型输出、用户后续行为都记下来。用户追问或者点踩的样本,我会单独筛出来人工看,判断是模型能力问题还是数据覆盖问题。这些样本攒到一定量,做一轮增量微调,用上一版的 Adapter 做初始化继续训,比从零训收敛快很多。回流数据记得做去重和清洗,线上日志里噪声不少,直接拿来训容易把模型带偏。

持续优化我现在的节奏是两到四周一个小版本。每个版本只解决一到两个明确的问题,比如“减少对模糊问题的强行回答”或者“提升某类设备故障的解决率”。改动前先定好验收指标,改完在固定测试集上对比。版本迭代多了之后我发现,LoRA 的好处这时候特别明显,每个版本的 Adapter 都很小,历史版本全留着也不占多少空间,随时能回滚对比。这套流程跑顺之后,微调从一个“大工程”变成了日常的迭代动作。

赞0
踩0
☆收藏0
版权声明
文章版权声明:除非注明,否则均为ZBLOG原创文章,转载或复制请以超链接形式并注明出处。
分享到
chuanbook

链接已复制到剪贴板