By Sagar Shankaran, Founder of CallSphere
Get started with the Instructor library to extract typed, validated Python objects from LLM responses. Covers setup, OpenAI patching, automatic retry logic, and validation-based error correction.
Key takeaways
Instructor is an open-source Python library that patches LLM client libraries (OpenAI, Anthropic, Mistral, and others) to return typed Pydantic objects instead of raw strings. It handles the entire structured output lifecycle: schema generation, prompt injection, response parsing, validation, and automatic retries when validation fails.
Instead of manually crafting JSON schemas, parsing responses, and writing retry loops, you define a Pydantic model and call the LLM. Instructor handles everything else.
pip install instructor
Instructor works by wrapping your existing OpenAI client:
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
import instructor
from openai import OpenAI
from pydantic import BaseModel
# Patch the OpenAI client
client = instructor.from_openai(OpenAI())
That single line transforms the client so that every call can accept a response_model parameter and return typed objects.
Define a Pydantic model and use it as the response_model:
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
class UserInfo(BaseModel):
name: str
age: int
email: str
user = client.chat.completions.create(
model="gpt-4o",
response_model=UserInfo,
messages=[
{"role": "user", "content": "John Smith is 32 years old. His email is john@example.com"}
],
)
print(user)
# UserInfo(name='John Smith', age=32, email='john@example.com')
print(type(user))
# <class '__main__.UserInfo'>
No JSON parsing. No schema construction. No validation code. The return value is a fully typed Python object.
When you call create() with a response_model, Instructor:
response_format or tools)This retry-with-error-feedback loop is what makes Instructor especially powerful. The model learns from its own mistakes within the same conversation.
Add Pydantic validators and let Instructor auto-correct:
from pydantic import field_validator
class MovieReview(BaseModel):
title: str
rating: float
genre: str
summary: str
@field_validator("rating")
@classmethod
def rating_in_range(cls, v: float) -> float:
if not 1.0 <= v <= 10.0:
raise ValueError(f"Rating must be between 1 and 10, got {v}")
return v
@field_validator("genre")
@classmethod
def valid_genre(cls, v: str) -> str:
allowed = {"action", "comedy", "drama", "horror", "sci-fi", "thriller"}
if v.lower() not in allowed:
raise ValueError(f"Genre must be one of {allowed}, got '{v}'")
return v.lower()
review = client.chat.completions.create(
model="gpt-4o",
response_model=MovieReview,
max_retries=3,
messages=[
{"role": "user", "content": "Review: Inception is a mind-bending masterpiece rated 9.2/10"}
],
)
print(review.genre) # "sci-fi"
print(review.rating) # 9.2
If the model returns a rating of 15 on the first attempt, Instructor catches the validation error and resends the request with a message like "Rating must be between 1 and 10, got 15. Please correct this." The model almost always self-corrects on the retry.
Instructor supports multiple extraction modes depending on your provider:
import instructor
# Use function calling (default, most compatible)
client = instructor.from_openai(OpenAI(), mode=instructor.Mode.TOOLS)
# Use JSON mode (simpler, slightly less reliable)
client = instructor.from_openai(OpenAI(), mode=instructor.Mode.JSON)
# Use structured outputs with strict schema (most reliable)
client = instructor.from_openai(OpenAI(), mode=instructor.Mode.JSON_SCHEMA)
JSON_SCHEMA mode uses OpenAI's constrained decoding and is the most reliable option for supported models. TOOLS mode works across more models and providers.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
Use Iterable to extract multiple objects from a single prompt:
from typing import Iterable
class Contact(BaseModel):
name: str
role: str
company: str
contacts = client.chat.completions.create(
model="gpt-4o",
response_model=Iterable[Contact],
messages=[
{
"role": "user",
"content": (
"Meeting attendees: Sarah Chen (CTO at TechCorp), "
"Mike Ross (Sales Lead at DataInc), "
"Lisa Park (Founder of AIStart)"
)
}
],
)
for contact in contacts:
print(f"{contact.name} - {contact.role} at {contact.company}")
Instructor is not limited to OpenAI. It supports Anthropic, Mistral, and any OpenAI-compatible API:
from anthropic import Anthropic
# Patch Anthropic client
client = instructor.from_anthropic(Anthropic())
result = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
response_model=UserInfo,
messages=[
{"role": "user", "content": "Extract: Alice is 28, alice@test.com"}
],
)
The same Pydantic models work across all providers. Switch providers without changing your extraction logic.
Instructor adds automatic retries with validation feedback, multi-provider support, streaming of partial objects, and a simpler API surface. With raw response_format, you handle parsing, validation, and retries yourself. Instructor is a convenience layer that eliminates that boilerplate.
Yes. Use instructor.from_openai() with any OpenAI-compatible API by setting the base_url parameter on the OpenAI client. Local models may be less reliable at following schemas, so set max_retries=5 and use simpler schemas.
The Python-side overhead is negligible — under 1ms per call. The real cost comes from retries: if your validators are too strict, you may burn extra API calls. Design validators that reject truly invalid data but accept reasonable variations.
#Instructor #Pydantic #StructuredOutputs #OpenAI #Python #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
OpenAI's Frontier platform makes model-native orchestration the default. What that means for agent builders, voice/chat buyers, and the build-vs-buy decision.
The 2026 desktop AI agent landscape — ServiceNow Project Arc, Anthropic Claude offerings, OpenAI agents, and Google Mariner. A buyer's map.
May 2026's biggest agent-architecture shift: planning, tool selection, and self-correction move inside the model. Framework code shrinks. Here is what changes.
A three-way comparison of Gemini Enterprise, Anthropic managed agents and OpenAI Frontier Platform after Cloud Next 2026 — strengths, gaps, buyer fit.
Anthropic's May 2026 push positions Claude as a vertical platform for financial services. The strategic positioning versus OpenAI and Google.
Anthropic's Mythos is not alone. Compare Mythos against OpenAI's cybersec offerings, Google's Big Sleep lineage, and open-source alternatives in 2026.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI