【Bug已解决】Getting Malformed input request when trying to use Claude Sonet Model by Bedrock 解决方案
2026/8/21 19:24:30 网站建设 项目流程

【Bug已解决】Getting Malformed input request when trying to use Claude Sonet Model by Bedrock 解决方案

一、现象长什么样

你在 Bedrock 上用 Claude Sonnet(原文拼写为 Sonet)模型,请求被拒:

  • Malformed input request(输入请求格式错误);
  • ValidationException: Malformed input request
  • 你照着 Anthropic 官方文档写的 body(带max_tokensmessagessystem),却在这报错;
  • invoke_model直接传 JSON 时尤其容易踩;
  • 有时是字段名不对(Bedrock 用maxTokens而非max_tokens),有时是缺anthropic_version
  • 同样的字段在直连 Anthropic 时没事,一上 Bedrock 就 malformed。

一句话:Bedrock 对 Claude 的请求体有自己的一套字段命名/结构(驼峰式maxTokens、通过inferenceConfig传参数、需要anthropic_version),你用了 Anthropic 原生的蛇形命名(max_tokens),于是被判定为格式错误。

二、背景

Bedrock 的InvokeModel接受的是原始 JSON body,而 Claude on Bedrock 的 body 格式与 Anthropic 官方 API 不同:

Anthropic 原生Bedrock (invoke_model)
max_tokensmax_tokens其实也接受,但inferenceConfig.maxTokens更标准
system(字符串)system是文本块数组[{"text": "..."}]
请求头anthropic-versionbody 里的"anthropic_version": "bedrock-2023-05-31"

最常见的"malformed"来源:

  1. 用了max_tokens但放在错误层级;Bedrock 推荐放在inferenceConfig: { maxTokens: 256 }
  2. system写成字符串而非文本块数组;
  3. 漏了anthropic_version字段;
  4. messages[].content结构不符合 Bedrock 的 content block 规范。

ConverseAPI 则更不同(前面 930/933 已讲),用inferenceConfig.maxTokenssystem作为参数。

三、根因

根因是请求体字段不符合 Bedrock 的 Claude 格式契约

// 错误(Anthropic 原生风格,Bedrock 不接受) { "model": "anthropic.claude-3-5-sonnet-...", "max_tokens": 256, "system": "你是助手", "messages": [{"role": "user", "content": "hi"}] } // -> Malformed input request
// 正确(Bedrock Claude 格式) { "anthropic_version": "bedrock-2023-05-31", "max_tokens": 256, "system": [{"text": "你是助手"}], "messages": [{"role": "user", "content": [{"text": "hi"}]}] }

注意:即便用invoke_modelbodymax_tokens顶层也可接受(Claude on Bedrock 容忍),但更稳妥的是按 Bedrock 约定。关键是system必须是文本块数组anthropic_version必填。

四、最小可运行复现

下面用 boto3 演示"错误结构 vs 正确结构":

import boto3 import json client = boto3.client("bedrock-runtime", region_name="us-west-2") MODEL = "anthropic.claude-3-5-sonnet-20241022-v2:0" def call(body: dict): try: client.invoke_model( modelId=MODEL, contentType="application/json", accept="application/json", body=json.dumps(body).encode(), ) return "ok" except client.exceptions.ValidationException as e: return f"Malformed: {e}" # 错误:system 是字符串 bad = { "anthropic_version": "bedrock-2023-05-31", "max_tokens": 256, "system": "你是助手", # 应为 [{text:...}] "messages": [{"role": "user", "content": [{"text": "hi"}]}], } print(call(bad)) # Malformed # 正确 good = { "anthropic_version": "bedrock-2023-05-31", "max_tokens": 256, "system": [{"text": "你是助手"}], "messages": [{"role": "user", "content": [{"text": "hi"}]}], } print(call(good)) # ok

运行后system为字符串时报 Malformed,改为数组后通过。

五、解决方案(第一层:最小直接修复)

最小修复是按 Bedrock 的 Claude 格式构造 body

