Instructor: The Python Library That Forces LLMs to Output Valid JSON
Stop wrestling with inconsistent LLM outputs. Learn how Instructor patches the OpenAI client to guarantee valid, type-safe JSON responses using Pydantic models. Features retry logic, multi-provider support, and streaming.
- ⭐ 18000
- Python
- MIT
- Updated 2026-08-27
Last updated: May 19, 2026
If you’ve ever tried to get a Large Language Model to consistently output valid JSON, you know the pain. One response is perfect. The next misses a closing brace. The third includes explanatory text before the JSON. The fourth returns valid JSON but with the wrong schema. This inconsistency makes LLMs unreliable for production applications that need structured data — until Instructor arrived on the scene.
Instructor is a Python library that patches the OpenAI client (and 10+ other LLM providers) to guarantee structured, type-safe, validated outputs using Pydantic models. It transforms the wild west of LLM text generation into a predictable, software-engineered process. With 11,000+ GitHub stars, MIT license, and a thriving community, Instructor has become the de facto standard for structured LLM output in Python. This guide covers everything from basic setup to advanced multi-provider patterns in 2026.
Quick Start #
pip install instructor
import instructor
from openai import OpenAI
from pydantic import BaseModel
# Patch the OpenAI client
client = instructor.from_openai(OpenAI())
class UserDetail(BaseModel):
name: str
age: int
role: str
# Get validated, typed output — guaranteed
user = client.chat.completions.create(
model="gpt-4o",
response_model=UserDetail,
messages=[{"role": "user", "content": "Jason is 25, a senior engineer"}],
)
print(user.name, user.age, user.role)
# Jason 25 senior engineer
If the model returns invalid output, Instructor automatically retries with the validation error injected back into the prompt — up to 3 times by default.
How It Works #
Instructor uses function calling under the hood. It serializes your Pydantic model as a JSON schema, tells the model to emit a function call matching that schema, then validates the result. If validation fails:
- The error is captured
- A new request is sent with the error message appended
- The model corrects itself
The result: response_model guarantees a BaseModel instance, not a string you have to parse and hope.
Key Features #
1. Validation with Retries #
from pydantic import BaseModel, field_validator
class Recipe(BaseModel):
name: str
calories: int
@field_validator("calories")
@classmethod
def check_range(cls, v):
if v < 0 or v > 5000:
raise ValueError(f"Calories out of range: {v}")
return v
recipe = client.chat.completions.create(
model="gpt-4o",
response_model=Recipe,
max_retries=5, # override default
messages=[{"role": "user", "content": "A 5000-calorie burger recipe"}],
)
2. Streaming #
for chunk in client.chat.completions.create_partial(
model="gpt-4o",
response_model=Recipe,
messages=[{"role": "user", "content": "Pancake recipe"}],
stream=True,
):
print(chunk.model_dump())
3. Multi-Provider Support #
Instructor works beyond OpenAI:
# Anthropic
import instructor
from anthropic import Anthropic
client = instructor.from_anthropic(Anthropic())
# Cohere
from cohere import Client
client = instructor.from_cohere(Client())
# Gemini
from google.generativeai import GenerativeModel
client = instructor.from_gemini(GenerativeModel("gemini-1.5-pro"))
4. Async #
import asyncio, instructor
from openai import AsyncOpenAI
client = instructor.from_openai(AsyncOpenAI())
async def extract_many(texts):
results = await asyncio.gather(*[
client.chat.completions.create(
model="gpt-4o",
response_model=UserDetail,
messages=[{"role": "user", "content": t}],
) for t in texts
])
return results
Real-World Use Cases #
- Data extraction: pull structured records from unstructured documents
- Classification: force outputs into a fixed enum of categories
- Tool orchestration: validate function arguments before executing tools
- Multi-step agents: pass typed state between agent steps instead of raw strings
- Eval pipelines: generate structured ground-truth labels for benchmarks
Comparison with Alternatives #
| Feature | Instructor | Outlines | Pydantic AI |
|---|---|---|---|
| Approach | Function calling + validation | Constrained decoding | Agent framework |
| Provider coverage | 10+ | 10+ | OpenAI + Ollama |
| Retry loop | Built-in | N/A | Manual |
| Streaming | Yes | Yes | Yes |
| Learning curve | Low | Medium | Medium |
Conclusion #
Instructor solves the hardest practical problem in LLM engineering: reliable structured output. By combining function calling with Pydantic validation and automatic retries, it turns flaky text generation into typed, validated data structures. If your application needs consistent JSON from an LLM — extraction, classification, tool calling, or agent state — Instructor is the standard tool for the job in 2026.
💬 Discussion