现场是这样的。语音标注在 Label Studio 1.13 上做,导出 JSON 后转成训练格式,发现每段对话的 speaker 字段全丢了,训练脚本按两人对话切分时把内容混在一起。

中间走过弯路,把「转换脚本只取了 annotations 下的 result.value」当成主因,改完现象没变。

这类报错背后常见的原因有几处,逐个排除就行。导出用的是 JSON 而不是 JSON_MIN,结构层级不同;标注模板里没有把 speaker 作为独立标签配置;同一任务被多人标注,导出时只保留了一份。

上来先看导出文件的实际结构

python -c "import json;d=json.load(open('export.json'));print(d[0]['annotations'][0]['result'][0].keys())"

接着改从 result 的 value 里逐项取 speaker

python -c "import json;d=json.load(open('export.json'));print([r['value'].get('speaker') for r in d[0]['annotations'][0]['result']][:5])"

再往下用官方 SDK 拉取任务保证字段完整

pip install label-studio-sdk==1.0.3 && python -c "from label_studio_sdk import Client;c=Client(url='http://ls:8080',api_key='$KEY');print(c.get_project(12).get_tasks()[0].keys())"

转换后用样例音频核对说话人顺序

python check_speaker.py --json export.json --audio sample.wav --expect A,B,A

恢复的判定其实很直接。转换后的样本里 speaker 标签完整,抽查 5 段对话的轮次顺序与音频一致,训练脚本不再把两人合成一段。

容易忽略的是,导出格式决定了字段能不能带出来,标注模板里没配的维度在导出时不会凭空出现,转换脚本改之前先看原始结构。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189