把流式收到的块原样拼进多轮历史后,下一轮请求报 400,原文是 messages.0.content must be a string,检查发现首块只有 role 没有 content,被拼成了一条空消息。
一开始怀疑是「空 content 的历史在严格校验下被拒」,查了一圈,方向不对。
原因不止一个,得分开看。首块的 delta 只带 role,content 为 null。少数情况下是拼接逻辑把每个块都当成一条完整消息。
不容易想到的是,工具轮次里 assistant 消息只有 tool_calls。
上来先按轮次累积而不是按块累积
python stream_accumulate.py --by-turn
丢弃空消息再写入历史
python history_clean.py --drop-empty
工具轮次补齐 tool_calls 字段
python history_clean.py --keep tool_calls
剩下的就是用两轮对话验证历史合法
python chat.py --turns 2 --stream
改之前我把相关日志按时间截了一段存着,事后对时间线用得上。
恢复的判定其实很直接。第二轮请求返回 200,历史里没有空 content 的 assistant 消息,工具轮次的 tool_calls 完整保留。
提醒一点。流式块是增量不是消息,把块直接追加到历史里是最常见的错,务必在流结束后再组装一条完整消息。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
