Bedrock の Structured outputs が Claude 全モデルでサポート、最新 Haiku 5.5 で試してみた

Bedrock の Structured outputs が Claude 全モデルでサポート、最新 Haiku 5.5 で試してみた

Amazon Bedrock の Structured outputs を Claude Haiku 5.5 で検証しました。InvokeModel、Converse、strict tool use のいずれもスキーマ通りの JSON が返り、JP と global の結果は同じでした。応答の先頭が thinking ブロックになる場合があるため、JSON は text ブロックから取り出す必要がありました。
2026.10.21

はじめに

2026年10月20日、Amazon Bedrock の Structured outputs が、bedrock-runtime と bedrock-mantle(Messages API)の両エンドポイントで、Claude の全モデルに対応したと案内されました。

https://aws.amazon.com/jp/about-aws/whats-new/2026/10/claude-structured-outputs-bedrock/

Structured outputs 自体は 2026年2月4日に一般提供されている機能でしたが、今回、Haiku 5.5 など、最新のモデルカードにも対応が明記されました。

https://dev.classmethod.jp/articles/amazon-bedrock-structured-outputs-json/

https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-haiku-5-5.html

この記事では、bedrock-runtime のエンドポイントを対象に、InvokeModel、Converse、strict tool use の3つのリクエスト形を Claude Haiku 5.5 で実行し、応答の構造を確認しました。

検証環境

項目 値
リージョン ap-northeast-1
Haiku 5.5 のモデル ID global.anthropic.claude-haiku-5-5、jp.anthropic.claude-haiku-5-5
boto3 1.43.116

3つのリクエスト形の動作確認

CSV 集計、sentiment 分類、商品検索のツール呼び出しを、global プロファイルで実行しました。

リクエスト形 入力 結果
InvokeModel の output_config.format CSV 集計 total_sales 746000、total_items 36
Converse の outputConfig.textFormat CSV 集計 同じ値
Converse の outputConfig.textFormat sentiment 分類 {"sentiment": "positive"}
Converse の strict tool use 商品検索 {"category": "electronics", "price_limit": 50000}
InvokeModel の strict tool use 商品検索 同じ引数

5つの応答はすべてスキーマ通りでした。

InvokeModel で CSV 集計を実行するコード全体

text の取り出し方は、次の節で説明します。

import json

import boto3

MODEL_ID = "global.anthropic.claude-haiku-5-5"
client = boto3.client("bedrock-runtime", region_name="ap-northeast-1")

CSV_INPUT = """date,product,quantity,price,region
2026-01-15,ノートPC,5,89800,東京
2026-01-15,マウス,20,2980,大阪
2026-01-16,キーボード,8,12800,東京
2026-01-16,モニター,3,45000,福岡"""

CSV_SCHEMA = {
    "type": "object",
    "properties": {
        "total_sales": {"type": "integer", "description": "総売上金額"},
        "total_items": {"type": "integer", "description": "総販売数"},
        "by_region": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {"region": {"type": "string"}, "sales": {"type": "integer"}},
                "required": ["region", "sales"],
                "additionalProperties": False,
            },
        },
        "top_product": {"type": "string", "description": "最も売上が高い商品"},
    },
    "required": ["total_sales", "total_items", "by_region", "top_product"],
    "additionalProperties": False,
}

response = client.invoke_model(
    modelId=MODEL_ID,
    body=json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 1024,
        "messages": [{"role": "user", "content": f"以下のCSVデータを集計してください:\n\n{CSV_INPUT}"}],
        "output_config": {"format": {"type": "json_schema", "schema": CSV_SCHEMA}},
    }),
)
result = json.loads(response["body"].read())
text = next(b["text"] for b in result["content"] if b["type"] == "text")
print(json.dumps(json.loads(text), indent=2, ensure_ascii=False))

実行結果は次のとおりでした。