import boto3, json client = boto3.client("bedrock-runtime", region_name="us-west-2") body = { "anthropic_version": "bedrock-2023-05-31", "max_tokens": 256, "system": [{"text": "你是乐于助人的助手"}], # 文本块数组 "messages": [ {"role": "user", "content": [{"text": "你好"}]}, ], } resp = client.invoke_model( modelId="anthropic.claude-3-5-sonnet-20241022-v2:0", contentType="application/json", accept="application/json", body=json.dumps(body).encode(), ) print(json.loads(resp["body"].read()))

若改用ConverseAPI,则参数走inferenceConfig

client.converse( modelId=MODEL, system=[{"text": "你是助手"}], # Converse 的 system 也是数组 messages=[{"role": "user", "content": [{"text": "hi"}]}], inferenceConfig={"maxTokens": 256}, # 驼峰 maxTokens )

六、解决方案(第二层:结构化改进)

把"Bedrock Claude 请求体规范化"做成策略,统一system数组化、补全anthropic_version

from dataclasses import dataclass, field from typing import Dict, List @dataclass(frozen=True) class BedrockMalformedInputPolicy: """Bedrock Claude 请求体策略:消除 Malformed input request。 规则: - anthropic_version 必填 - system 必须是文本块数组(非字符串) - messages content 必须是块数组 """ anthropic_version: str = "bedrock-2023-05-31" def normalize_system(self, system) -> List[Dict]: if isinstance(system, str): return [{"text": system}] if isinstance(system, list): return system return [{"text": str(system)}] def build_body(self, *, system, messages, max_tokens: int = 256) -> Dict: if not messages: raise ValueError("messages 不能为空") return { "anthropic_version": self.anthropic_version, "max_tokens": max_tokens, "system": self.normalize_system(system), "messages": messages, } def demo() -> None: policy = BedrockMalformedInputPolicy() body = policy.build_body( system="你是助手", messages=[{"role": "user", "content": [{"text": "hi"}]}], ) assert body["system"] == [{"text": "你是助手"}] print("body 规范化 OK") if __name__ == "__main__": demo()

七、解决方案(第三层:断言 / CI 守护)

import pytest from your_module import BedrockMalformedInputPolicy def test_system_string_to_array(): policy = BedrockMalformedInputPolicy() assert policy.normalize_system("hi") == [{"text": "hi"}] def test_system_array_passthrough(): policy = BedrockMalformedInputPolicy() assert policy.normalize_system([{"text": "x"}]) == [{"text": "x"}] def test_body_has_version(): policy = BedrockMalformedInputPolicy() b = policy.build_body(system="x", messages=[{"role": "user", "content": [{"text": "y"}]}]) assert b["anthropic_version"] == "bedrock-2023-05-31" def test_body_rejects_empty_messages(): policy = BedrockMalformedInputPolicy() with pytest.raises(ValueError): policy.build_body(system="x", messages=[]) def test_messages_content_is_blocks(): policy = BedrockMalformedInputPolicy() b = policy.build_body(system="x", messages=[{"role": "user", "content": [{"text": "y"}]}]) assert isinstance(b["messages"][0]["content"], list)

CI 里加一条:构造请求体后断言system是数组、anthropic_version存在,避免Malformed input request

八、排查清单

  • system是否写成了字符串?Bedrock 要求是文本块数组[{text:...}]
  • 是否漏了anthropic_version: bedrock-2023-05-31
  • 是否混用了 Anthropic 原生max_tokens与 BedrockinferenceConfig.maxTokens?两者层级不同。
  • messages[].content是否是块数组(如[{text:...}])?
  • Converse还是invoke_model?两者参数位置不同。
  • 是否从 Anthropic 官方文档直接搬了 body?Bedrock 字段命名有差异。

九、小结

Bedrock 上用 Claude Sonnet 报Malformed input request,根因是请求体不符合 Bedrock 的 Claude 格式契约——最常见是system写成字符串而非文本块数组、漏了anthropic_version、或max_tokens层级放错。最小修复是按 Bedrock 约定构造(system数组化、补全anthropic_version、参数走inferenceConfig);结构化做法是抽成BedrockMalformedInputPolicy,统一规范化请求体;最后用 pytest 守护"system是数组、anthropic_version存在",杜绝 malformed。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询