公司动态

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

📅 2026/8/21 19:24:43
【Bug已解决】Getting Malformed input request when trying to use Claude Sonet Model by Bedrock 解决方案
【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_tokens、messages、system却在这报错用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来源用了max_tokens但放在错误层级Bedrock 推荐放在inferenceConfig: { maxTokens: 256 }system写成字符串而非文本块数组漏了anthropic_version字段messages[].content结构不符合 Bedrock 的 content block 规范。而ConverseAPI 则更不同前面 930/933 已讲用inferenceConfig.maxTokens、system作为参数。三、根因根因是请求体字段不符合 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_model的bodymax_tokens顶层也可接受Claude on Bedrock 容忍但更稳妥的是按 Bedrock 约定。关键是system必须是文本块数组anthropic_version必填。四、最小可运行复现下面用 boto3 演示错误结构 vs 正确结构import boto3 import json client boto3.client(bedrock-runtime, region_nameus-west-2) MODEL anthropic.claude-3-5-sonnet-20241022-v2:0 def call(body: dict): try: client.invoke_model( modelIdMODEL, contentTypeapplication/json, acceptapplication/json, bodyjson.dumps(body).encode(), ) return ok except client.exceptions.ValidationException as e: return fMalformed: {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 格式构造 bodyimport boto3, json client boto3.client(bedrock-runtime, region_nameus-west-2) body { anthropic_version: bedrock-2023-05-31, max_tokens: 256, system: [{text: 你是乐于助人的助手}], # 文本块数组 messages: [ {role: user, content: [{text: 你好}]}, ], } resp client.invoke_model( modelIdanthropic.claude-3-5-sonnet-20241022-v2:0, contentTypeapplication/json, acceptapplication/json, bodyjson.dumps(body).encode(), ) print(json.loads(resp[body].read()))若改用ConverseAPI则参数走inferenceConfigclient.converse( modelIdMODEL, system[{text: 你是助手}], # Converse 的 system 也是数组 messages[{role: user, content: [{text: hi}]}], inferenceConfig{maxTokens: 256}, # 驼峰 maxTokens )六、解决方案第二层结构化改进把Bedrock Claude 请求体规范化做成策略统一system数组化、补全anthropic_versionfrom dataclasses import dataclass, field from typing import Dict, List dataclass(frozenTrue) 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(systemx, 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(systemx, messages[]) def test_messages_content_is_blocks(): policy BedrockMalformedInputPolicy() b policy.build_body(systemx, 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 官方文档直接搬了 bodyBedrock 字段命名有差异。九、小结Bedrock 上用 Claude Sonnet 报Malformed input request根因是请求体不符合 Bedrock 的 Claude 格式契约——最常见是system写成字符串而非文本块数组、漏了anthropic_version、或max_tokens层级放错。最小修复是按 Bedrock 约定构造system数组化、补全anthropic_version、参数走inferenceConfig结构化做法是抽成BedrockMalformedInputPolicy统一规范化请求体最后用 pytest 守护system是数组、anthropic_version存在杜绝 malformed。