> ## Documentation Index
> Fetch the complete documentation index at: https://notte-experiment-visibility-md-links.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured Output

> Get type-safe, structured responses from agents using Pydantic models

Agents can return structured data in a specific format using Pydantic models, ensuring type safety and validation.

## Overview

By default, agents return unstructured text answers:

{/* @sniptest testers/agents/structured-output/overview_default.py */}

```python overview_default.py theme={null}
result = agent.run(task="Find the contact email")
print(result.answer)  # "contact@example.com"
```

With structured output, define the exact format you want:

{/* @sniptest testers/agents/structured-output/overview_structured.py */}

```python overview_structured.py theme={null}
agent = client.Agent(session=session)
result = agent.run(task="Find contact info", response_format=ContactInfo)
if result.success and result.answer:
    contact = ContactInfo.model_validate_json(result.answer)
    print(contact.email)  # Type-safe access
```

## Basic Example

Define a Pydantic model and pass it to `response_format`:

{/* @sniptest testers/agents/structured-output/basic_example.py */}

```python theme={null}
from notte_sdk import NotteClient
from pydantic import BaseModel

client = NotteClient()


class Product(BaseModel):
    name: str
    price: float
    in_stock: bool


with client.Session() as session:
    agent = client.Agent(session=session)

    result = agent.run(
        task="Extract product information",
        url="https://example.com/product/123",
        response_format=Product,
    )

    # Parse and access
    if result.success and result.answer:
        product = Product.model_validate_json(result.answer)
        print(f"{product.name}: ${product.price}")
        if product.in_stock:
            print("Available!")
```

## Complex Models

### Nested Structures

Models can contain nested objects:

{/* @sniptest testers/agents/structured-output/nested_structures.py */}

```python nested_structures.py theme={null}
agent = client.Agent(session=session)
result = agent.run(task="Extract company information", response_format=Company)

if result.success and result.answer:
    company = Company.model_validate_json(result.answer)
    print(company.name)
    print(company.address.city)
```

### Lists of Objects

Extract multiple items:

{/* @sniptest testers/agents/structured-output/lists_of_objects.py */}

```python lists_of_objects.py theme={null}
from notte_sdk import NotteClient
from pydantic import BaseModel


class Review(BaseModel):
    author: str
    rating: int
    comment: str


class ReviewList(BaseModel):
    reviews: list[Review]


client = NotteClient()
with client.Session() as session:
    agent = client.Agent(session=session)
    result = agent.run(
        task="Extract all product reviews",
        response_format=ReviewList,
    )

    # Iterate over reviews
    if result.success and result.answer:
        data = ReviewList.model_validate_json(result.answer)
        for review in data.reviews:
            print(f"{review.author}: {review.rating}/5")
            print(review.comment)
```

### Optional Fields

Use `None` for optional fields:

{/* @sniptest testers/agents/structured-output/optional_fields.py */}

```python theme={null}
from pydantic import BaseModel


class Article(BaseModel):
    title: str
    author: str | None  # May not always be present
    date: str | None
    content: str
```

## Use Cases

### E-commerce Data Extraction

Extract structured product data:

{/* @sniptest testers/agents/structured-output/ecommerce_extraction.py */}

```python ecommerce_extraction.py theme={null}
class ProductListing(BaseModel):
    name: str
    price: float
    original_price: float | None
    rating: float
    review_count: int
    availability: str
    seller: str


client = NotteClient()
with client.Session() as session:
    agent = client.Agent(session=session)
    result = agent.run(
        task="Extract product listing information",
        url="https://store.example.com/products/laptop",
        response_format=ProductListing,
    )
```

### Lead Generation

Extract structured contact information:

{/* @sniptest testers/agents/structured-output/lead_generation.py */}

```python lead_generation.py theme={null}
class BusinessLead(BaseModel):
    company_name: str
    contact_email: str | None
    phone: str | None
    website: str
    industry: str
    employee_count: str | None


client = NotteClient()
with client.Session() as session:
    agent = client.Agent(session=session)
    result = agent.run(
        task="Extract business information from this company page",
        url="https://example.com/about",
        response_format=BusinessLead,
    )
```

### Job Listings

Extract job posting details:

{/* @sniptest testers/agents/structured-output/job_listings.py */}

```python job_listings.py theme={null}
class JobPosting(BaseModel):
    title: str
    company: str
    location: str
    salary_range: str | None
    job_type: str  # "Full-time", "Part-time", etc.
    posted_date: str
    requirements: list[str]


client = NotteClient()
with client.Session() as session:
    agent = client.Agent(session=session)
    result = agent.run(
        task="Extract job posting information",
        response_format=JobPosting,
```

### Social Media Data

Extract social media profiles:

{/* @sniptest testers/agents/structured-output/social_media.py */}

