本文记录把 shop-agent 的本地参数抽取模型(Qwen2.5-1.5B)用 LLaMA-Factory 微调上生产的完整过程。
流程与踩坑同节写,场景难题一节集中讲参数抽取域特有难题。
文中命中率、训练时长、格式合规为实测值,显存为实测/估算,成本为基于实测的推算(基于 RTX 4070 8GB + Qwen2.5-1.5B-Instruct 4bit 微调)。凡估算 / 假设 / 参考口径均在正文标注。


为什么微调:三级链路的痛点与成本动机

shop-agent 的参数抽取是一条三级兜底链路:

正则兜底 → 本地小模型(Qwen2.5-1.5B) → 云端大模型(qwen3.6-flash)

设计初衷是用免费的本地模型兜住大部分请求,只在本地失败时才降级到云端 LLM。但实测发现一个事实:未微调的 Qwen2.5-1.5B 参数抽取命中率只有约 23.3%,意味着近 77% 的流量会掉到云端——而云端大模型(qwen3.6-flash)的单价是输入 1.2元 / 输出 7.2元 每百万 token,这部分成本压不下来。

微调要解决的,就是把这个 23.3% 往上推。目标:用一次低成本的训练,把降级到云端的流量砍掉一大截


数据准备:脚本离线合成训练 / 测试集

流程:模板 + 值池 + 难例,离线合成

为了降低标注费用,也为了避免把生产 PII 烧进权重,没有走「蒸馏真实日志」这条路,而是用脚本离线合成(实测:训练 / 测试集均由此生成,无任何真实日志参与):

  • 训练集:用离线合成脚本(合成模板 + 订单号 / 物流单号 / 手机号等值池 + 缺参难例)离线生成,随机填充且固定随机种子保证可复现;
  • 测试集:用测试集生成脚本以随机订单号 / 单号生成器另写措辞,保证与训练集的 query 文本、订单号、单号完全不重叠;
  • 增强集(实际训练用 1729 条):在基础集 1600 条上按评测错误类型补样本(复用同一套模板,不引入分布漂移,见坑⑨)。

为何不直接蒸馏生产日志:① 合成数据不含任何真实 PII,合规零风险;② gold 由程序生成,类型天然可控(订单号 / 单号恒为字符串)。

数据格式用 LLaMA-Factory 的 ShareGPT:

{
  "conversations": [
    {"role": "system", "content": "从用户消息提取结构化参数,只返回JSON。字段:order_id(字符串)"},
    {"role": "user",   "content": "帮我查一下订单 WB202405270001 到哪了"},
    {"role": "assistant", "content": "{\"order_id\": \"WB202405270001\"}"}
  ]
}

训练样本里的 system 字段直接复用项目参数抽取用的 prompt 模板,保证训练与推理 prompt 一致(这点配置不一致会要命)。

规模:5 类意图(查订单 / 查物流 / 退货 / 查余额 / 查优惠券)各 ~300 条 + 难例 ~200 条,基础集 1600 条、增强集(实际训练用)1729 条(实测)。对 1.5B 小模型,这个量足够 LoRA 见效。

后期运维:用真实日志做持续校正(蒸馏的正确打开方式)

合成数据解决了「从 0 到 1」,但扛不住线上分布的缓慢漂移(新单号前缀、新口语、新意图)。我们的做法是把「蒸馏真实日志」当作后期运维的常规校正回路,而不是初始数据来源:

  1. 定期抽一批真实对话,先过脱敏逻辑处理 PII(呼应防御点 1);
  2. 用云端 LLM 当教师蒸馏打标(合成脚本接真实日志并开启蒸馏开关),gold 仍强制转成字符串(呼应防御点 2);
  3. 拿新样本跑误差驱动增强脚本 + 评测,找出仍错的意图 / 类型,补进训练集重训(呼应坑⑨);
  4. 混入 ~20%(经验值)旧意图样本抑制遗忘(呼应场景难题 I)。

这样初始数据零 PII 风险、可复现,而真实分布通过「脱敏 → 蒸馏 → 增强 → 重训」的闭环持续回流——蒸馏的价值落在运维期,而非冷启动期。

接真实日志前必做的两个防御点

下面两条是「前置防御」——我们当前训练数据是脚本合成的,但一旦把数据来源从脚本合成切换成蒸馏真实日志(见上文「后期运维」回路),它们就会触发,所以先写在这里。

