Skip to content

Structured Output

Structured output enables you to get type-safe, validated responses from language models using Pydantic models. Instead of receiving raw text that you need to parse, you can define the exact structure you want and receive a validated Python object that matches your schema. This transforms unstructured LLM outputs into reliable, program-friendly data structures that integrate seamlessly with your application's type system and validation rules.

What is Structured Output?

Structured output allows you to constrain language model responses to follow a specific schema defined by a Pydantic model. This ensures responses are properly formatted, validated, and type-safe, eliminating the need for manual parsing of text responses.

flowchart LR
    A[Pydantic Model] --> B[Agent.structured_output]

    subgraph Process[" "]
        direction TB
        C[convert_pydantic_to_tool_spec] --> D[LLM Response]
    end

    B --> Process
    Process --> E[Validated Pydantic Model]

The conversion to tool spec happens behind the scenes

Key benefits:

  • Type Safety: Get typed Python objects instead of raw strings
  • Automatic Validation: Pydantic validates responses against your schema
  • Clear Documentation: Schema serves as documentation of expected output
  • IDE Support: IDE type hinting from LLM-generated responses
  • Error Prevention: Catch malformed responses early

How It Works

The structured output system converts your Pydantic models into tool specifications that guide the language model to produce correctly formatted responses. Various model providers supported in Strands Agents sdk-python can work with these specifications, with some supporting Pydantic BaseModel directly.

Strands handles this through the Agent.structured_output() method, which manages the conversion, validation, and response processing automatically.

Usage

Define your desired output structure using Pydantic models:

from pydantic import BaseModel, Field
from typing import Optional, List

class WeatherForecast(BaseModel):
    """Complete weather forecast information."""
    location: str = Field(description="The location for this forecast")
    current_time: str = Field(description="Current time in HH:MM format")
    current_weather: str = Field(description="Current weather conditions")
    temperature: Optional[float] = Field(default=None, description="Temperature in Celsius")
    forecast_days: List[str] = Field(default_factory=list, description="Multi-day forecast")

Then use the Agent.structured_output() method:

Basic Usage

Extract structured information from text:

from pydantic import BaseModel
from strands import Agent

class PersonInfo(BaseModel):
    name: str
    age: int
    occupation: str

agent = Agent()
result = agent.structured_output(
    PersonInfo, 
    "John Smith is a 30-year-old software engineer"
)

print(f"Name: {result.name}")      # "John Smith"
print(f"Age: {result.age}")        # 30
print(f"Job: {result.occupation}") # "software engineer"

Using Conversation History

Structured output can work with existing conversation context:

agent = Agent()

# Build up conversation context
agent("What do you know about Paris, France?")
agent("Tell me about the weather there in spring.")

# Extract structured information with a prompt
class CityInfo(BaseModel):
    city: str
    country: str
    population: Optional[int] = None
    climate: str

# Uses existing conversation context with a prompt
result = agent.structured_output(CityInfo, "Extract structured information about Paris")

Complex Nested Models

Handle sophisticated data structures:

from typing import List
from pydantic import BaseModel, Field

class Address(BaseModel):
    street: str
    city: str
    country: str
    postal_code: Optional[str] = None

class Contact(BaseModel):
    email: Optional[str] = None
    phone: Optional[str] = None

class Person(BaseModel):
    """Complete person information."""
    name: str = Field(description="Full name of the person")
    age: int = Field(description="Age in years")
    address: Address = Field(description="Home address")
    contacts: List[Contact] = Field(default_factory=list, description="Contact methods")
    skills: List[str] = Field(default_factory=list, description="Professional skills")

agent = Agent()
result = agent.structured_output(
    Person,
    "Extract info: Jane Doe, a systems admin, 28, lives at 123 Main St, New York, NY. Email: jane@example.com"
)

print(result.name)                    # "Jane Doe"
print(result.address.city)            # "New York"
print(result.contacts[0].email)       # "jane@example.com"
print(result.skills)                  # ["systems admin"]

Refer to Pydantic documentation for details on:

Error Handling

from pydantic import ValidationError

try:
    result = agent.structured_output(MyModel, prompt)
except ValidationError as e:
    print(f"Validation failed: {e}")
    # Handle appropriately - options include:
    # 1. Retry with a more specific prompt
    # 2. Fall back to a simpler model
    # 3. Extract partial information from the error

Best Practices

  • Keep models focused: Define specific models for clear purposes
  • Use descriptive field names: Include helpful descriptions with Field
  • Handle errors gracefully: Implement proper error handling strategies with fallbacks
  • Extract key data at conversation completion: Use structured output at the end of agent workflows to distill conversations into actionable data structures