```python social_media.py theme={null}
    username: str
    display_name: str
    bio: str | None
    follower_count: int
    following_count: int
    post_count: int
    verified: bool


client = NotteClient()
with client.Session() as session:
    agent = client.Agent(session=session)
    result = agent.run(
        task="Extract social media profile information",
        response_format=SocialProfile,
```

## Field Validation

Use Pydantic validators for data quality:

{/* @sniptest testers/agents/structured-output/field_validation.py */}

```python field_validation.py theme={null}
class Product(BaseModel):
    name: str = Field(min_length=1)
    price: float = Field(gt=0)  # Must be positive
    rating: float = Field(ge=0, le=5)  # 0-5 range

    @field_validator("price")
    @classmethod
    def validate_price(cls, v: float) -> float:
        if v > 10000:
            raise ValueError("Price seems unreasonably high")
        return v


client = NotteClient()
with client.Session() as session:
    agent = client.Agent(session=session)
    result = agent.run(
        task="Extract product",
        response_format=Product,
```

## Best Practices

### 1. Be Specific in Task Description

Match your task to the response format:

{/* @sniptest testers/agents/structured-output/bp_specific_task.py */}

```python bp_specific_task.py theme={null}
result = agent.run(
    task="Extract the product name, price, and stock status",
    response_format=Product,
)

# Less clear - agent might not fill all fields
result = agent.run(
    task="Tell me about this product",
    response_format=Product,
)
```

### 2. Use Appropriate Types

Choose Python types that match the data:

{/* @sniptest testers/agents/structured-output/bp_appropriate_types.py */}

```python theme={null}
from datetime import date

from pydantic import BaseModel


class Event(BaseModel):
    title: str
    date: date  # Will be parsed as date
    price: float  # Not str
    attendee_count: int  # Not float
```

### 3. Make Optional Fields Explicit

Don't assume data will always be present:

{/* @sniptest testers/agents/structured-output/bp_optional_fields.py */}

```python theme={null}
from pydantic import BaseModel


class Product(BaseModel):
    name: str  # Always required
    price: float  # Always required
    discount: float | None = None  # Might not exist
    rating: float | None = None  # Might not exist
```

### 4. Use Field Descriptions

Help the agent understand what you want:

{/* @sniptest testers/agents/structured-output/bp_field_descriptions.py */}

```python theme={null}
from pydantic import BaseModel, Field


class Product(BaseModel):
    name: str = Field(description="Product title/name")
    price: float = Field(description="Current selling price in USD")
    original_price: float | None = Field(description="Original price before discount, if any")
```

### 5. Start Simple, Then Expand

Begin with basic models:

{/* @sniptest testers/agents/structured-output/bp_start_simple.py */}

```python theme={null}
from pydantic import BaseModel


# Start with minimal model
class Product(BaseModel):
    name: str
    price: float


# Add fields as needed
class DetailedProduct(BaseModel):
    name: str
    price: float
    description: str | None
    specs: dict[str, str] | None
```

## Error Handling

Handle validation errors:

{/* @sniptest testers/agents/structured-output/error_handling.py */}

```python error_handling.py theme={null}
try:
    result = agent.run(
        task="Extract product data",
        response_format=Product,
    )
    product = result.answer
except ValidationError as e:
    print(f"Agent returned invalid data: {e}")
```

## Limitations

### Not Suitable For

Structured output works best for data extraction, not for:

* Open-ended creative tasks
* Tasks requiring explanation or reasoning
* When you want natural language responses

{/* @sniptest testers/agents/structured-output/limitations_not_suitable.py */}

```python limitations_not_suitable.py theme={null}
with client.Session() as session:
    agent = client.Agent(session=session)
    # Do this instead
    result = agent.run(task="Explain how this product works")
    print(result.answer)  # Natural language explanation
```

### Complex Relationships

Very complex nested structures may be challenging:

{/* @sniptest testers/agents/structured-output/limitations_complex.py */}

```python limitations_complex.py theme={null}
class Product(BaseModel):
    name: str
    price: float


# Difficult for agents
class ComplexStructure(BaseModel):
    nested: dict[str, list[dict[str, Product]]]


# Better - flatten or simplify
class SimplifiedStructure(BaseModel):
    products: list[Product]
    categories: list[str]
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Configuration" icon="sliders" href="/features/agents/configuration.md">
    Configure agent parameters
  </Card>

  <Card title="Lifecycle" icon="rotate" href="/features/agents/lifecycle.md">
    Understand agent execution modes
  </Card>

  <Card title="Scraping" icon="database" href="/concepts/scraping.md">
    Alternative data extraction methods
  </Card>

  <Card title="Best Practices" icon="lightbulb" href="/guides/scraping.md">
    Data extraction best practices
  </Card>
</CardGroup>