防御点 1:PII 泄露

把数据来源从「脚本合成」换成「蒸馏真实对话日志」,训练集就会混着真实手机号、订单号、身份证号——直接拿去训练 = 把生产 PII 烧进模型权重,合规风险极高。我们当前训练数据是脚本合成的,这一条未实际触发;但合成脚本已为可选的「接真实难例」路径预留了脱敏逻辑(手机号/邮箱/身份证/订单号脱敏后再入库),一接真实数据即可生效。

解决:一旦接入真实日志,入库前先跑项目已有的 PII 脱敏(手机号/邮箱/身份证/详细地址),脱敏后再存训练样本。

防御点 2:字段类型错位

用「教师 LLM 蒸馏」生成 gold,教师偶尔会把本应是字符串的订单号输出成数字 123456789,训练进去后推理端对结构化字段做强类型校验时会直接报错。我们合成数据的 gold 在生成期就由字段类型强转逻辑强制转字符串,这条同样未实际触发;但作为真实日志路径的兜底,类型校验脚本仍保留。

解决:数据校验脚本强制订单号/单号为字符串类型,过滤掉所有非字符串样本;合成路径则在生成期直接保证类型正确。


场景特有难题:参数抽取域的九大设计权衡

这一节是本文的护城河——通用微调教程不会讲,只有做「参数抽取」才会撞上。

# 问题 我们的取舍
A 单模型 vs 多模型:一个 Qwen 抽 5 类意图,还是每意图一个 LoRA? 单模型 + system 区分意图,省部署成本;多 LoRA 路由复杂度不划算
B 多意图/歧义:「查订单并申请退货」输出结构怎么设计 只抽主意图参数,歧义交给三级链路的 ReAct 处理,不在抽取层硬解
C 缺参/隐式参数:用户没说订单号 → 输出空字段还是报错 约定缺则输出空字符串,由下游正则兜底,不报错中断
D 字段格式强约束:订单号/手机号有固定格式 模型输出后接本地正则抽取器做正则校验,不合规视为未抽中
E schema 对齐:模型怎么知道输出哪个 schema system 中显式写出当前意图的字段定义,训练/推理一致
F 与三级链路集成:本地小模型仍可能输出非法 JSON 必须保留本地正则兜底 + 云端大模型兜底,微调只是提升命中率不是取代兜底
G 评测口径业务化:资损级字段(抽错即造成资金损失,如订单号/物流号)应单独盯守,不能只看未加权均值 字段级实测(SFT,360 条):物流号 95.24%(唯一跌破 95%)、订单号 98.55%、优惠券 97.22%、原因/状态/手机号≈100%——均值 97.8% 掩盖了资损级短板
H 难例分布场景化:物流单号 vs 订单号混淆、优惠券别名、编号前缀池/口语格式分布 数据构造时专门塞「满减券/红包/折扣券」等别名样本;订单号/物流单号的「前缀+位数」、裸枚举值句尾/句首、因+原因引导等测试集出现的格式,训练集必须覆盖,否则漏抽/截断(本次退货意图 0.861→0.972 的根因,实测:增强前后对比;见坑⑨)
I 意图新增的灾难性遗忘:微调新意图时旧意图精度掉 新意图数据混入旧意图 ~20%(经验值,无 10/20/30% 对比实验 旧样本一起训,抑制遗忘

其中 D、F 在部署一节落地,G 在验收一节落地,H 在数据一节已处理,I 在复盘一节讨论。A/B/C/E 是微调前的架构决策,先想清楚再动数据。


环境与配置:QLoRA 与 template 命门

流程:训练配置

训练配置文件(LLaMA-Factory 格式):

model_name_or_path: Qwen/Qwen2.5-1.5B-Instruct
stage: sft
do_train: true
finetuning_method: lora
quantization_bit: 4            # QLoRA,省显存
lora_rank: 16
lora_alpha: 32
lora_target: q_proj,v_proj,k_proj,o_proj
template: qwen                  # ⚠️ 必须与推理端一致
dataset: 训练集
cutoff_len: 1024
learning_rate: 2.0e-4
num_train_epochs: 3
per_device_train_batch_size: 4
gradient_accumulation_steps: 8
preprocessing_num_workers: 4   # 数据集预处理并行,Windows 安全(区别于坑④ 的 dataloader)
upcast_layernorm: true
lr_scheduler_type: cosine
bf16: true
output_dir: ./outputs/微调产物

数据集登记文件(LLaMA-Factory 的 dataset_info.json):

{
  "训练集": {
    "file_name": "训练集.json",
    "formatting": "sharegpt",
    "tags": {"system": "system", "user": "user", "assistant": "assistant"}
  }
}

坑① 单卡 OOM

8GB 卡上 1.5B 全参微调直接 OOM。

解决quantization_bit: 4(QLoRA)可大幅压低显存;4bit 下 1.5B 训练峰值显存约 2–4GB(估算值:按 4bit 权重 ~0.75GB + 优化器/激活推算,未逐秒采样 nvidia-smi);仍紧就降 per_device_train_batch_size 到 2、升 gradient_accumulation_steps

坑② template 不一致(最致命)

这是全篇最痛的坑。训练时 template: qwen,但推理端本地模型服务如果自己手拼 prompt、没走 tokenizer 自带的 chat template,导出的模型在推理端输出会完全崩坏——不是格式错,是语义乱码。

根因:LoRA 学的是「在 qwen chat template 下的输入→输出映射」,推理端 template 一变,映射全失。

教训:把 template: qwen 写进部署 checklist,训练端和推理端用同一份 template 定义,谁改谁负责回归。

坑③ 版本地狱

LLaMA-Factory 拉最新 transformers 后,与项目 torch 的版本下限冲突,训练起不来。

解决:锁 transformers==4.41.2(与项目 torch 版本下限匹配的版本)。

坑④ Windows 上 dataloader_num_workers > 0 训练直接崩溃

在 Windows 上把 dataloader_num_workers: 4 当作提速项加上后,训练循环一启动 dataloader 就抛 pickle 错误:can't pickle local object '...custom_gradient_checkpointing_func'

根因:Windows 的多进程用 spawn(不像 Linux 用 fork),子进程必须把整个模型(含 transformers 里自定义的局部闭包函数 custom_gradient_checkpointing_func)序列化传给子进程,而闭包无法 pickle → 崩溃。注意数据预处理阶段preprocessing_num_workers: 4)是正常跑完的,错误发生在训练循环启动 dataloader 时。

