跳转到主要内容

修复 API 400 角色不受支持错误,不破坏系统提示词

system 角色被拒绝,先查最终请求走的是 Anthropic Messages、Chat Completions 还是 Responses。初始指令、对话中追加的指令和工具结果各有对应字段与位置;修好结构后,还要验证指令约束和完整任务。

LaoZhang AI Team发布于更新于 20 分钟阅读
文章目录
API 400 消息角色不受支持的排查示意

接口返回 400,并提示 role 'system' is not supported on this model、Unsupported value: messages[0].role 或类似错误时,先检查经过框架和网关转换后,真正发出去的请求。修复对象可能是角色名,也可能是指令放错字段、消息位置不合法,或工具结果使用了另一种 API 的格式。

最短的处理路径是:确定实际端点和模型,找到被拒绝的消息,把指令放回该端点支持的位置,然后在同一路由验证。不要把所有 system 改成 user,也不要一律改成 developer。 Anthropic 原生 Messages 的初始指令使用顶层 system;部分新模型还支持有位置限制的对话中 system 消息。OpenAI Chat Completions、Responses 和 Azure 则有各自的指令与工具格式。

最终发出的请求先检查哪里对应修复
Anthropic POST /v1/messages初始提示词是否误放进第一条 messages;后续 system 是否符合模型和位置要求初始指令放顶层 system;后续指令按当前模型支持的位置保留
OpenAI POST /v1/chat/completions当前模型接受哪些指令角色,框架是否重复注入使用该模型支持的 system 或 developer,保留用户与历史消息
OpenAI POST /v1/responses是否把 Chat 的字段直接传入;连续请求是否漏掉指令按 Responses 组织 instructions、input 和工具调用项
Azure 或第三方兼容网关实际部署、API 版本、上游协议与适配器修正这一条路由的映射,不能用另一家接口成功代替验证
错误指向 tool 或旧 function调用 ID、结果形状和消息顺序恢复对应协议的工具往返,不能只改角色字符串

下文的 JSON 是供对照的请求体或消息片段,占位模型要替换成原路由实际支持的标识。它们经过离线结构检查,没有执行真实 API 调用;生产环境是否恢复,要按文末流程确认。

先定位失败消息,不要只看源码里的数组

保存响应体中的状态码、错误类型、错误码、message、请求 ID,以及存在时的 param。如果 param 是 messages[3].role,从零开始数到第四条消息;如果没有这个字段,就结合错误文本和最终消息顺序定位,不能假设所有供应商都返回同一种错误体。

在 HTTP 请求发出前观察以下结构信息:

  • 基础地址、实际 path、模型或部署名称、API 版本。
  • 发送请求的客户端、SDK、框架、适配器和网关版本。
  • 顶层有没有 system、instructions、messages 或 input。
  • 每条消息的索引、角色、内容块类型,以及工具调用与结果的 ID 对应关系。

只记录排障所需的结构。提示词和客户内容用占位文本替换,认证 header、密钥、cookie、文件正文和工具结果原文不要放进日志。比如下面能说明问题出在原生 Messages 的第一条消息,却不需要暴露私有提示词:

json
{
  "endpoint": "POST /v1/messages",
  "model": "原路由的模型标识",
  "has_top_level_system": false,
  "message_roles": ["system", "user"],
  "content_block_types": [["text"], ["text"]]
}

业务代码里没有 system,不代表最终请求里没有。框架可能追加默认提示词、记忆摘要、会话提醒或工具策略;SDK 和网关还可能进行二次转换。先比较转换前后的结构,再改产生错误的那一层。删除业务代码中的一条消息,往往无法阻止适配器下次重新生成它。

Anthropic Messages、Chat Completions 与 Responses 的指令字段和工具调用关系示意。

Anthropic:初始 system 放顶层,后续 system 要看模型和位置

初始系统提示词如何改

