这个坑值得记一笔。线上客服机器人偶尔答到一半停住,流式日志里最后一个 chunk 的 finish_reason 是 length,业务侧只看 content 是否为空就判定成功,用户侧没有任何提示。
刚开始盯着「前端把 length 当成正常结束,不展示续写入口」,折腾了半个多小时,排掉了。
原因不止一个,得分开看。max_tokens 设得太小,长答案被硬切;停止判断只看了 done 事件,没读 finish_reason;重试时从头生成,截断处的内容被覆盖。
动手时先在最后一个 chunk 上打日志确认原因
python -c "import json;d=json.loads('{\"choices\":[{\"finish_reason\":\"length\"}]}');print(d['choices'][0]['finish_reason'])"
接着统计一周内 length 的占比
python -c "import json,collections;c=collections.Counter(json.loads(l)['finish_reason'] for l in open('finish.jsonl'));print(c)"
随后把 max_tokens 提到 2048 并复测同一批问题
python bench.py --max-tokens 2048 --cases cases.jsonl --out run2.jsonl
剩下的就是对 length 追加续写请求并拼接结果
python -c "print('continue_prompt = 上文 + 请接着写,不要重复')"
这类改动我都写进变更记录,过两周再出问题时能对上号。
改完先别撤,确认这几项。同一批问题的 length 占比从 9% 降到 1% 以下,截断的回答都有续写后的完整文本。
流式接口的成功标志不只是能读完,finish_reason 才说明模型是自然结束还是被切断。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
