Skip to content

feat(bedrock): add native structured output support#2093

Open
layertwo wants to merge 1 commit intostrands-agents:mainfrom
layertwo:feat/bedrock-native-structured-output
Open

feat(bedrock): add native structured output support#2093
layertwo wants to merge 1 commit intostrands-agents:mainfrom
layertwo:feat/bedrock-native-structured-output

Conversation

@layertwo
Copy link
Copy Markdown

@layertwo layertwo commented Apr 8, 2026

Description

Bedrock now supports native structured output for supported models, enforcing JSON schema compliance at the token generation level via outputConfig.textFormat. Currently, Strands uses a tool-based workaround for structured_output() - converting the Pydantic model into a fake tool spec and forcing tool use. This is indirect and can lead to extra round-trips when the model doesn't format correctly.

Native structured output eliminates the workaround by letting Bedrock guarantee schema-compliant JSON responses directly.

Public API Changes

New structured_output_mode config option on BedrockModel:

# Before: tool-based structured output (still the default)
model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-5-20250929-v1:0")

# After: opt-in to native structured output
model = BedrockModel(
    model_id="us.anthropic.claude-sonnet-4-5-20250929-v1:0",
    structured_output_mode="native",
)

agent = Agent(model=model)
result = agent("Describe the weather in Seattle", structured_output_model=WeatherReport)
weather = result.structured_output

New public utility convert_pydantic_to_json_schema() exported from strands.tools.structured_output — converts a Pydantic model to a JSON schema dict with additionalProperties: false injected recursively, suitable for Bedrock's outputConfig.textFormat.structure.jsonSchema.

No breaking changes. Default behavior (structured_output_mode="tool") is unchanged.

Use Cases

  • Schema-guaranteed responses: Native mode enforces JSON schema at the token generation level, eliminating malformed output
  • Reduced latency: No extra round-trips from tool-use forcing when the model doesn't comply on the first attempt
  • Cleaner agent interactions: No fake tool registration or tool call artifacts in the conversation history

Related Issues

Resolves #1652

Documentation PR

strands-agents/docs#749

Type of Change

New feature

Testing

How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli

  • Unit tests for convert_pydantic_to_json_schema() covering basic, nested, optional, and list-of-objects schemas
  • Unit tests for _format_request() with output_config
  • Unit tests for structured_output() in native mode (mocked Bedrock responses)
  • hatch run prepare passes across Python 3.10-3.14
  • Manual testing with live Bedrock API (Claude Sonnet 4.5) confirming native mode works at both agent and model level
  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@github-actions github-actions bot added the size/m label Apr 8, 2026
@layertwo layertwo force-pushed the feat/bedrock-native-structured-output branch from e355fa8 to d4381f6 Compare April 8, 2026 18:33
@github-actions github-actions bot added size/l and removed size/m labels Apr 8, 2026
…textFormat

Add opt-in native structured output mode for BedrockModel that uses
Bedrock's outputConfig.textFormat API for schema-constrained responses,
replacing the tool-based workaround when enabled.

Model-level:
- Add `structured_output_mode` config ("tool" | "native", defaults to "tool")
- Add `convert_pydantic_to_json_schema()` utility with recursive
  `additionalProperties: false` injection
- Thread `output_config` through stream() -> _stream() -> _format_request()
- Native mode parses JSON text response instead of extracting tool use args

Agent-level:
- StructuredOutputContext gains native_mode: skips tool registration,
  stores output_config, and extracts results from text responses
- event_loop_cycle handles end_turn as success in native mode
- stream_messages passes output_config through to model.stream()

Closes strands-agents#1652
@layertwo layertwo force-pushed the feat/bedrock-native-structured-output branch from d4381f6 to 23bae41 Compare April 8, 2026 18:45
@github-actions github-actions bot added size/m and removed size/l labels Apr 8, 2026
@layertwo layertwo marked this pull request as ready for review April 8, 2026 19:02
@layertwo layertwo changed the title feat(bedrock): add native structured output support via outputConfig.… feat(bedrock): add native structured output support Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Structured Outputs Bedrock Model

1 participant