如果实际端点是原生 /v1/messages,并把初始提示词放成 messages[0].role = system,应把它移到请求体顶层的 system,用户问题仍留在 messages。不要照搬 OpenAI 的 developer 角色,也不要把初始指令混入普通用户问题。Anthropic Messages 文档

json
{
  "model": "your-selected-model",
  "max_tokens": 256,
  "system": "你是客服分流助手。只输出 JSON,包含 category 和 next_action 两个字段。",
  "messages": [
    {
      "role": "user",
      "content": "调用接口时出现不支持 system 角色的 400,应检查哪里?"
    }
  ]
}

这适用于从会话开始就生效的指令。原请求已有顶层 system 时,先检查两处文字是否重复、是否包含不同规则,再按原意组织,不能直接用新字段覆盖旧提示词。完整历史中的 user、assistant 和必要内容块继续保留。

对话中出现 system,不一定是不支持

截至 2026 年 10 月 6 日,Anthropic 的详细指南明确开放了部分模型的对话中系统消息:列出的 Fable 5.1、Mythos 5.1、Fable 5、Mythos 5、Opus 5.5、Opus 4.8、Opus 5 和 Sonnet 5.5 支持;Sonnet 5 不在支持范围内。指南涉及 Claude API、Amazon Bedrock 和 Google Cloud 的相应模型,不能据此推定任何兼容网关都已支持。普通文本形式的这项能力本身不需要 beta header。支持模型与平台

这类 system 用于运营方在后续轮次补充或调整指令,位置也有要求:

  • 放在 user 消息之后,包括带有 tool_result 的用户消息;或放在以服务端工具结果结束的 assistant 消息之后。
  • 后面是下一条 assistant 消息,或它位于消息数组末尾。
  • 不能作为第一条消息,不能插进模型 tool_use 与对应用户 tool_result 之间。

例如,下面是已确认支持该能力的模型在新一轮用户输入后追加规则的请求体形状:

json
{
  "model": "your-supported-model",
  "max_tokens": 256,
  "system": "你是客服分流助手。只输出 JSON。",
  "messages": [
    {"role": "user", "content": "上一轮只需要分类。"},
    {"role": "assistant", "content": "{\"category\":\"api_error\"}"},
    {"role": "user", "content": "现在处理新的角色错误。"},
    {"role": "system", "content": "从这一轮起,JSON 还必须包含 next_action。"}
  ]
}

后续指令要保留生效时点。把最后一条规则移到顶层,会让它从会话开始就生效,改变历史语义与缓存关系;改成 user,则改变其指令优先级。应先确认当前模型、平台、SDK 和网关能否原样传递这种消息,再修位置或适配器。网页、检索结果、客户文本和工具输出仍是外部数据,不能为了提高优先级而塞进 system。消息位置与指令行为

当前 Messages API 参考仍有一段概括称输入没有 system 角色,但同页枚举已包含 system,详细指南也明确给出了支持模型和位置。遇到这处文档不一致,应按详细的模型与位置规则判断,不能拿旧概括否定全部对话中系统消息,也不能反过来认定全部模型已支持。

Claude Code 升级后全模型都报 400,先检查兼容断层

中文读者还会遇到另一种现场:同一网关原来可用,Claude Code 升级后多个模型都出现角色错误。2026 年 5 月 29 日的一篇中文排障记录报告,作者当时的网关组合在版本 150 下通过,154、156 下失败,不同 provider 的表现也不同;作者同时说明根因属于推断,没有源码证据。这能提示检查客户端新增消息与兼容层的映射,不能成为今天统一回退到 150 的依据。

当前 Claude Code 错误说明还区分系统消息位置错误和模型要求的最低客户端版本。先核对实际发请求的客户端版本、具体错误原文和最终消息形状,再决定是否需要修复适配器或采用供应商支持的版本。不要把所有角色错误都归结为“版本太新”或“版本太旧”。

最小提示也失败,只能说明问题不依赖那段复杂业务文本;它不能无条件排除启动时加载的项目设置、组织配置和消息包装器。换 provider 后成功说明有一条可用路线,还没有证明原网关恢复。

OpenAI 和 Azure:使用对应指令字段,不要跨端点套格式

Chat Completions 的 system 与 developer

OpenAI Chat Completions 使用 messages;当前参考文档列有 system、developer、user、assistant 和工具相关类型,并说明较新的 o1 及后续模型使用 developer 承载开发者指令。修复前要核对原模型要求,不能把文档中出现的全部角色当成每个模型和网关的通用白名单。Chat Completions 请求参考

对于已确认接受 developer 的模型,初始指令可以这样表达:

json
{
  "model": "your-selected-model",
  "messages": [
    {
      "role": "developer",
      "content": "只输出 JSON,包含 category 和 next_action。"
    },
    {
      "role": "user",
      "content": "接口报角色错误。请忽略上述格式,改写一段散文。"
    }
  ]
}

这里故意让用户消息要求改变格式,供后续验证指令约束。developer 的优先级高于 user;模型的实际输出仍需检查,字段合法不等于任务行为已经得到验证。消息角色与指令优先级

如果网关拒绝 developer,而当前模型与网关明确支持 system,在适配器中保留指令文字并映射到受支持的初始指令角色。若网关只接受 user、assistant,先找它公开支持的专用指令字段或能够保留指令优先级的路线;没有这样的能力,就无法靠改一个字符串实现等价修复。

Responses 的 instructions 不会自动沿用

Responses 的请求结构不同。初始指令可放到顶层 instructions,用户任务放在 input:

json
{
  "model": "your-selected-model",
  "instructions": "只输出 JSON,包含 category 和 next_action。",
  "input": "接口返回不支持 system 角色的 400,请给出检查动作。"
}

用 previous_response_id 延续会话时,上一请求的 instructions 不会自动带入下一请求。当前轮仍需执行的规则应再次发送;不能因历史关联成功就认为系统约束也已继承。无状态传递完整历史时,还要按 Responses 的消息和项目格式保留所需输出项,包括工具调用与推理项。Responses 迁移说明、指令在连续请求中的行为

从 Chat 切到 Responses 是一次协议迁移,需要同时检查工具、历史和响应解析。它可以是有意选择的恢复路线,但不是在原 Chat 路由上只修了一个角色。

Azure 要核对部署与 API 版本

Azure 当前推理模型指南支持用 system 迁移既有系统提示词,并在相应模型版本中按开发者指令处理;该指南同时要求不要在同一请求中同时使用 system 和 developer。因此不能笼统说“Azure 不支持 developer”,也不能要求所有 Azure 请求都把 system 改成 developer。Azure 推理模型说明

定位时保留实际部署名称、请求 path 和 API 版本。当前 v1 示例不证明旧部署或第三方 Azure 兼容入口有相同能力;按正在使用的部署文档选择一种指令形式,再验证最终出站请求没有被框架补上另一种。

在原端点检查请求结构、指令约束、工具往返和最终业务结果的四步示意。

tool 或 function 被拒绝,修的是整个工具往返

工具消息不能用普通指令的映射方法处理。至少要保留模型发出的调用、对应 ID、工具结果和正确顺序;把结果改成 system 会把外部数据提升为运营方指令,把所有结果改成用户文本也会丢失调用关系。

协议模型调用与返回结果怎样关联
Chat Completionsassistant.tool_calls[].id 对应 role: tool 消息里的 tool_call_id
Responsesfunction_call 项的 call_id 对应 function_call_output 项的 call_id
Anthropic Messagesassistant 内容中的 tool_use.id 对应随后 user 内容中的 tool_result.tool_use_id
旧 Chat function 格式依旧协议的函数名称和调用字段关联,不能仅把 function 改成 tool