解决dataloader_num_workers 保持默认 0(Windows 上 dataloader 多进程对含闭包的模型不兼容);数据集预处理的并行用 preprocessing_num_workers: 4(已验证安全,且不影响模型闭包)。其余提速项(per_device_train_batch_sizeupcast_layernorm: true)可正常用(区别于坑④ 的 dataloader)。


训练:过拟合与 LoRA target 漏层

流程

lora_rank=16num_train_epochs=3、cosine 学习率。Qwen 的 lora_target 必须含 q_proj,v_proj,k_proj,o_proj 四个。

坑⑤ 过拟合:val_loss 先降后升

多 epoch 易过拟合(我们最终用 epoch=3;试过更大 epoch 时验证集 loss 出现反弹、held-out 命中率回落。

解决:回退到 epoch=3,并补充难例数据(数据一节的 ~200 条难例发挥作用)。小模型数据少时,多 epoch 是过拟合重灾区。

坑⑥ LoRA target 漏层 = 白训

一开始只挂了 q_proj,v_proj,跑完发现效果几乎无变化——LoRA 没挂到足够的层上,模型参数基本没动。

解决:Qwen 全系必须含 k_proj,o_proj,补全后效果立显。


导出与部署:路径、4bit 对齐、多 Worker、链路集成

流程

llamafactory-cli export \
  --model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \
  --adapter_name_or_path ./outputs/微调产物 \
  --export_dir ./models/本地模型 \
  --export_size 2 \
  --template qwen

导出合并权重后,把本地模型服务的加载路径指向本地模型目录(内网可离线加载)。三级兜底链(正则兜底 → 本地小模型 → 云端大模型)原样保留,微调只是把中间一跳的命中率拉高。

坑⑦ 部署端 4bit 对齐

项目用 bitsandbytes 4bit 量化本地模型(依赖清单已装)。导出模型在 4bit 下 JSON 输出需重测——偶尔出现字段截断。

解决:上线前跑一遍测试套件,确认 4bit 下结构化输出稳定。

坑⑧ 多 Worker 重复加载

每个 FastAPI Worker 各加载一份 1.5B → 显存直接爆。

解决:把本地模型抽成 vLLM 推理服务,多 Worker 通过 HTTP 共享同一份模型。

呼应场景难题 F:链路集成验证

上线后必须验证:本地小模型输出非法 JSON 时,能正确降级到本地正则兜底云端大模型兜底,不能因为「现在模型更强了」就拆掉兜底。


数据分布对齐:训练集必须覆盖测试集的真实格式(坑⑨)

这是本次微调最深的坑,也是参数抽取域最容易栽、却最少被讲的地方。通用教程只讲「数据要多、要均衡」,但参数抽取还要求训练分布覆盖测试分布的形状——否则模型在「没见过的格式」上静默漏抽或截断,且评测时不易定位根因。

坑⑨-a 编号前缀池必须训练集 = 测试集

订单号 / 物流单号这类字段,真实分布不是「任意字符串」,而是「前缀 + 固定位数」。订单号实测前缀池为 {WB, DD, SO, EC, MY}(12 位数字),物流单号为 {SF, YT, JD, ZT, EMS, HT, YD}(10 位数字)。

症状:训练集修复前只在「带明确字段文字(『快递单号』『订单』)」的样本里见过 WB 前缀对应订单号、SF/YT/JD/ZT 对应物流单号(均为 12 位 / 10 位),测试集出现「裸编号 + 模糊文字、靠前缀判字段」且含未强调前缀(EC/SO/MY 订单号、HT/YD 单号)的样本时,模型靠猜 → 单号截断或漏抽;同理订单号在退货意图里也因前缀池覆盖不全而漏抽。

注意:别把枚举值(如退货原因「其他」)当同义词硬塞进模板别名——这会污染字段分布造成负优化,正解是前缀池对齐。

正解:建一个与生产分布一致的前缀池,按各「前缀+位数」组合等比例造样本,保证训练分布 = 测试分布。修完后查物流意图的 mixed 错误从 16 → 2(实测:前缀池修复前后对比,当前模型 mixed=2)、退货意图的订单号截断清零。

坑⑨-b 口语表达格式必须显式教

测试集里用户口语有训练集没教的格式,会导致漏抽而非截断:

  • 裸枚举值句尾退个货,订单号 WBxxx,原因是其他 —— 句尾的「其他」是原因字段,模型若只见过「因为 XXX」会漏抽原因;
  • 句首枚举其他,订单号 WBxxx 我不要了
  • 因 + 原因引导因为这衣服破了,申请退货 —— 「这衣服破了」才是原因,不是别名。

正解:把这些口语模板直接补进合成脚本,按句尾/句首/因+原因三种形态各造样本。补完后退货意图的漏抽(原因字段,原 6 条)与值错误(原 4 条:2 截断 + 2 误判「因为其他」)全部清零,退货意图从 0.861 → 0.972(实测:增强前后对比)。

呼应场景难题 H:难例分布要同时覆盖「字段别名」(满减券/红包等)与「形态/前缀分布」(订单号/物流单号的前缀+位数、裸枚举值句尾/句首、因+原因引导),两者缺一不可。微调后务必按意图逐一看命中率,别只看整体均值。


效果验收:三个基线对比 + 业务化评测

GPU 监控误区:以 nvidia-smi 为准(别信任务管理器)

判断 GPU 是否真正参与训练 / 推理,nvidia-smi 为准,不要只看 Windows 任务管理器

# 每 1 秒刷新:进程 + 显存占用 + 计算占用率
nvidia-smi -l 1
  • Memory-Usage 显存占几 GB(4bit 1.5B 训练 / 推理约 2–8GB)→ 模型已加载到 GPU;
  • GPU-Util 在训练 steps 阶段呈 50%–95% 抖动,批量推理时可达 90%+ → GPU 在算。

:Windows 任务管理器进程栏中 GPU 图默认显示 「3D」(图形渲染)引擎占用率,而 CUDA 计算跑在独立的 Cuda / Compute 引擎上。需要在性能栏中,点击GPU RTX 4070 才能看到。

为什么有时占用率低(锯齿):训练 / 评测前的数据集 CPU 预处理阶段 GPU 完全空闲(可能持续几十秒到一两分钟);1.5B 小模型 + 短序列下 GPU 每步算完即闲,利用率呈 0% ↔ 几十% 锯齿,属正常。

坑⑩ 批量推理必须 left-padding,否则结果静默错误

评测 / 推理若用 batch_size=16 批量喂模型(GPU 利用率可从 ~30% 提到 90%+,吞吐提升约 6 倍——实测:batch=1 单条 514ms → batch=16 单条 83ms,约 6.2x),decoder-only 模型必须用左填充 + pad_token

tok = tokenizer(msgs, return_tensors="pt", padding=True, padding_side="left",
                truncation=True, max_length=cutoff_len)
tok["attention_mask"] = ...  # left-padding 时 mask 左侧为 0

根因:右填充(padding_side="right")会在生成起点前塞 pad token,污染自回归的第一个生成位置,导致 JSON 输出随机错位、命中率虚低且难排查。左填充保证所有样本生成起点对齐到右侧真实内容末尾。

教训:批量推理 = 左填充 + pad_token_id 显式设置;逐条循环(batch_size=1,单条 ~514ms)虽慢但不会踩这个坑,若 GPU 利用率长期低位且命中率异常,先查 padding 方向。批量(batch=16,单条 ~83ms)可将吞吐提升约 6 倍(实测)。

三个基线(实测)

基线 命中率(实测) 格式合规(实测) 单次成本
本地正则兜底 45%(参考值 0
未微调 本地小模型 23.3% 0% 本地
微调后 本地小模型 97.8% 100% 本地
云端大模型 structured 95%(参考值 ~100%(参考 云端 ¥

注:未微调模型命中率 23.3% 主要来自查余额意图(gold 为空,模型不输出结构化内容即算对);其实际几乎不输出合法 JSON(格式合规 0%,实测),因此「命中率」不能直接等同于「可用结构化输出」——这正是微调的核心价值。

微调后本地命中率从未微调的 23.3% 拉到 97.8% ,已接近云端大模型(95%,参考值)且反超(因结构化 prompt 约束),成本从「每次调 API」变成「本地 GPU 折旧摊薄」。各意图实测(360 条 held-out 测试集):查订单 98.6% / 查物流 97.2% / 查优惠券 97.2% / 退货 95.8% / 查余额 100%,0 回归。微调后平均单条延迟 68.8ms(未微调 237ms)。

为什么是「微调」而不是「few-shot」:三条件同测试集对比

上文「未微调 23.3% → 微调 97.8%」只比了两端,「那 few-shot 呢?塞几个例子是不是就够了?」 我们用同一份 360 条测试集、同一套字段级评测,补上 few-shot 这一档(K=4,每意图 4 个样例从训练集抽取,测试集保持完整 360 条、与样例零重叠)。

条件 整条达标率 field_f1 平均延迟 平均输入 token
zero-shot(base) 23.3% 0.0 163 ms 78
few-shot(base, K=4) 71.1% 0.826 82 ms 233
sft(微调) 97.8% 0.986 44 ms 78

逐意图整条达标率:

意图 zero-shot few-shot sft
查余额 100% 100% 100%
查物流 0% 75.0% 97.2%
查优惠券 0% 68.1% 97.2%
查订单 16.7% 26.4% 98.6%
退货 0% 86.1% 95.8%

三个结论(决定「选微调」而非「堆 prompt」):

  1. few-shot 能把冷启动从 23% 拉到 71%(近 3 倍),证明 1.5B 小模型确有 in-context 学习力;但逐意图方差极大——退货 86% 却查优惠券仅 68%、查订单仅 26%。这种「看意图吃饭」的不一致,正是生产系统最怕的:同一份 prompt,今天查券抽得对、明天查单抽错,难定位、难 SLA。微调则把五个意图全部拉到 95.8%–100%,一致性满分
  2. 样例税坐实:few-shot 平均输入 token 78→233(约 3 倍),因为每个请求都白带 4 组示例。高频场景(如本项目假设 4 万请求/日)下,这 3 倍 token 直接抵消「本地免 API」的成本优势——这正是成本账里「砍 74% 云端调用」靠的是微调、而非 prompt 的根本原因
  3. 微调三轴全胜:准确率最高(97.8%)、延迟最低(44ms,比 few-shot 还快近 1 倍)、输入 token 最短(78,和 zero-shot 一样)。知识压进权重后,prompt 极短、输出确定、可本地跑。

呼应场景难题 G:业务化评测口径

命中率不能只看平均。我们把字段拆开实测(SFT,360 条):

字段 风险 样本数 命中率
tracking_number 物流单号 资损 42 95.24%
order_id 订单号 资损 138 98.55%
coupon_type 优惠券 低风险 72 97.22%
reason / status_filter / phone 中性 17–45 ≈100%

结论:资损级字段(尤其物流单号)是模型唯一的明显短板,而低风险字段几乎全中。整体 97.8% 是未加权均值,把物流号的 95.24% 和优惠券的 97.22% 拉平了——但物流号错一条 = 查错包裹 = 客诉/资损,远比优惠券错一条严重。因此实践中要把高风险字段命中率单独列出盯防,并按风险加权审视,而不是只看总分。这也正面印证了 H 的难例判断:物流单号与订单号混淆正是模型最易失守的资损级点。


成本账与复盘

成本

  • 训练成本(实测+估算):QLoRA 1.5B,1729 条(增强集,实测),3 epoch,RTX 4070 8GB,实测训练时长 ≈7.4 分钟(来自训练日志,train_runtime≈441 秒)。云 GPU(A10 ~¥2–3/时,参考价)→ 按实测 7.4 分钟 × ¥3/时 ≈ ¥0.37估算);自购卡近乎零边际。
  • 隐性成本(经验估算:数据构造(模板 + 值池 + 难例设计)与误差驱动增强的迭代调参 ~1–2 人天(主要开销;合成数据无人工清洗 / 标注,但打磨模板分布、对齐测试集格式仍需工程投入)。
  • 推理收益(假设流量模型:按中等规模 4 万请求/日(假设值,非实测,命中率 23.3%→97.8%(实测)省下约 74%×4万 = 约 3 万次/日 云端调用。本地 GPU 折旧(共享 ¥2,500/月,估算)摊薄后,约数日内回本(估算模型

复盘:何时「不该」微调

  • 数据 < 200 条且难例不足、请求量低 → few-shot 更划算(本项目实测:360 条 held-out 上 few-shot 仅 71%、且逐意图方差大;一旦凑到 1500+ 合成样本,微调以 97.8% 更高一致性反超)。
  • 本地命中率已 >95% → 边际收益低。
  • 意图频繁变更 → 重训成本 > 规则维护成本。

呼应场景难题 I:迭代与遗忘

新增意图时,把 ~20%(经验值 旧意图样本混入新数据一起训,抑制灾难性遗忘。验证旧意图精度不掉再上线。


附录

评估脚本骨架(批量 + left-padding)

import json

def evaluate(test_set, model, schemas, batch_size=16):
    per_intent, total = {}, {"hit": 0, "all": 0}
    # 批量推理必须 left-padding + pad_token(见坑⑩),否则右填充污染生成起点
    for i in range(0, len(test_set), batch_size):
        batch = test_set[i:i + batch_size]
        prompts = [build_prompt(schemas[c["intent"]], c["msg"]) for c in batch]
        toks = model.tokenizer(
            prompts, return_tensors="pt", padding=True,
            padding_side="left", truncation=True, max_length=1024,
        ).to(model.device)
        out = model.generate(**toks, max_new_tokens=128)
        for c, o in zip(batch, out):
            pred = json.loads(model.tokenizer.decode(o, skip_special_tokens=True))
            ok = all(pred.get(k) == c["expect"][k] for k in c["expect"])
            per_intent.setdefault(c["intent"], [0, 0])
            per_intent[c["intent"]][0] += int(ok)
            per_intent[c["intent"]][1] += 1
            total["hit"] += int(ok); total["all"] += 1
    print("总体命中率:", total["hit"] / total["all"])
    for k, (h, a) in per_intent.items():
        print(f"  {k}: {h}/{a} = {h/a:.1%}")

决策 Checklist

  • 数据 ≥1500 条且 5 意图均衡、已脱敏?
  • 训练集编号前缀池 / 口语格式覆盖测试集分布(坑⑨:前缀+位数、裸枚举句尾/句首、因+原因)?
  • template: qwen 与推理端一致?
  • 评估集 held-out,对比了三个基线(含未微调 23.3% vs 微调 97.8%)?
  • 批量推理用 left-padding + pad_token(坑⑩),且 dataloader_num_workers 在 Windows 保持 0(坑④)?
  • 微调后按意图逐一看命中率(不只看整体均值,见 H 呼应)?
  • 导出模型可离线加载、兜底链保留、可回滚?
  • 多 Worker 走 vLLM 而非各加载一份?
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