事情本身不复杂,线索都在日志里。Windows 上用记事本改过一批微调用的 jsonl,再用 Python 3.12 逐行 json.loads,第一行就抛 JSONDecodeError,提示 Unexpected UTF-8 BOM (decode using utf-8-sig)。同一文件拷到 Linux 上也一样,用 VSCode 看第一行开头确实有个不可见字符。

第一反应是「用 utf-8 打开后直接把首行交给 json.loads」,验证下来不成立。

排查方向其实有限,先把可能性排一排。文件被保存成带 BOM 的 UTF-8,首行多了三个字节。还有一种是多个来源的文件拼在一起,只有其中一个带 BOM。

还有一种情况,上传前的校验脚本跳过了第一行,问题被带到平台。

动手时先确认首字节是不是 EF BB BF

python -c "print(open('train.jsonl','rb').read(3))"

然后改用 utf-8-sig 读取,编码器会自动吃掉 BOM

python -c "import json;print(json.loads(open('train.jsonl',encoding='utf-8-sig').readline()))"

批量清洗目录下所有 jsonl 并统计坏行

python clean_jsonl.py --dir data --encoding utf-8-sig --report bad.jsonl

上传前跑一次行数与可解析性校验

python validate_jsonl.py --file train.jsonl --require-custom-id

恢复的判定其实很直接。逐行解析不再抛异常,校验脚本输出的总行数与成功行数相等,平台侧上传返回 file id。

容易忽略的是,BOM 只影响第一行,很容易被只重试失败行的逻辑掩盖,清洗时要整份文件重跑而不是从第二行接着来。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189