Structured outputs on Amazon Bedrock: Schema-compliant AI responses

Structured outputs on Amazon Bedrock: Schema-compliant AI responses

Today, we’re announcing structured outputs on Amazon Bedrock—a capability that fundamentally transforms how you can obtain validated JSON responses from foundation models through constrained decoding for schema compliance.

This represents a paradigm shift in AI application development. Instead of validating JSON responses and writing fallback logic for when they fail, you can move straight to building with the data. With structured outputs, you can build zero-validation data pipelines that trust model outputs, reliable agentic systems that confidently call external functions, and simplified application architectures without retry logic.

In this post, we explore the challenges of traditional JSON generation and how structured outputs solves them. We cover the two core mechanisms—JSON Schema output format and strict tool use—along with implementation details, best practices, and practical code examples. Whether you’re building data extraction pipelines, agentic workflows, or AI-powered APIs, you’ll learn how to use structured outputs to create reliable, production-ready applications. Our companion Jupyter notebook provides hands-on examples for every feature covered here.

The problem with traditional JSON generation

For years, getting structured data from language models meant crafting detailed prompts, hoping for the best, and building elaborate error-handling systems. Even with careful prompting, developers routinely encounter:

  • Parsing failures: Invalid JSON syntax that breaks json.loads() calls
  • Missing fields: Required data points absent from responses
  • Type mismatches: Strings where integers are expected, breaking downstream processing
  • Schema violations: Responses that technically parse but don’t match your data model

In production systems, these failures compound. A single malformed response can cascade through your pipeline, requiring retries that increase latency and costs. For agentic workflows where models call tools, invalid parameters can break function calls entirely.

Consider a booking system requiring passengers: int. Without schema enforcement, the model might return passengers: "two" or passengers: "2"—syntactically valid JSON, but semantically wrong for your function signature.

What changes with structured outputs

Structured outputs on Amazon Bedrock isn’t incremental improvement—it’s a fundamental shift from probabilistic to deterministic output formatting. Through constrained decoding, Amazon Bedrock constrains model responses to conform to your specified JSON schema. Two complementary mechanisms are available:

Feature Purpose Use case
JSON Schema output format Control the model’s response format Data extraction, report generation, API responses
Strict tool use Validate tool parameters Agentic workflows, function calling, multi-step automation

These features can be used independently or together, giving you precise control over both what the model outputs and how it calls your functions.

What structured outputs delivers:

  • Always valid: No more JSON.parse() errors or parsing exceptions
  • Type safe: Field types are enforced and required fields are always present
  • Reliable: No retries needed for schema violations
  • Production ready: Deploy with confidence at enterprise scale

How structured outputs works

Structured outputs uses constrained sampling with compiled grammar artifacts. Here’s what happens when you make a request:

  1. Schema validation: Amazon Bedrock validates your JSON schema against the supported JSON Schema Draft 2020-12 subset
  2. Grammar compilation: For new schemas, Amazon Bedrock compiles a grammar (first request might take longer)
  3. Caching: Compiled grammars are cached for 24 hours, making subsequent requests faster
  4. Constrained generation: The model generates tokens that produce valid JSON matching your schema

Performance considerations:

  • First request latency: Initial compilation might add latency to new schemas
  • Cached performance: Subsequent requests with identical schemas have minimal overhead
  • Cache scope: Grammars are cached per account for 24 hours from first access

Changing the JSON schema structure or a tool’s input schema invalidates the cache, but changing only name or description fields does not.

Getting started with structured outputs

The following example demonstrates structured outputs with the Converse API:

import boto3
import json
# Initialize the Bedrock Runtime client
bedrock_runtime = boto3.client(
    service_name='bedrock-runtime',
    region_name='us-east-1'  # Choose your preferred region
)
# Define your JSON schema
extraction_schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string", "description": "Customer name"},
        "email": {"type": "string", "description": "Customer email address"},
        "plan_interest": {"type": "string", "description": "Product plan of interest"},
        "demo_requested": {"type": "boolean", "description": "Whether a demo was requested"}
    },
    "required": ["name", "email", "plan_interest", "demo_requested"],
    "additionalProperties": False
}
# Make the request with structured outputs
response = bedrock_runtime.converse(
    modelId="us.anthropic.claude-opus-4-5-20251101-v1:0",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "text": "Extract the key information from this email: John Smith (john@example.com) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm."
                }
            ]
        }
    ],
    inferenceConfig={
        "maxTokens": 1024
    },
    outputConfig={
        "textFormat": {
            "type": "json_schema",
            "structure": {
                "jsonSchema": {
                    "schema": json.dumps(extraction_schema),
                    "name": "lead_extraction",
                    "description": "Extract lead information from customer emails"
                }
            }
        }
    }
)
# Parse the schema-compliant JSON response
result = json.loads(response["output"]["message"]["content"][0]["text"])
print(json.dumps(result, indent=2))

Output:

{
  "name": "John Smith",
  "email": "john@example.com",
  "plan_interest": "Enterprise",
  "demo_requested": true
}

The response conforms to your schema—no additional validation required.

Requirements and best practices

To use structured outputs effectively, follow these guidelines:

  • Set additionalProperties: false on all objects. This is required for structured outputs to work. Without it, your schema won’t be accepted.
{
  "type": "object",
  "properties": {
    "name": {"type": "string"}
  },
  "required": ["name"],
  "additionalProperties": false
}
  • Use descriptive field names and descriptions. Models use property names and descriptions to understand what data to extract. Clear names like customer_email outperform generic names like field1.
  • Use enum for constrained values. When a field has a limited set of valid values, use enum to constrain options. This improves accuracy and produces valid values.
  • Start basic, then add complexity. Begin with the minimum required fields and add complexity incrementally. Basic schemas compile faster and are easier to maintain.
  • Reuse schemas to benefit from caching. Structure your application to reuse schemas across requests. The 24-hour grammar cache significantly improves performance for repeated queries.
  • Check stopReason in every response. Two scenarios can produce non-conforming responses: refusals (when the model declines for safety reasons) and token limits (when max_tokens is reached before completing). Handle both cases in your code.
  • Test with realistic data before deployment. Validate your schemas against production-representative inputs. Edge cases in real data often reveal schema design issues.

Supported JSON Schema features:

  • All basic types: objectarraystringintegernumberbooleannull
  • enum (strings, numbers, bools, or nulls only)
  • constanyOfallOf (with limitations)
  • $ref$def, and definitions (internal references only)
  • String formats: date-timetimedatedurationemailhostnameuriipv4ipv6uuid
  • Array minItems (only values 0 and 1)

Not supported:

  • Recursive schemas
  • External $ref references
  • Numerical constraints (minimummaximummultipleOf)
  • String constraints (minLengthmaxLength)
  • additionalProperties set to anything other than false

Strict tool use for agentic workflows

When building applications where models call tools, set strict: true in your tool definition to constrain tool parameters to match your input schema exactly:

import boto3
import json
bedrock_runtime = boto3.client('bedrock-runtime', region_name='us-east-1')
response = bedrock_runtime.converse(
    modelId="us.anthropic.claude-opus-4-5-20251101-v1:0",
    messages=[
        {
            "role": "user",
            "content": [{"text": "What's the weather like in San Francisco?"}]
        }
    ],
    inferenceConfig={"maxTokens": 1024},
    toolConfig={
        "tools": [
            {
                "toolSpec": {
                    "name": "get_weather",
                    "description": "Get the current weather for a specified location",
                    "strict": True,  # Enable strict mode
                    "inputSchema": {
                        "json": {
                            "type": "object",
                            "properties": {
                                "location": {
                                    "type": "string",
                                    "description": "The city and state, e.g., San Francisco, CA"
                                },
                                "unit": {
                                    "type": "string",
                                    "enum": ["celsius", "fahrenheit"],
                                    "description": "Temperature unit"
                                }
                            },
                            "required": ["location", "unit"],
                            "additionalProperties": False
                        }
                    }
                }
            }
        ]
    }
)
# Tool inputs conform to the schema
for content_block in response["output"]["message"]["content"]:
    if "toolUse" in content_block:
        tool_input = content_block["toolUse"]["input"]
        print(f"Tool: {content_block['toolUse']['name']}")
        print(f"Input: {json.dumps(tool_input, indent=2)}")

With strict: true, structured outputs constrains the output so that:

  • The location field is always a string
  • The unit field is always either celsius or fahrenheit
  • No unexpected fields appear in the input

Practical applications across industries

