拼接多轮对话后请求返回 400,错误信息里提到 messages 必须以 system 开头,或者角色必须交替。多数是历史消息处理得不干净。
先打印真实结构
import json print(json.dumps(messages, ensure_ascii=False)[:800])
看清每条的角色和内容,空内容、连续两轮 user、以 assistant 结尾的残缺消息,都可能触发 400。
基本规则
- 第一条可以是 system,也可以直接是 user
- 之后按 user、assistant 交替,最后一条通常是 user
- 内容不能为空字符串,失败重试留下的空 assistant 要剔除
拼装前做一次清洗
clean = []
for m in messages:
if not m.get("content"):
continue
if clean and clean[-1]["role"] == m["role"]:
clean[-1]["content"] += "\n" + m["content"]
continue
clean.append(m)
连续同角色合并成一条,比删掉更保信息。涉及函数调用的会话还要保证 tool 消息紧跟对应的 assistant,顺序乱了同样报 400。
如果错误信息提到 token 或内容格式,先确认没有把整段 JSON 当字符串塞进 content,转义字符出问题也会报参数错误。
把校验放在服务端入口
在调用封装层加一个轻量校验:角色是否在允许范围内、内容是否为空、是否有连续同角色。上线前拦住,比等接口返回 400 再排查要快得多,日志里记录被修正的消息条数也便于观察上游逻辑改动。
多轮会话存储时,把失败或中断的轮次标记出来,重试前过滤掉,否则历史记录里会不断堆进空消息,最终把整个会话拖垮。