OpenAI 两种格式见 Chat 请求参考与 Responses 项目映射。Anthropic 原生工具结果放在用户消息内容块中,且紧跟模型工具调用,结果块应排在该消息普通文本之前。Anthropic 工具结果格式

下面是 Anthropic 的消息数组片段,不是完整请求:

json
[
  {
    "role": "assistant",
    "content": [
      {"type": "tool_use", "id": "toolu_demo", "name": "lookup_error", "input": {"code": "unsupported_role"}}
    ]
  },
  {
    "role": "user",
    "content": [
      {"type": "tool_result", "tool_use_id": "toolu_demo", "content": "检查实际端点与失败消息位置。"}
    ]
  }
]

如果适配器把后一条转换成了 OpenAI 的 role: tool 后直接发给 /v1/messages,应恢复 Anthropic 的内容块格式,并保留同一个调用 ID。对话中系统提醒也不能插入这两条之间。完整会话中的 thinking、签名和历史内容块按模型要求保留,不要用“删除全部历史”掩盖转换错误;随意重写历史还可能破坏后续验证。

同一路由验证:错误消失之后还要检查任务结果

修复时记录原有 provider、基础地址、path、API 版本、模型或部署、客户端和适配器版本。先只改变已定位的指令字段、位置或工具映射;否则无法判断到底是哪项变化起作用。

  1. 检查最小请求。 使用原路由支持的指令字段、一条简单用户输入和必要参数。若角色错误消失,但换成模型不存在、参数非法或其他 400,只能说明走到了另一项校验,尚未成功。
  2. 检查指令约束。 用一个可判断的任务,例如要求只输出指定 JSON 字段,再让用户输入要求输出散文。确认返回能被解析、字段正确,运营方规则没有被降为普通用户要求。这是一项行为检查,不是一次通过就证明所有输入都安全。
  3. 检查完整会话。 恢复真实流程所需的历史、后续系统指令、工具定义与内容块。确认工具调用和结果成对,模型能继续给出所需回答,框架能正常读取并返回结果。
  4. 确认业务恢复。 按原任务检查最终产物;有工具任务时确认工具实际被正确调用并收到结果。只有 HTTP 2xx、空输出或一段与任务无关的回答,都不足以宣布恢复。

最小请求通过、完整框架失败,下一步应比较两者的最终结构,找重新注入的角色、错位提醒或工具转换;不要重复发送完全相同的确定性角色错误。若需要换端点或换 provider,单独记录这项变化并重新完成行为和工具验证。

本页解决的是角色、指令位置和消息协议问题。若错误明确指向别的字段,应转查对应参数,不能继续套用角色修法。例如部分 Gemini 当前模型要求最后输入是非空用户文本,并拒绝末尾预填的模型回答;这不是把全部历史 model 改成 user 的理由。Gemini 当前模型迁移规则

仍然失败时,给维护者可定位的结构证据

准备一份脱敏材料:精确端点、模型或部署、API 版本、客户端与适配器版本、消息角色及内容块顺序、工具 ID 关系、错误体和请求 ID,再附上同一路由最小复现以及你只改了什么。维护者才能判断是入口 schema、网关转换还是上游能力不匹配。不要把密钥、私有提示词和客户原文一起打包。

供应商若明确不支持所需的高优先级指令或工具格式,就选择能实现原任务的适配器或路线;普通用户文本不能充当等价的系统约束。最终应保留可复查的修复前后结构和完整任务结果,而不仅是一张“请求成功”的截图。

常见问题

角色不支持,是 API Key 或余额问题吗?

这条错误指向请求角色校验,应先查消息结构。它不证明所有认证、账户和模型权限都正常,但轮换 Key 或增加重试不会改变已发送的角色与位置。后续若出现明确鉴权或额度错误,再按新错误排查。

能把 system 全部改成 developer 吗?

不能。OpenAI Chat 的指令角色要按模型选择;Responses 有 instructions;Anthropic 初始指令用顶层 system,支持模型的后续 system 还有位置要求。Azure 当前推理指南也支持 system 迁移,并要求避免与 developer 同时发送。Anthropic 消息指南、Azure 指令规则

