事情本身不复杂,线索都在日志里。拿 6 条客服问答做 gpt-4o-mini 微调试水,创建 job 时直接 400,原文 training file must contain at least 10 examples,可文件用预览工具打开格式完全正常。
第一反应是「messages 结构不完整,缺 assistant 回合的样本不计入条数」,验证下来不成立。
这类报错背后常见的原因有几处,逐个排除就行。训练集最少 10 条样本,少于下限在创建阶段就被拒。另一种情况是文件里的空行被当成无效样本,实际条数比看到的多算少。
少数情况下是不同模型对应的样本下限不一样,小模型的要求反而更高。
先统计文件里非空的样本条数
python -c "import json;print(sum(1 for l in open('train.jsonl') if l.strip()))"
然后逐条打印角色序列确认结构完整
python -c "import json;[print(i,[m['role'] for m in json.loads(l)['messages']]) for i,l in enumerate(open('train.jsonl')) if l.strip()]"
再往下把角色不全的样本单独挑出来
python -c "import json;print([i for i,l in enumerate(open('train.jsonl')) if l.strip() and [m['role'] for m in json.loads(l)['messages'][:2]]!=['system','user']])"
补齐后用 fine-tune 用途重新上传
curl https://api.openai.com/v1/files -H "Authorization: Bearer $OPENAI_API_KEY" -F purpose=fine-tune -F file=@train.jsonl
恢复的判定其实很直接。文件详情里 bytes 与本地一致,创建 job 返回 200 且 status 进入 queued,日志里不再出现 at least 10 examples,trained_tokens 大于零。
提醒一点。样本条数和请求条数是两个概念,微调按有效对话计算,空行和结构残缺的行会悄悄被丢掉,凑数前先按结构过滤一遍。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。
