Skip to content

feat(bedrock): Add support for AWS Bedrock native structured outputs #2084

@ndgigliotti

Description

@ndgigliotti

Is your feature request related to a problem? Please describe.

AWS Bedrock announced native structured outputs support in February 2026, providing guaranteed JSON schema compliance for Claude 4.5+ models and select open-weight models. Currently, Instructor's Bedrock integration relies on prompt engineering (BEDROCK_JSON mode) or basic tool calling (BEDROCK_TOOLS mode), which can lead to validation failures and retries.

The current implementation:

This approach misses the benefits of Bedrock's native feature:

  • No guaranteed schema compliance (relies on model interpretation)
  • Higher retry rates when validation fails
  • Increased token costs from retries
  • Less predictable production behavior

Describe the solution you'd like

Add support for Bedrock's native structured outputs feature through two complementary approaches, following the patterns established by other providers (OpenAI's TOOLS_STRICT/JSON_SCHEMA, Mistral's MISTRAL_STRUCTURED_OUTPUTS):

1. JSON Schema Output Format

Add a new mode (or enhance existing BEDROCK_JSON to use) that leverages outputConfig.textFormat for the Converse API:

import instructor
from pydantic import BaseModel

client = instructor.from_provider(
    "bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0",
    mode=instructor.Mode.BEDROCK_STRUCTURED_OUTPUTS  # or Mode.JSON_SCHEMA
)

class User(BaseModel):
    name: str
    age: int

user = client.create(
    modelId="anthropic.claude-sonnet-4-5-20250929-v1:0",
    messages=[{"role": "user", "content": "Extract: Jason is 25 years old"}],
    response_model=User,
)
# Response guaranteed to conform to User schema

Implementation approach (based on similar providers):

Follow the pattern from handle_mistral_structured_outputs() in instructor/providers/mistral/utils.py:94-109.

Add handler function in instructor/providers/bedrock/utils.py:

def handle_bedrock_structured_outputs(
    response_model: type[Any], new_kwargs: dict[str, Any]
) -> tuple[type[Any], dict[str, Any]]:
    """
    Handle Bedrock structured outputs mode using native outputConfig.
    
    Kwargs modifications:
    - Adds: "outputConfig" with textFormat.jsonSchema
    - Removes: System prompt JSON instructions (no longer needed)
    """
    schema = response_model.model_json_schema()
    
    new_kwargs["outputConfig"] = {
        "textFormat": {
            "type": "json_schema",
            "structure": {
                "jsonSchema": {
                    "schema": json.dumps(schema),
                    "name": response_model.__name__,
                    "description": response_model.__doc__ or f"Extract {response_model.__name__}"
                }
            }
        }
    }
    
    # Remove any JSON instruction prompts from system messages
    # since native schema enforcement handles this
    
    return response_model, _prepare_bedrock_converse_kwargs_internal(new_kwargs)

2. Strict Tool Use

Enhance BEDROCK_TOOLS mode to support the strict: true flag for tool definitions:

client = instructor.from_provider(
    "bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0",
    mode=instructor.Mode.BEDROCK_TOOLS_STRICT  # or enhance existing BEDROCK_TOOLS
)

Implementation approach:

Update generate_bedrock_schema() in instructor/providers/bedrock/utils.py:19-43 to add strict parameter:

def generate_bedrock_schema(
    response_model: type[Any], 
    strict: bool = False
) -> dict[str, Any]:
    """Generate Bedrock tool schema from a Pydantic model."""
    schema = response_model.model_json_schema()
    
    tool_spec = {
        "name": response_model.__name__,
        "description": response_model.__doc__ or f"Correctly extracted `{response_model.__name__}`",
        "inputSchema": {"json": schema},
    }
    
    if strict:
        tool_spec["strict"] = True
    
    return {"toolSpec": tool_spec}

Update handle_bedrock_tools() to use strict mode when appropriate.

Describe alternatives you've considered

  1. Do nothing: Continue with prompt-based JSON extraction

    • Misses guaranteed schema compliance
    • Higher operational costs from retries
    • Inconsistent with how Instructor handles native structured outputs for other providers
  2. Only add strict tool use, not JSON schema format

    • Simpler initial implementation
    • But incomplete - doesn't cover all use cases
  3. Map to existing generic modes (Mode.JSON_SCHEMA, Mode.TOOLS_STRICT)

    • Cleaner, following mode migration strategy
    • Consistent with mode migration guide
    • Requires ensuring generic modes properly route to Bedrock-specific handlers

Additional context

Official AWS Documentation

Supported Models (as of Feb 2026)

Anthropic Claude:

  • Claude Haiku 4.5 (anthropic.claude-haiku-4-5-20251001-v1:0)
  • Claude Sonnet 4.5 (anthropic.claude-sonnet-4-5-20250929-v1:0)
  • Claude Opus 4.5 (anthropic.claude-opus-4-5-20251101-v1:0)
  • Claude Opus 4.6 (anthropic.claude-opus-4-6-v1)

Open-weight models: Qwen3, OpenAI OSS, DeepSeek V3.1, Gemma 3, MiniMax M2, Mistral variants, Moonshot Kimi K2, NVIDIA Nemotron

API Examples from AWS Docs

Converse API with JSON Schema:

{
  "outputConfig": {
    "textFormat": {
      "type": "json_schema",
      "structure": {
        "jsonSchema": {
          "schema": "{\"type\": \"object\", \"properties\": {...}, \"required\": [...]}",
          "name": "data_extraction",
          "description": "Extract structured data"
        }
      }
    }
  }
}

Converse API with Strict Tools:

{
  "toolConfig": {
    "tools": [{
      "toolSpec": {
        "name": "get_weather",
        "strict": true,
        "inputSchema": {
          "json": {
            "type": "object",
            "properties": {...}
          }
        }
      }
    }]
  }
}

Related Code References

Files to modify:

  • instructor/providers/bedrock/utils.py - Add handlers for structured outputs
  • instructor/providers/bedrock/client.py - Update mode validation
  • instructor/mode.py - Add new modes if needed (or map to generic modes)
  • docs/integrations/bedrock.md - Document the new feature
  • tests/llm/test_bedrock/ - Add tests for structured outputs

Similar implementations to reference:

Benefits of Implementation

  1. Production reliability: Guaranteed schema compliance eliminates parsing errors
  2. Cost reduction: Fewer retries from validation failures
  3. Developer experience: Simpler code without custom validation loops
  4. Consistency: Aligns Bedrock integration with other providers' native structured outputs support
  5. Future-proof: Leverages AWS's native feature rather than workarounds

Compatibility Notes

From AWS documentation:

  • Works with Converse, ConverseStream, InvokeModel, InvokeModelWithResponseStream APIs
  • Compatible with cross-region inference and batch inference
  • Incompatible with citations for Anthropic models (returns 400 error if both enabled)
  • Schema compilation caches for 24 hours (first request may take longer)

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or requestpythonPull requests that update python codestatus:pending-mergeRelated PR is pending mergetype:docs-outdatedDocumentation is outdated or needs updating

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions