Anthropic Python SDK 报 400把 system 从 messages 移到顶层修正用 Anthropic Python SDK 调一个自建或兼容端点时如果网络已经连通、认证也没有报错却收到400 Bad Request先不要把问题归因到模型不可用。一个很常见的结构错误是把 OpenAI 风格的system消息直接放进messages数组而 Anthropic Messages API 要求系统提示放在请求体顶层的system字段。本文只解决这个请求体问题使用 Anthropic Python SDK0.64.0把错误的rolesystem请求改成顶层system并用一个只监听127.0.0.1的本地夹具对照400和200。本次不请求线上 provider也不把本地夹具结果写成任意网关都兼容 Anthropic Messages。先按最小请求跑通适用环境Python 项目使用anthropic包的messages.create需要把请求发送到一个提供 Anthropic Messages 路径的自建或兼容端点。本文实测版本是anthropic0.64.0。1. 固定 SDK 版本并确认入口python3 -m pip install anthropic0.64.0 python3 -c import anthropic; print(anthropic.__version__)输出应为0.64.0这个版本的Anthropic客户端可以通过base_url指定端点messages.create会向/v1/messages发起 POST。先确认你接入的服务确实提供这条路径路径不对时改消息体不会修复 404 或 405。2. 把 system 写在顶层最小可复制请求如下base_url、api_key和model都是占位符from anthropic import Anthropic client Anthropic( api_keyYOUR_KEY, base_urlhttps://your-anthropic-compatible-endpoint.example, ) message client.messages.create( modelYOUR_MODEL_ID, max_tokens64, system用简短中文回答。, messages[ {role: user, content: 只回复 OK}, ], ) print(message.content[0].text)成功信号有三个请求路径是/v1/messagesHTTP 状态为200响应能按 Anthropic Message 结构读取content[0].text。如果你看到400先打印脱敏后的请求结构和状态码不要打印完整 Key 或 Authorization 头。3. 错误写法与修正错误写法把system当成普通消息message client.messages.create( modelYOUR_MODEL_ID, max_tokens64, messages[ {role: system, content: 用简短中文回答。}, {role: user, content: 只回复 OK}, ], )修正动作只有一处从messages删除rolesystem项并把它的content移到顶层system。messages只保留实际的用户和助手消息。不要为了绕过错误把系统提示拼进用户文本这会改变消息契约也让后续调试更困难。本地实测错误 400修正后 200为了区分“消息结构错误”和“线上服务不可用”我运行了内容包中的标准库夹具。夹具绑定随机本地端口只接收POST /v1/messages发现messages中有rolesystem时返回 400发现顶层system且路径正确时返回一个最小 Anthropic Message。在内容包目录执行python3 06-evidence/probe_anthropic_system.py脱敏后的实际输出ANTHROPIC_VERSION0.64.0 WRONG_SYSTEM_ERRORBadRequestError WRONG_SYSTEM_HTTP400 CORRECT_SYSTEM_TEXTfixture system success CORRECT_SYSTEM_HTTP200 CORRECT_SYSTEM_ERRORnone REQUESTS[{path: /v1/messages, status: 400, system_role_in_messages: true, top_level_system: false}, {path: /v1/messages, status: 200, system_role_in_messages: false, top_level_system: true}] ONLINE_PROVIDER_REQUESTNO这组对照证明的是当前 SDK 版本能发出两种请求、夹具能把错误结构与正确结构分开并且正确响应可以由 SDK 读取。它不证明某个线上模型、Key 或第三方网关已经通过认证也不证明 OpenAI 的choices响应可以直接交给 Anthropic SDK。实测结果图收到 400 时按顺序排查先看错误体不要先换模型如果错误体明确提到system、messages、role或invalid_request_error优先检查 JSON 结构。很多兼容层会把字段不符合契约统一返回 400此时换模型 ID、重试或增加max_tokens都没有帮助。再确认调用的是 Messages不是另一套协议Anthropic SDK 的messages.create对应/v1/messages请求体使用system、messages、max_tokens等字段响应读取content和stop_reason。如果你的端点只实现了 OpenAI Chat Completions就不能仅靠把 URL 改成/v1来获得 Anthropic 兼容性。先查服务文档再用最小请求确认它支持的协议。最后检查兼容层是否改写了请求自建代理可能在转发前把顶层system再次合并进messages或者只允许 OpenAI 风格的choices响应。客户端侧看到的代码正确不等于上游收到的结构正确。排查时在代理日志中只保留路径、状态码、字段存在性和 request id例如path/v1/messages status400 top_level_systemtrue system_role_in_messagestrue这表示客户端传入了顶层system但转发层又产生了rolesystem问题要回到代理映射规则而不是继续改 Python 调用。认证错误要和结构错误分开401通常需要检查 Key、认证头或 Base URL400则先检查请求体契约。不能因为两种错误都出现在第一次请求就使用同一套修复动作。调试输出只保留status、路径、错误类型和字段布尔值避免把凭据写入终端历史、日志或截图。一张最小检查表[ ] anthropic 版本已记录本文实测为 0.64.0 [ ] 客户端 base_url 指向目标服务的 Anthropic 入口 [ ] messages.create 实际请求 /v1/messages [ ] system 位于请求体顶层 [ ] messages 只保留 user/assistant 消息 [ ] max_tokens 已填写且为正数 [ ] 响应按 content[0].text 读取而不是 choices [ ] 400 与 401/404 分开排查 [ ] 日志没有明文 Key、Cookie、Token 或用户数据如果最小请求在本地夹具能返回 200而真实端点仍然 400下一步是保存脱敏请求结构、响应错误类型和 request id核对兼容层的协议映射不要把本地成功写成线上成功。若端点返回 404/405先检查 Base URL 是否重复或缺少/v1若返回 401回到认证方式与变量来源只有确认请求已到达正确路由后才继续检查模型权限或服务端实现。总结Anthropic Python SDK 报 400 时最先检查system的位置它应是请求体顶层字段messages中只保留用户和助手消息。本文用anthropic0.64.0的本地夹具复现了错误结构400和正确结构200并保留了/v1/messages、字段存在性与 SDK 异常类型。这个方法可以帮助你快速判断问题在请求体还是网络/认证层但不能替代目标服务当前版本的兼容性文档和脱敏日志。本文不要求注册、购买、充值或使用任何商业服务删除本地夹具和实测说明后最小请求与排错顺序仍可独立使用。