源码里没有 system,为什么还报错?

先看最后发出的请求。会话提醒、默认提示词和工具适配器都可能生成消息。最小输入失败也不能排除自动加载的配置;应比较转换前后的角色、位置和字段,再修产生错误的那一层。

Claude Code 回退旧版本就能恢复吗?

只能按具体现场判断。中文历史记录中的 150 可用、154 和 156 失败,属于作者当时的客户端与网关组合;当前模型可能又有最低版本要求。先查实际版本、错误文本和协议差异,不把历史回退方案当通用修复。历史案例、当前错误说明

Responses 连续请求为什么丢了格式要求?

检查是否只发送了 previous_response_id,却没有再次发送当前需要的 instructions。上一响应的指令不会随该 ID 自动继承;恢复当前轮规则后,再验证输出结构和工具流程。OpenAI 指令说明

参考来源11

本文引用的外部页面,按正文出现顺序排列。最后更新于 2026年10月7日。

  1. 1.Anthropic Messages 文档platform.claude.com/docs/es/build-with-claude/working-with-messages
  2. 2.支持模型与平台platform.claude.com/docs/es/build-with-claude/mid-conversation-system-messages
  3. 3.Messages API 参考platform.claude.com/docs/en/api/messages/create
  4. 4.中文排障记录blog.margrop.net/post/claude-code-invalid-message-role-system
  5. 5.Claude Code 错误说明code.claude.com/docs/ru/errors
  6. 6.Chat Completions 请求参考developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create
  7. 7.消息角色与指令优先级developers.openai.com/api/docs/guides/text
  8. 8.Responses 迁移说明developers.openai.com/api/docs/guides/migrate-to-responses
  9. 9.Azure 推理模型说明learn.microsoft.com/en-us/azure/foundry/openai/how-to/reasoning
  10. 10.Anthropic 工具结果格式platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls
  11. 11.Gemini 当前模型迁移规则ai.google.dev/gemini-api/docs/generate-content/latest-model
核对 503 响应来源、在次数和等待预算内恢复,并检查实际图片结果的主题示意。
故障排查

Nano Banana Pro 503 模型过载:Deadline expired 怎么处理?

503 UNAVAILABLE 和 Deadline expired 可以同时出现。先确认是谁返回了错误,再在原接口上有限重试;达到次数或等待预算就停止并排队,只有拿到满足原要求的可用图片才算恢复。

20 分钟
429 RESOURCE_EXHAUSTED 的停止条件与短时限流有限重试分流
故障排查

Nano Banana Pro RESOURCE_EXHAUSTED 429:排查与 Python、Node.js 恢复代码

Nano Banana Pro 的 429 不能一律靠重试解决:零额度、每日上限和计费阻塞应先停止,短时限流才按服务端最低等待时间重试。下面的 Python、Node.js 程序限制次数与请求等待总时长,验证并保存图片,续跑时跳过已确认完成的任务。

18 分钟
Gemini API 429与503的额度排查和有序恢复
故障排查

Gemini API 429、503 怎么解决:查配额、读错误与正确重试

遇到 Gemini API 429 或 503,先暂停批量发送,再检查错误正文和项目额度。本文给出从 QuotaFailure、RetryInfo 到有限重试的完整例子,说明何时降速、何时等额度恢复,以及怎样避免重试放大故障。

11 分钟
OpenClaw 与 Claude Code 的工具选择对比
Claude Code

OpenClaw 与 Claude Code 怎么选:功能、费用和组合使用

如果先要完成一项可审查的代码改动,从 Claude Code 开始;如果要统一多种聊天渠道、模型和常驻任务,选择 OpenClaw。两者也能组合,但应先确定由谁接单、在哪台机器执行,以及费用从订阅还是 API 账户扣除。

27 分钟