The notebook demonstrates use cases that span industries:

  • Financial services: Extract structured data from earnings reports, loan applications, and compliance documents. With structured outputs, every required field is present and correctly typed for downstream processing.
  • Healthcare: Parse clinical notes into structured, schema-compliant records. Extract patient information, diagnoses, and treatment plans into validated JSON for EHR integration.
  • Ecommerce: Build reliable product catalog enrichment pipelines. Extract specifications, categories, and attributes from product descriptions with consistent, reliable results.
  • Legal: Analyze contracts and extract key terms, parties, dates, and obligations into structured formats suitable for contract management systems.
  • Customer service: Build intelligent ticket routing and response systems where extracted intents, sentiments, and entities match your application’s data model.

Choosing the right approach

Our testing revealed clear patterns for when to use each feature:

Use JSON Schema output format when:

  • You need the model’s response in a specific structure
  • Building data extraction pipelines
  • Generating API-ready responses
  • Creating structured reports or summaries

Use strict tool use when:

  • Building agentic systems that call external functions
  • Implementing multi-step workflows with tool chains
  • Requiring validated parameter types for function calls
  • Connecting AI to databases, APIs, or external services

Use both together when:

  • Building complex agents that need validated tool calls and structured final responses
  • Creating systems where intermediate tool results feed into structured outputs
  • Implementing enterprise workflows requiring end-to-end schema compliance

API comparison: Converse compared to InvokeModel

Both the Converse API and InvokeModel API support structured outputs, with slightly different parameter formats:

Aspect Converse API InvokeModel (Anthropic Claude) InvokeModel (open-weight models)
Schema location outputConfig.textFormat output_config.format response_format
Tool strict flag toolSpec.strict tools[].strict tools[].function.strict
Schema format JSON string in jsonSchema.schema JSON object in schema JSON object in json_schema.schema
Best for Conversational workflows Single-turn inference (Claude) Single-turn inference (open-weight)

Note: The InvokeModel API uses different request field names depending on the model type. For Anthropic Claude models, use output_config.format for JSON schema outputs. For open-weight models, use response_format instead.

Choose the Converse API for multi-turn conversations and the InvokeModel API when you need direct model access with provider-specific request formats.

Supported models and availability

Structured outputs is generally available in all commercial AWS Regions for select Amazon Bedrock model providers:

  • Anthropic
  • DeepSeek
  • Google
  • MiniMax
  • Mistral AI
  • Moonshot AI
  • NVIDIA
  • OpenAI
  • Qwen

The feature works seamlessly with:

  • Cross-Region inference: Use structured outputs across AWS Regions without additional setup
  • Batch inference: Process large volumes with schema-compliant outputs
  • Streaming: Stream structured responses with ConverseStream or InvokeModelWithResponseStream

Conclusion

In this post, you discovered how structured outputs on Amazon Bedrock reduce the uncertainty of AI-generated JSON through validated, schema-compliant responses. By using JSON Schema output format and strict tool use, you can build reliable data extraction pipelines, robust agentic workflows, and production-ready AI applications—without custom parsing or validation logic.Whether you’re extracting data from documents, building intelligent automation, or creating AI-powered APIs, structured outputs deliver the reliability your applications demand.

Structured outputs is now generally available on Amazon Bedrock. To use structured outputs with the Converse APIs, update to the latest AWS SDK. To learn more, see the Amazon Bedrock documentation and explore our sample notebook.

What workflows could validated, schema-compliant JSON unlock in your organization? The notebook provides everything you need to find out.


About the authors

Jeffrey Zeng

Jeffrey Zeng is a Worldwide Specialist Solutions Architect for Generative AI at AWS, leading third-party models on Amazon Bedrock. He focuses on agentic coding and workflows, with hands-on experience helping customers build and deploy AI solutions from proof-of-concept to production.

Jonathan Evans

Jonathan Evans is a Worldwide Solutions Architect for Generative AI at AWS, where he helps customers leverage cutting-edge AI technologies with Anthropic Claude models on Amazon Bedrock, to solve complex business challenges. With a background in AI/ML engineering and hands-on experience supporting machine learning workflows in the cloud, Jonathan is passionate about making advanced AI accessible and impactful for organizations of all sizes.

​ 

Leave a Comment

Your email address will not be published. Required fields are marked *

Sign In

Register

Reset Password

Please enter your username or email address, you will receive a link to create a new password via email.

Scroll to Top