{
  "total_sales": 746000,
  "total_items": 36,
  "by_region": [
    {
      "region": "東京",
      "sales": 551400
    },
    {
      "region": "大阪",
      "sales": 59600
    },
    {
      "region": "福岡",
      "sales": 135000
    }
  ],
  "top_product": "ノートPC"
}

Converse では、呼び出しと text の取り出しが次のように変わります。client、MODEL_ID、CSV_INPUT、CSV_SCHEMA は共通です。

response = client.converse(
    modelId=MODEL_ID,
    messages=[{"role": "user", "content": [{"text": f"以下のCSVデータを集計してください:\n\n{CSV_INPUT}"}]}],
    inferenceConfig={"maxTokens": 1024},
    outputConfig={"textFormat": {
        "type": "json_schema",
        "structure": {"jsonSchema": {"schema": json.dumps(CSV_SCHEMA), "name": "sales_summary"}},
    }},
)
blocks = response["output"]["message"]["content"]
text = next(b["text"] for b in blocks if "text" in b)
print(json.dumps(json.loads(text), indent=2, ensure_ascii=False))

strict の位置は、Converse では toolSpec の中、InvokeModel ではツール定義の直下です。TOOL_SCHEMA は両方で共通です。

TOOL_SCHEMA = {
    "type": "object",
    "properties": {
        "category": {"type": "string", "enum": ["electronics", "books"]},
        "price_limit": {"type": "integer"},
    },
    "required": ["category", "price_limit"],
    "additionalProperties": False,
}
# Converse
tool_config = {
    "tools": [{
        "toolSpec": {
            "name": "search_products",
            "description": "商品を検索する",
            "strict": True,
            "inputSchema": {"json": TOOL_SCHEMA},
        }
    }],
    "toolChoice": {"auto": {}},
}
# InvokeModel
tools = [{
    "name": "search_products",
    "description": "商品を検索する",
    "strict": True,
    "input_schema": TOOL_SCHEMA,
}]

JP プロファイルでは、CSV 集計(InvokeModel、Converse)と sentiment 分類(Converse)を実行しました。結果は global と同じで、集計は total_sales 746000、total_items 36、sentiment は positive でした。

CSV 集計の応答に含まれる thinking ブロック

Haiku 5.5 の既定は adaptive thinking で、effort は medium です。

https://docs.aws.amazon.com/bedrock/latest/userguide/claude-messages-adaptive-thinking.html

thinking を指定していないのに、CSV 集計の応答には thinking ブロックが含まれていました。content の並びは、InvokeModel では thinking、text の順、Converse では reasoningContent、text の順でした。global、JP ともに thinking の本文は空で、signature だけが入っていました。

一方、sentiment 分類の応答は text ブロックだけ、strict tool use の応答は toolUse(Converse)または tool_use(InvokeModel)のブロックだけでした。

result["content"][0]["text"] のように先頭のブロックから text を読むコードでは、先頭が thinking ブロックの場合に JSON を取り出せません。InvokeModel では type が text のブロックを、Converse では text キーを持つブロックを選ぶようにします。

# InvokeModel
text = next(b["text"] for b in result["content"] if b["type"] == "text")
data = json.loads(text)
# Converse
blocks = response["output"]["message"]["content"]
text = next(b["text"] for b in blocks if "text" in b)
data = json.loads(text)

まとめ

2026年10月7日にリリースされた Claude Haiku 5.5 で、Structured outputs によりスキーマ通りの JSON を取得できました。

https://dev.classmethod.jp/articles/bedrock-claude-haiku-5-5/

Bedrock の Claude モデルで応答の形式が安定しない場合や、最新モデルのモデルカードにサポートの記載がなく Structured outputs を見送っていた場合は、今回正式にサポートされた Structured outputs での JSON 取得を試してみてください。


Claudeならクラスメソッドにお任せください

クラスメソッドは、Anthropic社とリセラー契約を締結しています。各種製品ガイドから、業種別の活用法、フェーズごとのお悩み解決などサービス支援ページにまとめております。まずはご覧いただき、お気軽にご相談ください。

サービス詳細を見る

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事