참고소스 수정본

This commit is contained in:
LASTA_DEV01\lasta
2026-05-12 19:40:31 +09:00
parent 0f34a451fc
commit 2e9204243d
8708 changed files with 3259488 additions and 869 deletions

View File

@@ -0,0 +1,135 @@
---
title: Your First LLM Extraction with Instructor
description: Step-by-step tutorial for your first structured data extraction from language models using Instructor and Pydantic.
---
# Your First LLM Extraction: Structured Outputs Tutorial
Learn how to extract structured data from LLMs using Instructor in this hands-on tutorial. We'll build a simple yet powerful example that demonstrates how to transform unstructured text into validated Python objects using GPT-4, Claude, or any supported LLM.
## Quick Start: Extract Structured Data from LLMs
This LLM tutorial shows you how to extract structured information from natural language. We'll parse a person's name and age - a perfect starting point for understanding Instructor's power:
```python
from pydantic import BaseModel
import instructor
# 1. Define your data model for LLM extraction
class Person(BaseModel):
name: str
age: int
# 2. Initialize Instructor with your LLM provider
client = instructor.from_provider("openai/gpt-5-nano")
# 3. Extract structured data from LLM
person = client.create(
response_model=Person, # Type-safe extraction
messages=[
{"role": "user", "content": "John Doe is 30 years old"}
]
)
# 4. Use validated, structured data from LLM
print(f"Name: {person.name}, Age: {person.age}")
# Output: Name: John Doe, Age: 30
```
## How Instructor LLM Extraction Works
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Define │ -> │ Instruct LLM │ -> │ Get Typed │
│ Structure │ │ to Extract │ │ Response │
└─────────────┘ └──────────────┘ └─────────────┘
```
Understanding the LLM structured output pipeline:
### Step 1: Define Your LLM Output Schema
```python
class Person(BaseModel):
name: str
age: int
```
Pydantic models define the structure for LLM outputs:
- `name`: String field for extracting names from LLM
- `age`: Integer field with automatic type validation
### Step 2: Configure Your LLM Client
```python
client = instructor.from_provider("openai/gpt-5-nano")
```
Instructor enhances your LLM client with structured output capabilities. Works with OpenAI, Anthropic, Google, and 15+ providers.
### Step 3: Execute LLM Extraction
```python
person = client.create(
response_model=Person,
messages=[
{"role": "user", "content": "John Doe is 30 years old"}
]
)
```
Key parameters for structured LLM outputs:
- `response_model`: Pydantic model for type-safe extraction
- `messages`: Input text for the LLM to process
Note: The model is already specified when creating the client with `from_provider()`, so you don't need to pass it again.
### Step 4: Work with Validated LLM Data
```python
print(f"Name: {person.name}, Age: {person.age}")
```
Get back a fully validated Python object from your LLM - no JSON parsing, no validation errors, just clean data ready to use.
## Enhance LLM Extraction with Field Descriptions
Improve LLM accuracy by providing clear field descriptions:
```python
from pydantic import BaseModel, Field
class Person(BaseModel):
name: str = Field(description="Person's full name")
age: int = Field(description="Person's age in years")
```
Field descriptions act as prompts, guiding the LLM to extract exactly what you need.
## Handle Optional Data in LLM Responses
Real-world LLM extractions often have missing data. Handle it gracefully:
```python
from typing import Optional
class Person(BaseModel):
name: str
age: Optional[int] = None # Now age is optional
```
## Continue Your LLM Tutorial Journey
You've successfully extracted structured data from an LLM! Next steps:
1. **[Advanced Response Models](response_models.md)** - Complex schemas for LLM outputs
2. **[Multi-Provider Setup](../../concepts/from_provider.md)** - Use GPT-4, Claude, Gemini interchangeably
3. **[Production Patterns](../patterns/simple_object.md)** - Real-world LLM extraction examples
## Common LLM Extraction Patterns
- **Entity Extraction**: Names, dates, locations from unstructured text
- **Sentiment Analysis**: Structured sentiment scores with reasoning
- **Data Classification**: Categorize text into predefined schemas
- **Information Parsing**: Convert documents into structured databases
Ready to build more complex LLM extractions? Continue to [Response Models](response_models.md) →

View File

@@ -0,0 +1,147 @@
---
title: Installing Instructor for LLM Structured Outputs
description: Complete installation guide for Instructor with support for OpenAI, Anthropic, Google, and 15+ LLM providers. Get started in minutes.
---
# Instructor Installation Guide: Setup for LLM Structured Outputs
Learn how to install Instructor, the leading Python library for extracting structured data from LLMs like GPT-4, Claude, and Gemini. This comprehensive installation tutorial covers all major LLM providers and gets you ready for production use.
## Quick Start: Install Instructor for LLM Development
Get started with structured LLM outputs in seconds. Install Instructor using pip:
```shell
pip install instructor
```
Instructor leverages Pydantic for type-safe LLM data extraction:
```shell
pip install pydantic
```
> **Pro Tip**: Use `uv` for faster installation: `uv pip install instructor`
## LLM Provider Installation Guide
Instructor supports 15+ LLM providers. Here's how to install and configure each:
### OpenAI (GPT-4, GPT-3.5)
OpenAI is the default LLM provider for Instructor. Perfect for GPT-4 and GPT-3.5-turbo structured outputs:
```shell
pip install instructor
```
Configure your OpenAI API key for LLM access:
```shell
export OPENAI_API_KEY=your_openai_key
```
### Anthropic Claude LLM Setup
Extract structured data from Claude 3 models (Opus, Sonnet, Haiku) with native tool support:
```shell
pip install "instructor[anthropic]"
```
Configure Claude API access:
```shell
export ANTHROPIC_API_KEY=your_anthropic_key
```
### Google Gemini LLM Integration
Use Gemini Pro and Flash models for structured outputs with function calling:
```shell
pip install "instructor[google-genai]"
```
Set up Gemini API access:
```shell
export GOOGLE_API_KEY=your_google_key
```
### Cohere
To use with Cohere's models:
```shell
pip install "instructor[cohere]"
```
Set up your Cohere API key:
```shell
export COHERE_API_KEY=your_cohere_key
```
### Mistral
To use with Mistral AI's models:
```shell
pip install "instructor[mistralai]"
```
Set up your Mistral API key:
```shell
export MISTRAL_API_KEY=your_mistral_key
```
### LiteLLM (Multiple Providers)
To use LiteLLM for accessing multiple providers:
```shell
pip install "instructor[litellm]"
```
Set up API keys for the providers you want to use.
## Verify Your Instructor LLM Setup
Test your Instructor installation with this simple LLM structured output example:
```python
import instructor
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
client = instructor.from_provider("openai/gpt-5-nano")
person = client.create(
model="gpt-3.5-turbo",
response_model=Person,
messages=[
{"role": "user", "content": "John Doe is 30 years old"}
]
)
print(f"Name: {person.name}, Age: {person.age}")
```
## Next Steps in Your LLM Tutorial Journey
With Instructor installed, you're ready to build powerful LLM applications:
1. **[Create Your First LLM Extraction](first_extraction.md)** - Build structured outputs with any LLM
2. **[Master Response Models](response_models.md)** - Learn Pydantic models for LLM data validation
3. **[Configure LLM Clients](../../concepts/from_provider.md)** - Set up OpenAI, Anthropic, Google, and more
## Common Installation Issues
- **Import Errors**: Ensure you've installed the provider-specific extras (e.g., `instructor[anthropic]`)
- **API Key Issues**: Verify your environment variables are set correctly
- **Version Conflicts**: Use `pip install --upgrade instructor` to get the latest version
Ready to extract structured data from LLMs? Continue to [Your First Extraction](first_extraction.md) →

View File

@@ -0,0 +1,202 @@
---
title: Understanding Response Models in Instructor
description: Learn how to create response models with Pydantic to define structure, validation rules, and extract complex data from LLMs.
---
# Understanding Response Models
Response models are at the core of Instructor's functionality. They define the structure of the data you want to extract and provide validation rules. This guide explains how to create different types of response models for various use cases.
## Basic Models
Let's start with a simple model similar to what we've seen before:
```python
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
```
This defines a model with two required fields: `name` (a string) and `age` (an integer).
## Adding Field Metadata
You can add metadata to fields using the `Field` class:
```python
from pydantic import BaseModel, Field
class WeatherForecast(BaseModel):
"""Weather forecast for a specific location"""
temperature: float = Field(
description="Current temperature in Celsius"
)
condition: str = Field(
description="Weather condition (sunny, cloudy, rainy, etc.)"
)
humidity: int = Field(
description="Humidity percentage from 0-100"
)
```
Field descriptions help the LLM understand what information to extract for each field.
## Field Validation
You can add validation rules to ensure the extracted data meets your requirements:
```python
from pydantic import BaseModel, Field
class Product(BaseModel):
name: str = Field(min_length=3)
price: float = Field(gt=0) # greater than 0
quantity: int = Field(ge=0) # greater than or equal to 0
description: str = Field(max_length=500)
```
Common validation parameters include:
- `min_length`/`max_length`: For strings
- `ge`/`gt`/`le`/`lt`: For numbers (greater/less than or equal/than)
- `pattern`: For regex pattern matching
For more on validation, see the [Field Validation](../patterns/field_validation.md) and [Validation Basics](../validation/basics.md) guides.
## Nested Models
You can create complex data structures with nested models:
```python
from pydantic import BaseModel, Field
from typing import List, Optional
class Address(BaseModel):
street: str
city: str
state: Optional[str] = None
country: str
class User(BaseModel):
name: str
age: int
addresses: List[Address]
```
This allows you to extract hierarchical data structures. For more examples, check out the [Simple Nested Structure](../patterns/nested_structure.md) guide.
## Using Enums
Enums help when you want to restrict a field to a set of specific values:
```python
from enum import Enum
from pydantic import BaseModel
class UserType(str, Enum):
ADMIN = "admin"
REGULAR = "regular"
GUEST = "guest"
class User(BaseModel):
name: str
user_type: UserType
```
## Optional Fields
For fields that might not be present in the source text:
```python
from typing import Optional
from pydantic import BaseModel
class Contact(BaseModel):
name: str
email: str
phone: Optional[str] = None
address: Optional[str] = None
```
For more about working with optional fields, see the [Optional Fields](../patterns/optional_fields.md) guide.
## Lists and Arrays
To extract multiple items of the same type:
```python
from typing import List
from pydantic import BaseModel
class BlogPost(BaseModel):
title: str
content: str
tags: List[str]
```
For more about working with lists, see the [List Extraction](../patterns/list_extraction.md) guide.
## Using Your Models with Instructor
Once you've defined your model, you can use it for extraction:
```python
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
forecast = client.create(
model="gpt-3.5-turbo",
response_model=WeatherForecast,
messages=[
{"role": "user", "content": "What's the weather in New York today?"}
]
)
print(forecast.model_dump_json(indent=2))
```
## Model Documentation
You can add documentation to your models using docstrings and field descriptions:
```python
from pydantic import BaseModel, Field
class Investment(BaseModel):
"""Represents an investment opportunity with risk and return details."""
name: str = Field(description="Name of the investment")
amount: float = Field(description="Investment amount in USD")
expected_return: float = Field(description="Expected annual return percentage")
risk_level: str = Field(description="Risk level (low, medium, high)")
```
This documentation helps both the LLM understand what to extract and makes your code more maintainable.
## Advanced Validation with Validators
For more complex validation rules, you can use validator methods:
```python
from pydantic import BaseModel, Field, field_validator
from datetime import date
class Reservation(BaseModel):
check_in: date
check_out: date
guests: int = Field(ge=1)
@field_validator("check_out")
def check_dates(cls, v, values):
if "check_in" in values.data and v <= values.data["check_in"]:
raise ValueError("check_out must be after check_in")
return v
```
For more advanced validation techniques, check out the [Custom Validators](../validation/custom_validators.md) guide.
## Next Steps
In the next section, learn about [from_provider](../../concepts/from_provider.md) to configure different LLM providers and understand the various modes of operation.

View File

@@ -0,0 +1,148 @@
---
title: Getting Started with Structured LLM Outputs
description: Learn the basics of extracting structured data from language models using Instructor. Understand the difference between unstructured and structured outputs.
---
# Getting Started with Structured Outputs
Large language models (LLMs) are powerful tools for generating text, but extracting structured data from their outputs can be challenging. Structured outputs solve this problem by having LLMs return data in consistent, machine-readable formats.
## The Problem with Unstructured Outputs
Let's look at what happens when we ask an LLM to extract information without any structure:
```python
from openai import OpenAI
client = OpenAI()
response = client.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "Extract customer: John Doe, age 35, email: john@example.com",
}
],
)
print(response.choices[0].message.content)
```
The output might look like:
```
Customer Name: John Doe
Age: 35
Email: john@example.com
```
Or it could be:
```
I found the following customer information:
- Name: John Doe
- Age: 35
- Email address: john@example.com
```
This inconsistency makes it difficult to reliably parse the information in downstream applications.
## The Solution: Structured Outputs with Instructor
Instructor solves this problem by using Pydantic models to define the expected structure of the output:
```python
import instructor
from pydantic import BaseModel, Field, EmailStr
class Customer(BaseModel):
name: str = Field(description="Customer's full name")
age: int = Field(description="Customer's age in years", ge=0, le=120)
email: EmailStr = Field(description="Customer's email address")
client = instructor.from_provider("openai/gpt-5-nano")
customer = client.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "Extract customer: John Doe, age 35, email: john@example.com",
}
],
response_model=Customer, # This is the key part
)
print(customer) # Customer(name='John Doe', age=35, email='john@example.com')
print(f"Name: {customer.name}, Age: {customer.age}, Email: {customer.email}")
```
The benefits of this approach include:
1. **Consistency**: Always get data in the same format
2. **Validation**: Age must be between 0 and 120, email must be valid
3. **Type Safety**: `age` is always an integer, not a string
4. **Documentation**: Model fields are self-documenting with descriptions
## Complex Example: Nested Structures
Instructor shines with complex data structures:
```python
from typing import List, Optional
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Address(BaseModel):
street: str
city: str
state: str
zip_code: str
class Contact(BaseModel):
email: Optional[str] = None
phone: Optional[str] = None
class Person(BaseModel):
name: str
age: int
occupation: str
address: Address
contact: Contact
skills: List[str] = Field(description="List of professional skills")
person = client.create(
model="gpt-4",
messages=[
{
"role": "user",
"content": """
Extract detailed information for this person:
John Smith is a 42-year-old software engineer living at 123 Main St, San Francisco, CA 94105.
His email is john.smith@example.com and phone is 555-123-4567.
John is skilled in Python, JavaScript, and cloud architecture.
""",
}
],
response_model=Person,
)
print(f"Name: {person.name}")
print(f"Location: {person.address.city}, {person.address.state}")
print(f"Skills: {', '.join(person.skills)}")
```
## Installation
To get started with Instructor, install it via pip:
```shell
pip install instructor pydantic
```
You'll also need to set up your API keys for the LLM provider you're using.
## Next Steps
In the next sections, you'll learn how to:
1. Create your [first extraction](first_extraction.md)
2. Understand the different [response models](response_models.md) you can create
3. Set up [clients for various LLM providers](../../concepts/from_provider.md)

View File

@@ -0,0 +1,52 @@
# Instructor LLM Tutorial: Complete Guide to Structured Outputs
Learn how to use Instructor for LLM structured outputs with this comprehensive tutorial. Instructor is the leading Python library for extracting structured, validated data from large language models (LLMs) like GPT-4, Claude, and Gemini.
## What You'll Learn in This LLM Tutorial
This Instructor tutorial covers everything from basic LLM integration to advanced structured output patterns. Whether you're building AI applications, automating data extraction, or creating LLM-powered APIs, this guide provides practical, production-ready examples.
## Getting Started with Instructor LLM Tutorial
Start your journey with these beginner-friendly tutorials for LLM integration:
* [**Installation Guide**](getting_started/installation.md) - Install Instructor for Python LLM development
* [**Your First LLM Extraction**](getting_started/first_extraction.md) - Build your first structured output with OpenAI, Anthropic, or Google LLMs
* [**Response Models Tutorial**](getting_started/response_models.md) - Master Pydantic models for LLM outputs
* [**LLM Client Setup**](../concepts/from_provider.md) - Configure Instructor for OpenAI, Anthropic, Gemini, and 15+ LLM providers
## LLM Data Extraction Patterns
Learn essential patterns for extracting structured data from language models:
* [**Simple Object Extraction**](patterns/simple_object.md) - Extract structured objects from LLM responses
* [**List Extraction Tutorial**](patterns/list_extraction.md) - Generate lists and arrays with LLMs
* [**Nested Data Structures**](patterns/nested_structure.md) - Handle complex, hierarchical LLM outputs
* [**Optional Fields**](patterns/optional_fields.md) - Manage missing data in LLM responses
* [**Field Validation**](patterns/field_validation.md) - Validate LLM outputs with Pydantic
* [**Prompt Engineering Templates**](patterns/prompt_templates.md) - Optimize prompts for better LLM extraction
## LLM Output Validation Tutorial
Ensure reliability with these validation tutorials:
* [**Validation Fundamentals**](validation/basics.md) - Core concepts for validating LLM outputs
* [**Field-Level Validation**](validation/field_level_validation.md) - Granular validation for LLM data
* [**Custom Validators**](validation/custom_validators.md) - Build domain-specific LLM validators
* [**Retry Strategies**](validation/retry_mechanisms.md) - Handle LLM failures gracefully
## Streaming LLM Responses
Real-time LLM output processing tutorials:
* [**Streaming Basics**](streaming/basics.md) - Stream LLM responses for better UX
* [**Streaming Lists**](streaming/lists.md) - Process LLM arrays in real-time
## Why This Instructor LLM Tutorial?
- **Production-Ready Examples**: Real-world LLM integration patterns used by thousands of developers
- **Multi-Provider Support**: Works with OpenAI, Anthropic, Google, Cohere, and more
- **Type-Safe Outputs**: Leverage Python's type system for reliable LLM applications
- **Progressive Learning Path**: From basic LLM calls to advanced extraction techniques
Ready to master structured outputs with LLMs? Start with our [installation guide](getting_started/installation.md) and build your first LLM-powered application today!

View File

@@ -0,0 +1,385 @@
# Field Validation
This guide covers how to add validation to fields when extracting structured data with Instructor. Field validation ensures that your extracted data meets specific criteria and constraints.
## Why Field Validation Matters
Field validation helps you:
1. Ensure data quality and consistency
2. Enforce business rules
3. Prevent errors in downstream processing
4. Provide clear feedback for invalid data
Instructor uses Pydantic's validation system, which is applied automatically during extraction.
## Basic Field Constraints
You can add basic constraints to fields using Pydantic's `Field` function:
```python
from pydantic import BaseModel, Field
import instructor
from openai import OpenAI
client = instructor.from_provider("openai/gpt-5-nano")
class User(BaseModel):
name: str = Field(..., min_length=2, max_length=50)
age: int = Field(..., ge=0, le=120) # greater than or equal to 0, less than or equal to 120
email: str = Field(..., pattern=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
# Extract with validation
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "I'm John Smith, 35 years old, with email john@example.com"}
],
response_model=User
)
```
Common Field constraints include:
| Constraint | Description | Example |
|------------|-------------|---------|
| `min_length` | Minimum string length | `min_length=2` |
| `max_length` | Maximum string length | `max_length=50` |
| `pattern` | Regex pattern to match | `pattern=r'^[0-9]+$'` |
| `gt` | Greater than | `gt=0` (for numbers) |
| `ge` | Greater than or equal | `ge=18` |
| `lt` | Less than | `lt=100` |
| `le` | Less than or equal | `le=120` |
| `min_items` | Minimum list items | `min_items=1` |
| `max_items` | Maximum list items | `max_items=10` |
For more information on field definitions, see the [Fields](../../concepts/fields.md) concepts page.
## Validation with Field Validators
For more complex validation logic, use Pydantic's `field_validator` decorator:
```python
from pydantic import BaseModel, Field, field_validator
import instructor
from openai import OpenAI
import re
client = instructor.from_provider("openai/gpt-5-nano")
class Product(BaseModel):
name: str
sku: str
price: float
@field_validator('name')
@classmethod
def validate_name(cls, v):
if len(v.strip()) < 3:
raise ValueError("Product name must be at least 3 characters")
return v.strip()
@field_validator('sku')
@classmethod
def validate_sku(cls, v):
if not re.match(r'^[A-Z]{3}-\d{4}$', v):
raise ValueError("SKU must be in format XXX-0000")
return v
@field_validator('price')
@classmethod
def validate_price(cls, v):
if v <= 0:
raise ValueError("Price must be greater than zero")
if v > 10000:
raise ValueError("Price exceeds maximum allowed value")
return v
# Extract validated data
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "Product: Wireless Headphones, SKU: ABC-1234, Price: $79.99"}
],
response_model=Product
)
```
Field validators can:
- Perform complex validation logic
- Clean and normalize data
- Transform values
- Check values against external data sources
For more on custom validators, see the [Custom Validators](../validation/custom_validators.md) guide.
## Model-level Validation
Sometimes validation needs to check relationships between fields. For this, use `model_validator`:
```python
from pydantic import BaseModel, Field, model_validator
import instructor
from openai import OpenAI
from datetime import date
client = instructor.from_provider("openai/gpt-5-nano")
class DateRange(BaseModel):
start_date: date
end_date: date
@model_validator(mode='after')
def validate_date_range(self):
if self.end_date < self.start_date:
raise ValueError("End date must be after start date")
return self
```
## Validation in Nested Structures
You can apply validation at any level in nested structures:
```python
from pydantic import BaseModel, Field, field_validator
import instructor
from openai import OpenAI
from typing import List
client = instructor.from_provider("openai/gpt-5-nano")
class Address(BaseModel):
street: str
city: str
state: str
zip_code: str
@field_validator('state')
@classmethod
def validate_state(cls, v):
valid_states = {"CA", "NY", "TX", "FL"} # Example: just a few states
if v not in valid_states:
raise ValueError(f"State must be one of: {', '.join(valid_states)}")
return v
@field_validator('zip_code')
@classmethod
def validate_zip(cls, v):
if not v.isdigit() or len(v) != 5:
raise ValueError("ZIP code must be 5 digits")
return v
class Person(BaseModel):
name: str
addresses: List[Address] # Nested structure with validation
```
For more on nested structures, see the [Nested Structure](nested_structure.md) guide.
## List Item Validation
You can validate items in a list:
```python
from typing import List
from pydantic import BaseModel, Field, field_validator
import instructor
from openai import OpenAI
client = instructor.from_provider("openai/gpt-5-nano")
class TagList(BaseModel):
tags: List[str] = Field(..., min_items=1, max_items=5)
@field_validator('tags')
@classmethod
def validate_tags(cls, tags):
# Convert all tags to lowercase
tags = [tag.lower() for tag in tags]
# Check for minimum length of each tag
for tag in tags:
if len(tag) < 2:
raise ValueError("Each tag must be at least 2 characters")
# Check for duplicates
if len(tags) != len(set(tags)):
raise ValueError("Tags must be unique")
return tags
```
For more on lists, see the [List Extraction](list_extraction.md) guide.
## Using Enumerations for Validation
Enums provide a way to validate fields against a predefined set of values:
```python
from enum import Enum
from pydantic import BaseModel
import instructor
from openai import OpenAI
client = instructor.from_provider("openai/gpt-5-nano")
class Status(str, Enum):
PENDING = "pending"
APPROVED = "approved"
REJECTED = "rejected"
class Priority(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
class Task(BaseModel):
title: str
description: str
status: Status # Must be one of the enum values
priority: Priority # Must be one of the enum values
# Extract with enum validation
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "Task: Update website, Description: Refresh content on homepage, Status: pending, Priority: high"}
],
response_model=Task
)
```
For more information on enums, see the [Enums](../../concepts/enums.md) concepts page.
## Custom Error Messages
You can customize validation error messages for better feedback:
```python
from pydantic import BaseModel, Field
import instructor
from openai import OpenAI
client = instructor.from_provider("openai/gpt-5-nano")
class CreditCard(BaseModel):
number: str = Field(
...,
pattern=r'^\d{16}$',
json_schema_extra={"error_msg": "Credit card number must be exactly 16 digits"}
)
expiry_month: int = Field(
...,
ge=1,
le=12,
json_schema_extra={"error_msg": "Expiry month must be between 1 and 12"}
)
expiry_year: int = Field(
...,
ge=2023,
le=2030,
json_schema_extra={"error_msg": "Expiry year must be between 2023 and 2030"}
)
cvv: str = Field(
...,
pattern=r'^\d{3,4}$',
json_schema_extra={"error_msg": "CVV must be 3 or 4 digits"}
)
```
## Handling Validation Failures
When validation fails, Instructor will:
1. Capture the validation error
2. Add the error message to the context
3. Retry the request with this feedback (if retries are enabled)
To control retry behavior:
```python
client = instructor.from_provider(
"openai/gpt-4o",
max_retries=2, # Number of retries after the initial attempt
throw_error=True # Whether to raise an exception on validation failure
)
```
For more on retries, see the [Retry Mechanisms](../validation/retry_mechanisms.md) guide.
## Real-world Example: Form Data Validation
Here's a more complete example validating form inputs:
```python
from pydantic import BaseModel, Field, field_validator, model_validator
import instructor
import re
from datetime import date, datetime
from typing import Optional
client = instructor.from_provider("openai/gpt-5-nano")
class RegistrationForm(BaseModel):
username: str = Field(..., min_length=3, max_length=20)
email: str
password: str
confirm_password: str
birth_date: date
@field_validator('username')
@classmethod
def validate_username(cls, v):
if not re.match(r'^[a-zA-Z0-9_]+$', v):
raise ValueError("Username can only contain letters, numbers, and underscores")
return v
@field_validator('email')
@classmethod
def validate_email(cls, v):
if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', v):
raise ValueError("Invalid email format")
return v
@field_validator('password')
@classmethod
def validate_password(cls, v):
if len(v) < 8:
raise ValueError("Password must be at least 8 characters")
if not re.search(r'[A-Z]', v):
raise ValueError("Password must contain at least one uppercase letter")
if not re.search(r'[a-z]', v):
raise ValueError("Password must contain at least one lowercase letter")
if not re.search(r'[0-9]', v):
raise ValueError("Password must contain at least one number")
return v
@field_validator('birth_date')
@classmethod
def validate_age(cls, v):
today = date.today()
age = today.year - v.year - ((today.month, today.day) < (v.month, v.day))
if age < 18:
raise ValueError("You must be at least 18 years old to register")
return v
@model_validator(mode='after')
def passwords_match(self):
if self.password != self.confirm_password:
raise ValueError("Passwords do not match")
return self
```
## Related Resources
- [Validation Basics](../validation/basics.md) - Core validation concepts
- [Custom Validators](../validation/custom_validators.md) - Creating custom validation logic
- [Field-level Validation](../validation/field_level_validation.md) - Advanced field validation
- [Retry Mechanisms](../validation/retry_mechanisms.md) - Handling validation failures
- [Fields](../../concepts/fields.md) - Understanding field definitions
- [Enums](../../concepts/enums.md) - Using enumeration types
## Next Steps
- Learn about [Optional Fields](optional_fields.md) for handling missing data
- Explore [Custom Validators](../validation/custom_validators.md) for complex validation
- Check out [Nested Structure](nested_structure.md) for complex data relationships

View File

@@ -0,0 +1,291 @@
---
title: List Extraction from LLMs Tutorial
description: Master extracting multiple structured objects from language models using Instructor with type-safe list validation.
---
# List Extraction Tutorial: Extract Multiple Objects from LLMs
Master the art of extracting lists and arrays from LLMs in this comprehensive tutorial. Learn how to use Instructor to extract multiple structured objects from language models like GPT-4, Claude, and Gemini with type-safe validation.
## Basic List Extraction
To extract a list of items, you define a model for a single item and then use Python's typing system to specify you want a list of that type:
```python
from typing import List
from pydantic import BaseModel, Field
import instructor
# Initialize the client
client = instructor.from_provider("openai/gpt-5-nano")
# Define a single item model
class Person(BaseModel):
name: str = Field(..., description="The person's full name")
age: int = Field(..., description="The person's age in years")
# Define a wrapper model for the list
class PeopleList(BaseModel):
people: List[Person] = Field(..., description="List of people mentioned in the text")
# Extract the list
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": """
Here's information about some people:
- John Smith is 35 years old
- Mary Johnson is 28 years old
- Robert Davis is 42 years old
"""}
],
response_model=PeopleList
)
# Access the extracted data
for i, person in enumerate(response.people):
print(f"Person {i+1}: {person.name}, {person.age} years old")
```
This example shows how to:
1. Define a model for a single item (`Person`)
2. Create a wrapper model that contains a list of items (`PeopleList`)
3. Access each item in the list through the response
## Direct List Extraction
You can also extract a list directly without a wrapper model:
```python
from typing import List
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Book(BaseModel):
title: str
author: str
publication_year: int
# Extract a list directly
books = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": """
Classic novels:
1. To Kill a Mockingbird by Harper Lee (1960)
2. 1984 by George Orwell (1949)
3. The Great Gatsby by F. Scott Fitzgerald (1925)
"""}
],
response_model=List[Book] # Direct list extraction
)
# Access the extracted data
for book in books:
print(f"{book.title} by {book.author} ({book.publication_year})")
```
## Nested Lists
You can extract nested lists by combining list types:
```python
from typing import List
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Author(BaseModel):
name: str
nationality: str
class Book(BaseModel):
title: str
authors: List[Author] # Nested list of authors
publication_year: int
# Extract data with nested lists
books = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": """
Book 1: "Good Omens" (1990)
Authors: Terry Pratchett (British), Neil Gaiman (British)
Book 2: "The Talisman" (1984)
Authors: Stephen King (American), Peter Straub (American)
"""}
],
response_model=List[Book]
)
# Access the nested data
for book in books:
author_names = ", ".join([author.name for author in book.authors])
print(f"{book.title} ({book.publication_year}) by {author_names}")
```
## Using Streaming with Lists
You can stream list extraction results using Instructor's streaming capabilities:
```python
from typing import List
import instructor
from pydantic import BaseModel, Field
client = instructor.from_provider("openai/gpt-5-nano")
class Task(BaseModel):
description: str
priority: str
deadline: str
# Stream a list of tasks
for task in client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "Generate a list of 5 sample tasks for a project manager"}
],
response_model=List[Task],
stream=True
):
print(f"Received task: {task.description} (Priority: {task.priority}, Deadline: {task.deadline})")
```
For more information on streaming, see the [Streaming Basics](../streaming/basics.md) and [Streaming Lists](../streaming/lists.md) guides.
## List Validation
You can add validation for both individual items and the entire list:
```python
from typing import List
from pydantic import BaseModel, Field, field_validator, model_validator
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Product(BaseModel):
name: str
price: float
@field_validator('price')
@classmethod
def validate_price(cls, v):
if v <= 0:
raise ValueError("Price must be greater than zero")
return v
class ProductList(BaseModel):
products: List[Product] = Field(..., min_items=1)
@model_validator(mode='after')
def validate_unique_names(self):
names = [p.name for p in self.products]
if len(names) != len(set(names)):
raise ValueError("All product names must be unique")
return self
# Extract list with validation
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "List of products: Headphones ($50), Speakers ($80), Earbuds ($30)"}
],
response_model=ProductList
)
```
For more on validation, see [Field Validation](./field_validation.md) and [Validation Basics](../validation/basics.md).
## List Constraints
You can add constraints to lists using Pydantic's Field:
```python
from typing import List
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Ingredient(BaseModel):
name: str
amount: str
class Recipe(BaseModel):
title: str
ingredients: List[Ingredient] = Field(
...,
min_items=2, # Minimum 2 ingredients
max_items=10, # Maximum 10 ingredients
description="List of ingredients needed for the recipe"
)
steps: List[str] = Field(
...,
min_items=1,
description="Step-by-step instructions to prepare the recipe"
)
```
## Real-world Example: Task Extraction
Here's a more complete example for extracting a list of tasks from a meeting transcript:
```python
from typing import List, Optional
from pydantic import BaseModel, Field
import instructor
from datetime import date
client = instructor.from_provider("openai/gpt-5-nano")
class Assignee(BaseModel):
name: str
email: Optional[str] = None
class ActionItem(BaseModel):
description: str = Field(..., description="The task that needs to be completed")
assignee: Assignee = Field(..., description="The person responsible for the task")
due_date: Optional[date] = Field(None, description="The deadline for the task")
priority: str = Field(..., description="Priority level: Low, Medium, or High")
# Extract action items from meeting notes
action_items = client.create(
model="gpt-4",
messages=[
{"role": "user", "content": """
Meeting Notes - Project Kickoff
Date: 2023-05-15
Attendees: John (john@example.com), Sarah (sarah@example.com), Mike
Discussion points:
1. John will prepare the project timeline by next Friday. This is high priority.
2. Sarah needs to contact the client for requirements clarification by Wednesday. Medium priority.
3. Mike is responsible for setting up the development environment. Due by tomorrow, high priority.
"""}
],
response_model=List[ActionItem]
)
# Process the extracted action items
for item in action_items:
due_str = item.due_date.isoformat() if item.due_date else "Not specified"
print(f"Task: {item.description}")
print(f"Assignee: {item.assignee.name} ({item.assignee.email or 'No email'})")
print(f"Due: {due_str}, Priority: {item.priority}")
print("---")
```
For a more detailed example, see the [Action Items Extraction](../../examples/action_items.md) example.
## Related Resources
- [Simple Object Extraction](./simple_object.md) - Extracting single objects
- [Nested Structure](./nested_structure.md) - Working with complex nested data
- [Streaming Lists](../streaming/lists.md) - Streaming list results
- [Lists and Arrays](../../concepts/lists.md) - Concepts related to list extraction
## Next Steps
- Learn about [Nested Structure](./nested_structure.md) for complex data
- Explore [Streaming Lists](../streaming/lists.md) for handling large lists
- Check out [Field Validation](./field_validation.md) for validation techniques

View File

@@ -0,0 +1,357 @@
---
title: Nested Structure Extraction with Instructor
description: Learn how to extract complex nested data structures from LLMs using hierarchical Pydantic models.
---
# Simple Nested Structure
This guide explains how to extract nested structured data using Instructor. Nested structures allow you to represent complex, hierarchical data relationships.
## Understanding Nested Structures
Nested structures are objects that contain other objects as fields. They're useful for representing:
1. Parent-child relationships
2. Complex entities with sub-components
3. Hierarchical data
4. Related data that belongs together
## Basic Nested Structure Example
Here's a simple example of extracting a nested structure:
```python
from pydantic import BaseModel, Field
import instructor
from typing import List, Optional
# Initialize the client
client = instructor.from_provider("openai/gpt-5-nano")
# Define nested models
class Address(BaseModel):
street: str
city: str
state: str
zip_code: str
class Person(BaseModel):
name: str
age: int
address: Address # Nested structure
# Extract the nested data
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": """
John Smith is 35 years old.
He lives at 123 Main Street, Boston, MA 02108.
"""}
],
response_model=Person
)
# Access the nested data
print(f"Name: {response.name}")
print(f"Age: {response.age}")
print(f"Address: {response.address.street}, {response.address.city}, "
f"{response.address.state} {response.address.zip_code}")
```
## Multiple Levels of Nesting
You can use multiple levels of nesting for more complex structures:
```python
from pydantic import BaseModel, Field
import instructor
from typing import List, Optional
client = instructor.from_provider("openai/gpt-5-nano")
class EmployeeDetails(BaseModel):
department: str
position: str
start_date: str
class ContactInfo(BaseModel):
phone: str
email: str
class Address(BaseModel):
street: str
city: str
state: str
zip_code: str
class Person(BaseModel):
name: str
age: int
contact: ContactInfo # First level nesting
address: Address # First level nesting
employment: Optional[EmployeeDetails] = None # Optional nested structure
# Extract deeply nested data
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": """
Employee Profile:
Name: Jane Doe
Age: 32
Phone: (555) 123-4567
Email: jane.doe@example.com
Address: 456 Oak Avenue, Chicago, IL 60601
Department: Engineering
Position: Senior Developer
Start Date: 2021-03-15
"""}
],
response_model=Person
)
```
## Nested Lists
You can combine nesting with lists to represent complex collections:
```python
from pydantic import BaseModel, Field
import instructor
from typing import List
client = instructor.from_provider("openai/gpt-5-nano")
class Ingredient(BaseModel):
name: str
amount: str
unit: str
class Recipe(BaseModel):
title: str
description: str
ingredients: List[Ingredient] # Nested list of ingredients
steps: List[str] # List of strings
# Extract nested list data
response = client.create(
model="gpt-4",
messages=[
{"role": "user", "content": """
Recipe: Chocolate Chip Cookies
Description: Classic homemade chocolate chip cookies that are soft in the middle and crispy on the edges.
Ingredients:
- 2 1/4 cups all-purpose flour
- 1 teaspoon baking soda
- 1 teaspoon salt
- 1 cup butter
- 3/4 cup white sugar
- 3/4 cup brown sugar
- 2 eggs
- 2 teaspoons vanilla extract
- 2 cups chocolate chips
Instructions:
1. Preheat oven to 375°F (190°C)
2. Mix flour, baking soda, and salt
3. Cream butter and sugars, then add eggs and vanilla
4. Gradually add dry ingredients
5. Stir in chocolate chips
6. Drop by rounded tablespoons onto ungreased baking sheets
7. Bake for 9 to 11 minutes or until golden brown
8. Cool on wire racks
"""}
],
response_model=Recipe
)
```
For more information on working with lists, see the [List Extraction](list_extraction.md) guide.
## Handling Optional Nested Fields
Sometimes parts of a nested structure might be missing. Use Optional to handle this:
```python
from pydantic import BaseModel, Field
import instructor
from typing import Optional
client = instructor.from_provider("openai/gpt-5-nano")
class SocialMedia(BaseModel):
twitter: Optional[str] = None
linkedin: Optional[str] = None
instagram: Optional[str] = None
class ContactInfo(BaseModel):
email: str
phone: Optional[str] = None
social: Optional[SocialMedia] = None # Optional nested structure
class Person(BaseModel):
name: str
contact: ContactInfo
```
For more information on optional fields, see the [Optional Fields](optional_fields.md) guide.
## Nested Structure Validation
You can add validation to nested structures at any level:
```python
from pydantic import BaseModel, Field, field_validator, model_validator
import instructor
import re
client = instructor.from_provider("openai/gpt-5-nano")
class EmailContact(BaseModel):
email: str
@field_validator('email')
@classmethod
def validate_email(cls, v):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(pattern, v):
raise ValueError("Invalid email format")
return v
class Customer(BaseModel):
name: str
contact: EmailContact # Nested structure with its own validation
@model_validator(mode='after')
def validate_name_email_match(self):
name_part = self.name.lower().split()[0]
if name_part not in self.contact.email.lower():
print(f"Warning: Email {self.contact.email} may not match name {self.name}")
return self
```
For more on validation, see [Field Validation](field_validation.md) and [Validation Basics](../validation/basics.md).
## Working with Recursive Structures
For more complex hierarchical data, you can use recursive structures:
```python
from typing import List, Optional
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Comment(BaseModel):
text: str
author: str
replies: List["Comment"] = [] # Recursive structure
# Update the Comment class reference for Pydantic
Comment.model_rebuild()
class Post(BaseModel):
title: str
content: str
author: str
comments: List[Comment] = []
# Extract recursive nested data
response = client.create(
model="gpt-4",
messages=[
{"role": "user", "content": """
Blog Post: "Python Tips and Tricks"
Author: John Smith
Content: Here are some helpful Python tips for beginners...
Comments:
1. Alice: "Great post! Very helpful."
- Bob: "I agree, I learned a lot."
- Alice: "Bob, did you try the last example?"
- Charlie: "Thanks for sharing this."
2. David: "Could you explain the second tip more?"
- John: "Sure, I'll add more details."
"""}
],
response_model=Post
)
```
For more advanced recursive structures, see the [Recursive Structures](../../examples/recursive.md) guide.
## Real-world Example: Organization Structure
Here's a more complete example extracting an organization structure:
```python
from typing import List, Optional
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Employee(BaseModel):
name: str
title: str
class Department(BaseModel):
name: str
head: Employee
employees: List[Employee]
sub_departments: List["Department"] = []
# Update for Pydantic's recursive model support
Department.model_rebuild()
class Organization(BaseModel):
name: str
ceo: Employee
departments: List[Department]
# Extract organization structure
response = client.create(
model="gpt-4",
messages=[
{"role": "user", "content": """
Acme Corporation
CEO: Jane Smith, Chief Executive Officer
Departments:
1. Engineering
Head: Bob Johnson, CTO
Employees:
- Sarah Lee, Senior Engineer
- Tom Brown, Software Developer
Sub-departments:
- Frontend Team
Head: Lisa Wang, Frontend Lead
Employees:
- Mike Chen, UI Developer
- Ana Garcia, UX Designer
- Backend Team
Head: David Kim, Backend Lead
Employees:
- James Wright, Database Engineer
- Rachel Patel, API Developer
2. Marketing
Head: Michael Davis, CMO
Employees:
- Jennifer Miller, Marketing Specialist
- Robert Chen, Content Creator
"""}
],
response_model=Organization
)
```
## Related Resources
- [Simple Object Extraction](./simple_object.md) - Extracting basic objects
- [List Extraction](./list_extraction.md) - Working with lists of objects
- [Optional Fields](./optional_fields.md) - Handling optional data
- [Recursive Structures](../../examples/recursive.md) - Building more complex hierarchies
- [Field Validation](./field_validation.md) - Adding validation to your fields

View File

@@ -0,0 +1,191 @@
---
title: Working with Optional Fields in Instructor
description: Learn how to use optional fields in Pydantic models to handle missing or uncertain information from LLM outputs.
---
# Optional Fields
This guide explains how to work with optional fields in your data models. Optional fields allow the model to skip fields when information is unavailable or uncertain.
## Why Use Optional Fields?
Optional fields are useful when:
1. Some information is missing from the input text
2. Certain fields are only relevant in specific contexts
3. The LLM can't confidently extract all fields
4. You want to allow partial success instead of complete failure
## Basic Optional Fields
To make a field optional, use Python's `Optional` type and provide a default value:
```python
from typing import Optional
from pydantic import BaseModel
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Person(BaseModel):
name: str # Required field
age: Optional[int] = None # Optional field with None default
occupation: Optional[str] = None # Optional field with None default
```
Here, `name` is required, while `age` and `occupation` are optional and will default to `None` if not found.
## Using Default Values
You can provide meaningful default values for optional fields:
```python
from typing import List
from pydantic import BaseModel
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Product(BaseModel):
name: str
price: float
currency: str = "USD" # Default value
in_stock: bool = True # Default value
tags: List[str] = [] # Default empty list
```
## Optional Fields with Validation
You can add the `Field` class for more control and validation:
```python
from typing import Optional
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class UserProfile(BaseModel):
username: str
email: str
bio: Optional[str] = Field(
None, # Default value
max_length=200, # Validation applies if present
description="User's biography, limited to 200 characters"
)
```
## Optional Nested Structures
Entire nested structures can be optional:
```python
from typing import Optional
from pydantic import BaseModel
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Address(BaseModel):
street: str
city: str
state: str
zip_code: str
class Contact(BaseModel):
email: str
phone: Optional[str] = None
address: Optional[Address] = None # Optional nested structure
class Person(BaseModel):
name: str
contact: Contact
```
When using nested optional structures, check if they exist before accessing:
```python
# Access nested data safely
if person.contact.address:
print(f"Address: {person.contact.address.city}")
else:
print("No address information available")
```
## Using `Maybe` for Uncertain Fields
Instructor provides a `Maybe` type for uncertain or ambiguous fields:
```python
from pydantic import BaseModel
import instructor
from instructor.types import Maybe
client = instructor.from_provider("openai/gpt-5-nano")
class PersonInfo(BaseModel):
name: str
age: Maybe[int] = None # Maybe type for uncertain fields
```
Check if a `Maybe` field contains uncertain information:
```python
if person.age and person.age.is_uncertain:
print(f"Uncertain age: approximately {person.age.value}")
elif person.age:
print(f"Age: {person.age.value}")
else:
print("Age: Unknown")
```
For more about the `Maybe` type, see the [Missing Concepts](../../concepts/maybe.md) page.
## Handling Optional Values
Always handle the possibility of `None` values in your code:
```python
# Check for None before using
if person.age is not None:
drinking_age = "Legal" if person.age >= 21 else "Underage"
else:
drinking_age = "Unknown"
# Use conditional expressions
price_display = f"${product.price}" if product.price is not None else "Price unavailable"
# Provide defaults with 'or'
display_name = user.nickname or user.username
```
## Validation with Optional Fields
Optional fields can still have validation when they're present:
```python
from typing import Optional
from pydantic import BaseModel, field_validator
import instructor
import re
client = instructor.from_provider("openai/gpt-5-nano")
class ContactInfo(BaseModel):
email: str
phone: Optional[str] = None
@field_validator('phone')
@classmethod
def validate_phone(cls, v):
if v is not None and not re.match(r'^\+?[1-9]\d{1,14}$', v):
raise ValueError("Invalid phone format")
return v
```
## Related Resources
- [Simple Object Extraction](./simple_object.md) - Extracting basic objects
- [Field Validation](./field_validation.md) - Adding validation to fields
- [Nested Structure](./nested_structure.md) - Working with complex data
- [Missing Concepts](../../concepts/maybe.md) - Using the Maybe type for uncertain fields
## Next Steps
- Learn about [Field Validation](./field_validation.md)
- Explore [Nested Structure](./nested_structure.md) for complex data
- Check out [Prompt Templates](./prompt_templates.md) for crafting prompts

View File

@@ -0,0 +1,174 @@
---
title: Using Prompt Templates with Instructor
description: Learn how to create reusable prompt templates for consistent structured output extraction across different use cases.
---
# Prompt Templates
This guide covers how to use prompt templates with Instructor to create reusable, parameterized prompts for structured data extraction.
## Why Prompt Templates Matter
Good prompts are essential for effective structured data extraction. Prompt templates help you:
1. Create consistent and reusable prompts
2. Parameterize prompts with dynamic values
3. Separate prompt engineering from application logic
4. Standardize prompt patterns for different use cases
## Basic Prompt Templates
The simplest form of a prompt template is a string with placeholders for variables:
```python
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class Person(BaseModel):
name: str
age: int
occupation: str
# Define a template with parameters
prompt_template = """
Extract information about the person mentioned in the following {document_type}:
{content}
Please provide their name, age, and occupation.
"""
# Use the template with specific values
document_type = "email"
content = "Hi team, I'm introducing our new project manager, Sarah Johnson. She's 34 and has been in project management for 8 years."
prompt = prompt_template.format(
document_type=document_type,
content=content
)
# Extract structured data using the formatted prompt
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": prompt}
],
response_model=Person
)
```
## Using f-strings for Simple Templates
For simple cases, you can use f-strings to create prompt templates:
```python
def extract_person(content, document_type="text"):
prompt = f"""
Extract information about the person mentioned in the following {document_type}:
{content}
Please provide their name, age, and occupation.
"""
return client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": prompt}
],
response_model=Person
)
# Use the function
person = extract_person(
"According to his resume, John Smith (42) works as a software developer.",
document_type="resume"
)
```
## Template Functions
For more complex templates, create dedicated template functions:
```python
from typing import List, Optional
from pydantic import BaseModel
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class ProductReview(BaseModel):
product_name: str
rating: int
pros: List[str]
cons: List[str]
summary: str
def create_review_extraction_prompt(
review_text: str,
product_category: str,
include_sentiment: bool = False
) -> str:
sentiment_instruction = """
Also include a brief sentiment analysis of the review.
""" if include_sentiment else ""
return f"""
Extract product review information from the following {product_category} review:
{review_text}
Please identify:
- The name of the product being reviewed
- The numerical rating (1-5)
- A list of pros/positive points
- A list of cons/negative points
- A brief summary of the review
{sentiment_instruction}
"""
# Use the template function
review_text = """
I recently purchased the UltraSound X300 headphones, and I'm mostly satisfied.
The sound quality is amazing and the battery lasts for days. They're also very
comfortable to wear for long periods. However, they're a bit pricey at $299, and
the Bluetooth occasionally disconnects. Overall, I'd give them 4 out of 5 stars.
"""
prompt = create_review_extraction_prompt(
review_text=review_text,
product_category="headphone",
include_sentiment=True
)
review = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": prompt}
],
response_model=ProductReview
)
```
## Best Practices for Prompt Templates
1. **Be explicit about the output format**: Clearly specify what fields you need and in what format
2. **Use consistent language**: Maintain consistent terminology throughout the template
3. **Keep it concise**: Avoid unnecessary verbosity that could confuse the model
4. **Parameterize only what varies**: Only make template parameters for parts that need to change
5. **Include examples for complex tasks**: Provide few-shot examples for more complex extractions
6. **Test with different inputs**: Ensure your template works well with a variety of inputs
## Related Resources
- [Simple Object Extraction](./simple_object.md) - Extracting basic objects
- [List Extraction](./list_extraction.md) - Working with lists of objects
- [Optional Fields](./optional_fields.md) - Handling optional data
- [Prompting](../../concepts/prompting.md) - General prompting concepts
- [Templating](../../concepts/templating.md) - Advanced template techniques
## Next Steps
- Explore [Field Validation](./field_validation.md) for ensuring data quality
- Try [List Extraction](./list_extraction.md) for extracting multiple items
- Learn about [Nested Structure](./nested_structure.md) for complex data

View File

@@ -0,0 +1,145 @@
---
title: Simple Object Extraction Pattern
description: Learn the fundamental pattern of extracting simple objects from text using Instructor with type-safe validation.
---
# Simple Object Extraction: LLM Tutorial for Structured Data
Learn how to extract structured objects from text using LLMs in this comprehensive tutorial. We'll cover the fundamental pattern of transforming unstructured text into validated Python objects using Instructor with GPT-4, Claude, and other language models.
## Basic LLM Object Extraction Tutorial
```python
from pydantic import BaseModel
import instructor
# Define your LLM extraction schema
class Person(BaseModel):
name: str
age: int
occupation: str
# Extract structured data from LLM
client = instructor.from_provider("openai/gpt-5-nano")
person = client.create(
model="gpt-3.5-turbo", # Works with GPT-4, Claude, Gemini
messages=[
{"role": "user", "content": "John Smith is a 35-year-old software engineer."}
],
response_model=Person # Type-safe LLM extraction
)
print(f"Name: {person.name}")
print(f"Age: {person.age}")
print(f"Occupation: {person.occupation}")
```
```
┌───────────────┐ ┌───────────────┐
│ Define Model │ │ Extracted │
│ name: str │ Extract │ name: "John" │
│ age: int │ ─────────> │ age: 35 │
│ occupation: str│ │ occupation: │
└───────────────┘ │ "software..." │
└───────────────┘
```
## Enhance LLM Extraction with Field Descriptions
Guide your LLM with clear field descriptions for more accurate extraction:
```python
from pydantic import BaseModel, Field
class Book(BaseModel):
title: str = Field(description="The full title of the book")
author: str = Field(description="The author's full name")
publication_year: int = Field(description="The year the book was published")
```
Field descriptions serve as prompts for the LLM, improving extraction accuracy and reducing errors in your structured outputs.
## Handle Missing Data in LLM Responses
Real-world LLM extractions often encounter missing information. Here's how to handle it gracefully:
```python
from typing import Optional
from pydantic import BaseModel
class MovieReview(BaseModel):
title: str
director: Optional[str] = None # Optional field
rating: float
```
Using `Optional` fields ensures your LLM extraction remains robust when dealing with incomplete or partial information.
## Validate LLM Outputs with Pydantic
Ensure LLM outputs meet your requirements with built-in validation:
```python
from pydantic import BaseModel, Field
class Product(BaseModel):
name: str
price: float = Field(gt=0, description="The product price in USD")
in_stock: bool
```
Pydantic validation ensures your LLM outputs are not just structured, but also correct and business-rule compliant.
## Production-Ready LLM Extraction Example
Here's a complete example showing nested object extraction from LLMs:
```python
from pydantic import BaseModel
from typing import Optional
class Address(BaseModel):
street: str
city: str
state: str
zip_code: str
class ContactInfo(BaseModel):
name: str
email: str
phone: Optional[str] = None
address: Optional[Address] = None
# Extract structured data
client = instructor.from_provider("openai/gpt-5-nano")
contact = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": """
Contact information:
Name: Sarah Johnson
Email: sarah.j@example.com
Phone: (555) 123-4567
Address: 123 Main St, Boston, MA 02108
"""}
],
response_model=ContactInfo
)
print(f"Name: {contact.name}")
print(f"Email: {contact.email}")
```
## Common LLM Object Extraction Use Cases
- **Contact Information**: Extract names, emails, phones from unstructured text
- **Product Details**: Parse product descriptions into structured catalogs
- **Event Information**: Extract dates, locations, attendees from event descriptions
- **Entity Recognition**: Identify and structure people, places, organizations
## Continue Your LLM Tutorial Journey
- **[List Extraction Tutorial](list_extraction.md)** - Extract multiple objects from LLM responses
- **[Nested Structures](nested_structure.md)** - Handle complex hierarchical data from LLMs
- **[Advanced Validation](field_validation.md)** - Implement business rules for LLM outputs
Master these patterns to build production-ready LLM applications with reliable structured outputs!

View File

@@ -0,0 +1,114 @@
---
title: Streaming Basics with Instructor
description: Learn how to use streaming to receive partial structured responses from LLMs as they are generated.
---
# Streaming Basics
Streaming allows you to receive parts of a structured response as they're generated, rather than waiting for the complete response.
## Why Use Streaming?
Streaming offers several benefits:
1. **Faster Perceived Response**: Users see results immediately
2. **Progressive UI Updates**: Update your interface as data arrives
3. **Processing While Generating**: Start using data before the complete response is ready
```
Without Streaming:
┌─────────┐ ┌─────────────────────┐
│ Request │─── Wait ───>│ Complete Response │
└─────────┘ └─────────────────────┘
With Streaming:
┌─────────┐ ┌───────┐ ┌───────┐ ┌───────┐
│ Request │───>│Part 1 │───>│Part 2 │───>│Part 3 │─── ...
└─────────┘ └───────┘ └───────┘ └───────┘
```
## Simple Example
Here's how to stream a structured response:
```python
import instructor
from pydantic import BaseModel
# Define your data structure
class UserProfile(BaseModel):
name: str
bio: str
interests: list[str]
# Set up client
client = instructor.from_provider("openai/gpt-5-nano")
# Enable streaming
for partial in client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "Generate a profile for Alex Chen"}
],
response_model=UserProfile,
stream=True # This enables streaming
):
# Print each update as it arrives
print("\nUpdate received:")
# Access available fields
if hasattr(partial, "name") and partial.name:
print(f"Name: {partial.name}")
if hasattr(partial, "bio") and partial.bio:
print(f"Bio: {partial.bio[:30]}...")
if hasattr(partial, "interests") and partial.interests:
print(f"Interests: {', '.join(partial.interests)}")
```
## How Streaming Works
When streaming with Instructor:
1. Enable streaming with `stream=True`
2. The method returns an iterator of partial responses
3. Each partial contains fields that have been completed so far
4. You check for fields using `hasattr()` since they appear incrementally
5. The final iteration contains the complete response
## Progress Tracking Example
Here's a simple way to track progress:
```python
import instructor
from pydantic import BaseModel
client = instructor.from_provider("openai/gpt-5-nano")
class Report(BaseModel):
title: str
summary: str
conclusion: str
# Track completed fields
completed = set()
total_fields = 3 # Number of fields in our model
for partial in client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "Generate a report on climate change"}
],
response_model=Report,
stream=True
):
# Check which fields are complete
for field in ["title", "summary", "conclusion"]:
if hasattr(partial, field) and getattr(partial, field) and field not in completed:
completed.add(field)
percent = (len(completed) / total_fields) * 100
print(f"Received: {field} - {percent:.0f}% complete")
```
## Next Steps
- Explore [Streaming Lists](lists.md) for handling collections
- Learn about [Validation with Streaming](../validation/basics.md)

View File

@@ -0,0 +1,101 @@
---
title: Streaming Lists with Instructor
description: Learn how to stream lists of structured objects from LLMs, processing collection items as they are generated for better responsiveness.
---
# Streaming Lists
This guide explains how to stream lists of structured data with Instructor. Streaming lists allows you to process collection items as they're generated, improving responsiveness for larger outputs.
## Basic List Streaming
Here's how to stream a list of structured objects:
```python
from typing import Iterable
import instructor
from pydantic import BaseModel, Field
# Initialize the client
client = instructor.from_provider("openai/gpt-5-nano")
class Book(BaseModel):
title: str = Field(..., description="Book title")
author: str = Field(..., description="Book author")
year: int = Field(..., description="Publication year")
# Stream a list of books
for book in client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "List 5 classic science fiction books"}
],
response_model=Iterable[Book],
):
print(f"Received: {book.title} by {book.author} ({book.year})")
```
This example shows how to:
1. Define a Pydantic model for each list item
2. Use Python's typing system to specify a list
3. Process each item as it arrives in the stream
## Real-world Example: Task Generation
Here's a practical example of streaming a list of tasks with progress tracking:
```python
from typing import Iterable
import instructor
from pydantic import BaseModel, Field
import time
client = instructor.from_provider("openai/gpt-5-nano")
class Task(BaseModel):
title: str = Field(..., description="Task title")
description: str = Field(..., description="Detailed task description")
priority: str = Field(..., description="Task priority (High/Medium/Low)")
estimated_hours: float = Field(..., description="Estimated hours to complete")
print("Generating project tasks...")
start_time = time.time()
received_tasks = 0
for task in client.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "Generate a list of 5 tasks for building a personal website",
}
],
response_model=Iterable[Task],
stream=True,
):
received_tasks += 1
print(f"\nTask {received_tasks}: {task.title} (Priority: {task.priority})")
print(f"Description: {task.description[:100]}...")
print(f"Estimated time: {task.estimated_hours} hours")
# Calculate progress percentage based on expected items
progress = (received_tasks / 5) * 100
print(f"Progress: {progress:.0f}%")
elapsed_time = time.time() - start_time
print(f"\nAll {received_tasks} tasks generated in {elapsed_time:.2f} seconds")
```
## Related Resources
- [Streaming Basics](./basics.md) - Fundamentals of streaming structured outputs
- [List Extraction](../../learning/patterns/list_extraction.md) - Core concepts for working with lists
- [Validation Basics](../../learning/validation/basics.md) - Understanding validation for streaming
- [Streaming API](../../concepts/partial.md) - Technical details on the streaming implementation
## Next Steps
- Learn about [Validation](../../learning/validation/basics.md) to ensure your streamed data is valid
- Explore [Field Validation](../../learning/validation/field_level_validation.md) for more control
- See [Async Support](../../integrations/index.md) for integrating streaming with your specific provider when writing asynchronous code

View File

@@ -0,0 +1,116 @@
---
title: LLM Validation Basics with Instructor
description: Master the fundamentals of validating LLM outputs to ensure reliable, business-compliant structured data from GPT-4, Claude, and other models.
---
# LLM Validation Tutorial: Ensure Data Quality with Instructor
Master the fundamentals of validating LLM outputs in this comprehensive tutorial. Learn how to use Instructor's validation system to ensure GPT-4, Claude, and other language models produce reliable, business-compliant structured data.
## Why LLM Output Validation is Critical
When extracting structured data from LLMs, validation ensures:
1. **Data Integrity**: LLM outputs contain all required fields with correct formats
2. **Business Compliance**: Extracted data adheres to your domain rules and constraints
3. **Production Reliability**: LLM responses meet quality standards before entering your system
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ LLM │ -> │ Instructor │ -> │ Validated │
│ Generates │ │ Validates │ │ Structured │
│ Response │ │ Structure │ │ Data │
└─────────────┘ └──────────────┘ └─────────────┘
│ If validation fails
┌─────────────┐
│ Retry with │
│ Feedback │
└─────────────┘
```
## Basic LLM Validation Example
See how Instructor validates LLM outputs automatically:
```python
from pydantic import BaseModel, Field
import instructor
# Define validation rules for LLM extraction
class UserProfile(BaseModel):
name: str
age: int = Field(ge=13, description="User's age in years")
# Extract and validate LLM output
client = instructor.from_provider("openai/gpt-5-nano")
response = client.create(
model="gpt-3.5-turbo", # Works with GPT-4, Claude, Gemini
messages=[
{"role": "user", "content": "My name is Jane Smith and I'm 25 years old."}
],
response_model=UserProfile # Automatic validation
)
print(f"User: {response.name}, Age: {response.age}")
```
Key validation features in this LLM tutorial:
- **Constraint Validation**: Age must be ≥ 13 years
- **Automatic Retry**: If LLM output fails validation, Instructor retries with error context
- **Type Safety**: Ensures LLM returns proper data types
## Essential LLM Validation Patterns
Common validation rules for LLM outputs:
| Validation | Example | What It Does |
|------------|---------|-------------|
| Type checking | `age: int` | Ensures value is an integer |
| Required fields | `name: str` | Field must be present |
| Optional fields | `middle_name: Optional[str] = None` | Field can be missing |
| Minimum value | `age: int = Field(ge=18)` | Value must be ≥ 18 |
| Maximum value | `rating: float = Field(le=5.0)` | Value must be ≤ 5.0 |
| String length | `username: str = Field(min_length=3)` | String must be at least 3 chars |
## How LLM Output Validation Works
The LLM validation pipeline in Instructor:
1. **LLM Generation**: Language model produces structured output
2. **Schema Matching**: Instructor maps LLM response to your Pydantic model
3. **Validation Check**: Pydantic validates against defined constraints
4. **Smart Retry**: On failure, errors are sent back to the LLM with context
5. **Success or Timeout**: Process continues until valid output or retry limit
## Enhance LLM Validation with Custom Messages
Guide LLMs with specific error messages for better corrections:
```python
from pydantic import BaseModel, Field
class Product(BaseModel):
name: str
price: float = Field(
gt=0,
description="Product price in USD",
json_schema_extra={"error_msg": "Price must be greater than zero"}
)
```
## Common LLM Validation Use Cases
- **Age Verification**: Ensure extracted ages meet minimum requirements
- **Price Validation**: Verify LLM-extracted prices are positive numbers
- **Email Format**: Validate email addresses from unstructured text
- **Date Constraints**: Ensure dates are within valid ranges
- **Business Rules**: Enforce domain-specific constraints on LLM outputs
## Continue Your LLM Validation Journey
- **[Custom Validators](custom_validators.md)** - Build complex validation logic for LLM outputs
- **[Retry Mechanisms](retry_mechanisms.md)** - Configure how Instructor handles validation failures
- **[Field-Level Validation](field_level_validation.md)** - Validate individual fields in LLM responses
Master validation to ensure your LLM applications produce reliable, production-ready data!

View File

@@ -0,0 +1,220 @@
---
title: Custom Validators for LLM Outputs
description: Learn to build custom validators for LLM outputs using rule-based and semantic validation techniques with Instructor.
---
# Custom LLM Validators Tutorial: Advanced Data Quality Control
Learn how to build custom validators for LLM outputs in this advanced tutorial. Master both rule-based and semantic validation techniques to ensure GPT-4, Claude, and other language models produce data that meets your exact requirements.
## Basic Custom Validator
Custom validators are functions that validate field values and can be applied using Pydantic's field validators.
```python
from pydantic import BaseModel, field_validator
import instructor
# Initialize the client
client = instructor.from_provider("openai/gpt-5-nano")
class Person(BaseModel):
name: str
age: int
@field_validator('age')
@classmethod
def validate_age(cls, value):
if value < 0 or value > 120:
raise ValueError("Age must be between 0 and 120")
return value
# Extract data with validation
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "The person's name is John and they are 150 years old."}
],
response_model=Person
)
```
If the model returns an age outside the valid range, Instructor will retry the request with specific feedback about the validation failure.
For more information on how Instructor handles validation and retries, see [Validation Basics](../../concepts/validation.md) and the [Retrying](../../concepts/retrying.md) concepts page.
## Complex Validation
You can create more complex validators that check multiple fields or have conditional logic:
```python
from pydantic import BaseModel, field_validator, model_validator
import instructor
from typing import List, Optional
from datetime import date
client = instructor.from_provider("openai/gpt-5-nano")
class Employee(BaseModel):
name: str
hire_date: date
termination_date: Optional[date] = None
skills: List[str]
@field_validator('skills')
@classmethod
def validate_skills(cls, skills):
if len(skills) < 1:
raise ValueError("Employee must have at least one skill")
return skills
@model_validator(mode='after')
def validate_dates(self):
if self.termination_date and self.termination_date < self.hire_date:
raise ValueError("Termination date cannot be before hire date")
return self
```
For more advanced validation approaches, check out [Field-level Validation](../../concepts/fields.md) and the [Validators](../../concepts/reask_validation.md) concepts page.
## Handling Complex Data Types
Custom validators can also process more complex data types and perform transformations:
```python
from pydantic import BaseModel, field_validator
import instructor
import re
client = instructor.from_provider("openai/gpt-5-nano")
class Contact(BaseModel):
name: str
email: str
phone: str
@field_validator('email')
@classmethod
def validate_email(cls, value):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(pattern, value):
raise ValueError("Invalid email format")
return value
@field_validator('phone')
@classmethod
def validate_phone(cls, value):
# Remove non-digit characters and validate
digits_only = re.sub(r'\D', '', value)
if len(digits_only) < 10:
raise ValueError("Phone number must have at least 10 digits")
return digits_only # Return the cleaned version
```
For a practical example of extraction with validation, see the [Contact Information Extraction](../../examples/extract_contact_info.md) example.
## Using External Services for Validation
You can also use external services or APIs for validation:
```python
from pydantic import BaseModel, field_validator
import instructor
import requests
client = instructor.from_provider("openai/gpt-5-nano")
class Address(BaseModel):
street: str
city: str
state: str
zip_code: str
@field_validator('zip_code')
@classmethod
def validate_zip_code(cls, value):
# Example of validation using an external service (simplified)
# In a real app, you might use a postal code validation API
if not (value.isdigit() and len(value) == 5):
raise ValueError("Zip code must be 5 digits")
return value
```
## Semantic Validation with LLMs
For complex validation scenarios where rule-based validation is difficult, Instructor provides semantic validation capabilities using LLMs via the `llm_validator` function. For a comprehensive guide on this topic, see the dedicated [Semantic Validation](../../concepts/semantic_validation.md) page:
```python
from typing import Annotated
from pydantic import BaseModel, BeforeValidator
import instructor
from instructor import llm_validator
client = instructor.from_provider("openai/gpt-5-nano")
class ProductDescription(BaseModel):
product_name: str
description: Annotated[
str,
BeforeValidator(
llm_validator(
"The description must be professional, accurate, and free of hyperbole. "
"It should not make unsubstantiated claims or use superlatives excessively.",
client=client
)
)
]
# This would fail validation because it uses excessive hyperbole
try:
product = ProductDescription(
product_name="SuperClean 3000",
description="The absolute BEST cleaning product in the world! Will change your life FOREVER! Makes every other cleaning product completely OBSOLETE!"
)
except ValueError as e:
print(e) # The validation error would explain the issue with the hyperbolic language
```
Semantic validation is particularly useful for validating against criteria that are:
1. **Subjective** - Such as tone, style, or appropriateness
2. **Contextual** - Requiring understanding of relationships between elements
3. **Complex** - Where multiple interrelated factors need to be evaluated together
4. **Hard to formalize** - When rules would be too numerous or complex to express programmatically
Unlike rule-based validators that check against predefined criteria, semantic validators leverage LLMs to evaluate content based on natural language instructions. They can understand nuance and context in ways that traditional validation cannot.
### When to Use Semantic Validation
Consider using semantic validation when:
- You need to enforce style guidelines or content policies
- Validating natural language content against subjective criteria
- Checking for consistency across multiple fields or complex relationships
- Traditional validation would require hundreds of individual rules
Remember that semantic validation requires additional API calls, which adds cost and latency to your application. Use it strategically for high-value validation needs rather than for simple constraints that can be handled with standard validators.
## Handling Validation Failures
When validation fails, Instructor can handle it in different ways. Learn more about:
- [Retry Mechanisms](../../concepts/retrying.md) for automatic retries with feedback
- [Self-Correction](../../examples/self_critique.md) for AI model self-correction techniques
## Best Practices for Custom Validators
1. **Be specific in error messages**: Provide clear error messages that explain exactly what went wrong
2. **Validate early**: Apply validators to individual fields when possible before model-level validation
3. **Keep validators focused**: Each validator should have a single responsibility
4. **Use type hints**: Proper type hints help both Pydantic and Instructor understand your data better
5. **Consider both validation and transformation**: Validators can both validate and transform data
6. **Choose appropriate validation type**: Use rule-based validation for simple, objective criteria and semantic validation for complex, subjective, or context-dependent validation
7. **Balance cost and benefits**: Consider the additional cost and latency of semantic validation against the value it provides
For more information on validation in general, check out the [Validation](../../concepts/validation.md) concepts page.
## Related Resources
- [Fields](../../concepts/fields.md) - Learn about field definitions and properties
- [Models](../../concepts/models.md) - Understand model creation and configuration
- [Types](../../concepts/types.md) - Explore the different data types you can use
Custom validators are a powerful way to ensure the data you extract meets your specific requirements, improving the reliability and quality of structured outputs from LLMs.

View File

@@ -0,0 +1,128 @@
---
title: Field-level Validation with Instructor
description: Learn how to create specific validation rules for individual fields in your Pydantic models to ensure data quality.
---
# Field-level Validation
Field-level validation lets you create specific rules for individual fields in your data models. This guide shows how to use field-level validation with Instructor.
## What is Field-level Validation?
Field-level validation in Instructor uses Pydantic's validation features to:
1. Check individual fields with custom rules
2. Transform field values (like formatting or cleaning data)
3. Apply business rules to specific fields
4. Give clear feedback when values are invalid
Validation happens when your model is being processed, and if it fails, Instructor will retry with better instructions.
## Basic Field Validation
You can apply simple validation using Pydantic's Field constraints:
```python
from pydantic import BaseModel, Field
import instructor
client = instructor.from_provider("openai/gpt-5-nano")
class User(BaseModel):
name: str = Field(..., min_length=2, description="User's full name")
age: int = Field(..., ge=18, le=120, description="User's age in years")
email: str = Field(
...,
pattern=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
description="Valid email address"
)
```
For more details, see the [Fields](../../concepts/fields.md) concepts page.
## Custom Field Validators
For more complex rules, use the `field_validator` decorator:
```python
from pydantic import BaseModel, field_validator
import instructor
import re
client = instructor.from_provider("openai/gpt-5-nano")
class Product(BaseModel):
name: str
sku: str
price: float
@field_validator('name')
@classmethod
def validate_name(cls, v):
if len(v.strip()) < 3:
raise ValueError("Product name must be at least 3 characters long")
return v.strip().title() # Clean up and format
@field_validator('sku')
@classmethod
def validate_sku(cls, v):
pattern = r'^[A-Z]{3}-\d{4}$'
if not re.match(pattern, v):
raise ValueError("SKU must be in format XXX-0000 (3 uppercase letters, dash, 4 digits)")
return v
```
## Validating Multiple Fields Together
Sometimes one field's validity depends on other fields. Use `model_validator` for this:
```python
from pydantic import BaseModel, model_validator
import instructor
from datetime import date
client = instructor.from_provider("openai/gpt-5-nano")
class Reservation(BaseModel):
check_in: date
check_out: date
room_type: str
guests: int
@model_validator(mode='after')
def validate_dates(self):
if self.check_out <= self.check_in:
raise ValueError("Check-out date must be after check-in date")
if self.room_type == "Standard" and self.guests > 2:
raise ValueError("Standard rooms can only fit 2 guests")
return self
```
## How Validation Errors Are Handled
When validation fails, Instructor adds error details to help the AI fix the problem:
```
The following errors occurred during validation:
- product_sku: Product not found
- quantity: Quantity must be at least 1
Please fix these errors and ensure the response is valid.
```
## Best Practices
1. **Order matters**: Validators run in the order they're defined
2. **Clear messages**: Write specific error messages
3. **Clean first**: Handle data cleaning before validation
4. **Validate early**: Check fields before model-level validation
5. **Transform wisely**: Field validators can both check and change values
## Related Resources
- [Fields](../../concepts/fields.md) - Basic field properties
- [Custom Validators](../../concepts/reask_validation.md) - Creating custom validation logic
- [Validation Basics](../../concepts/validation.md) - Fundamental validation concepts
- [Retry Mechanisms](../../concepts/retrying.md) - How validation retries work
- [Fallback Strategies](../../concepts/error_handling.md) - Handling persistent validation failures
- [Types](../../concepts/types.md) - Understanding data types in Pydantic models

View File

@@ -0,0 +1,206 @@
# Retry Mechanisms
Retry mechanisms in Instructor handle validation failures by giving the LLM another chance to generate valid responses. This guide explains how retries work and how to customize them for your use case.
## How Retries Work
When validation fails, Instructor:
1. Captures the validation error(s)
2. Formats them as feedback
3. Adds the feedback to the prompt context
4. Asks the LLM to try again with this new information
This creates a feedback loop that helps the LLM correct its output until it produces a valid response.
## Basic Retry Example
Here's a simple example showing retries in action:
```python
import instructor
from pydantic import BaseModel, Field, field_validator
# Initialize the client with max_retries
client = instructor.from_provider(
"openai/gpt-4o",
max_retries=2 # Will try up to 3 times (initial + 2 retries)
)
class Product(BaseModel):
name: str
price: float = Field(..., gt=0)
@field_validator('name')
@classmethod
def validate_name(cls, v):
if len(v) < 3:
raise ValueError("Product name must be at least 3 characters")
return v
# This will automatically retry if validation fails
response = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "Product: Pen, Price: -5"}
],
response_model=Product
)
```
In this example, the initial response will likely fail validation because:
- The price is negative (violating the `gt=0` constraint)
- Instructor will automatically retry with feedback about these issues
For more details on max_retries configuration, see the [Retrying](../../concepts/retrying.md) concepts page.
## Customizing Retry Behavior
You can customize retry behavior when initializing the Instructor client:
```python
import instructor
# Customize retry behavior
client = instructor.from_provider(
"openai/gpt-4o",
max_retries=3, # Maximum number of retries
retry_if_parsing_fails=True, # Retry on JSON parsing failures
throw_error=True # Throw an error if all retries fail
)
```
### Retry Configuration Options
| Option | Description | Default |
|--------|-------------|---------|
| `max_retries` | Maximum number of retry attempts | 0 |
| `retry_if_parsing_fails` | Whether to retry if JSON parsing fails | True |
| `throw_error` | Whether to throw an error if all retries fail | True |
## Handling Retry Failures
When all retries fail, Instructor raises an `InstructorRetryException` that contains comprehensive information about all failed attempts:
```python
from instructor.core.exceptions import InstructorRetryException
try:
response = client.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Product: Invalid data"}],
response_model=Product,
max_retries=3
)
except InstructorRetryException as e:
print(f"Failed after {e.n_attempts} attempts")
print(f"Total usage: {e.total_usage}")
# New: Access detailed information about each failed attempt
for attempt in e.failed_attempts:
print(f"Attempt {attempt.attempt_number}: {attempt.exception}")
if attempt.completion:
# Analyze the raw completion that failed validation
print(f"Raw response: {attempt.completion}")
```
The `InstructorRetryException` now includes:
- `failed_attempts`: A list of `FailedAttempt` objects containing:
- `attempt_number`: The retry attempt number
- `exception`: The specific exception that occurred
- `completion`: The raw LLM response (when available)
- `n_attempts`: Total number of attempts made
- `total_usage`: Total token usage across all attempts
- `last_completion`: The final failed completion
- `messages`: The conversation history
This comprehensive tracking enables better debugging and analysis of retry patterns.
For more on handling validation failures, see [Fallback Strategies](../../concepts/error_handling.md).
## Error Messages and Feedback
Instructor provides detailed error messages to the LLM during retries:
```
The following errors occurred during validation:
- price: ensure this value is greater than 0
- name: Product name must be at least 3 characters
Please fix these errors and ensure the response is valid.
```
This feedback helps the LLM understand exactly what needs to be fixed.
## Retry Limitations
While retries are powerful, they have some limitations:
1. **Retry Budget**: Each retry consumes tokens and time
2. **Persistent Errors**: Some errors might not be fixable by the LLM
3. **Model Limitations**: Some models may consistently struggle with certain validations
For complex validation scenarios, consider implementing [Custom Validators](custom_validators.md) or [Field-level Validation](field_level_validation.md).
## Advanced Retry Pattern: Progressive Validation
For complex schemas, you can implement a progressive validation pattern:
```python
import instructor
from pydantic import BaseModel, Field
# Initialize with moderate retries
client = instructor.from_provider(
"openai/gpt-4o",
max_retries=2
)
# Basic validation first
class BasicProduct(BaseModel):
name: str
price: float = Field(..., gt=0)
# Advanced validation second
class DetailedProduct(BasicProduct):
description: str = Field(..., min_length=10)
category: str
in_stock: bool
# Two-step extraction with validation
try:
# First get basic fields
basic = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "Product: Mini Pen, Price: $2.50"}
],
response_model=BasicProduct
)
# Then get full details with context from the first step
detailed = client.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": f"Provide more details about {basic.name} which costs ${basic.price}"}
],
response_model=DetailedProduct
)
except Exception as e:
# Handle validation failures
print(f"Validation failed: {e}")
```
## Related Resources
- [Retrying](../../concepts/retrying.md) - Core retry concepts
- [Validation](../../concepts/validation.md) - Main validation documentation
- [Custom Validators](../../concepts/reask_validation.md) - Creating custom validation logic
- [Fallback Strategies](../../concepts/error_handling.md) - Handling persistent validation failures
- [Self Critique](../../examples/self_critique.md) - Example of model self-correction
## Next Steps
- Learn about [Field-level Validation](field_level_validation.md)
- Implement [Custom Validators](custom_validators.md)