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
@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
@layertwo layertwo force-pushed the feat/bedrock-native-structured-output branch from 23bae41 to 7a0d12f Compare April 10, 2026 18:50
@github-actions github-actions bot added size/m and removed size/m labels Apr 10, 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:
- When native_mode is enabled, the agent loop runs normally with tools
  and thinking. On end_turn, calls model.structured_output() for final
  formatting instead of forcing tool use (which disables thinking).

Closes strands-agents#1652
@layertwo layertwo force-pushed the feat/bedrock-native-structured-output branch from 7a0d12f to 9e48c5e Compare April 10, 2026 19:44
@github-actions github-actions bot added size/m and removed size/m labels Apr 10, 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