Instructor: reliable structured outputs
Table of contents
- Key takeaways
- What problem does Instructor solve?
- Pydantic models as the output schema
- Automatic retries and validation
- Multi-provider support and local models
- Instructor versus the structured-outputs API
- Frequently asked questions
- How does Instructor differ from Pydantic AI?
- Does it work with models I run on my own machine?
- How much code does it take to get started?
- Conclusion
- Sources
Instructor is the most widely used Python library for getting reliable structured outputs from a language model: you define the result you expect as a Pydantic model, Instructor patches the client so the model honours it, and it retries on its own, with the validation error included, until it returns a valid, already-typed object.
Instructor is the most popular Python library for wringing structured, reliable data out of a language model, rather than a block of text you then have to parse by hand. Its idea is straightforward: you declare the answer you expect as a Pydantic model, pass it to your model client in response_model, and Instructor makes sure the output meets that schema, retrying on its own if the model breaks the format. In this guide you will see what problem it solves, how the schema is defined, how validation and retries work, its multi-provider support and how it differs from the native structured-outputs API. The same explanation is available in Spanish.
Key takeaways
- Instructor is an open-source library that extracts validated structured outputs from an LLM using Pydantic models; it has over 11,000 stars on GitHub and more than 3 million downloads a month.
- It is on version 1.15.4, released on 28 June 2026, and requires Python 3.9 or higher; you install it with a single
pip install instructor. - Its mechanism is a patch on the model client: it adds the
response_modelparameter and returns an already-typed instance instead of loose text. - When validation fails, it retries on its own: it re-asks the model with the error message included, up to
max_retriestimes, so the model corrects its own answer. - It is provider-agnostic: the same API works with more than 15 providers (OpenAI, Anthropic, Gemini, Mistral, Cohere, DeepSeek and local models with Ollama).
What problem does Instructor solve?
A language model returns text, and text is an awkward format for a program. If you need the answer to be an object with concrete fields (a name, a date, an amount), the usual approach is to ask the model to "reply in JSON", get a string back and cross your fingers on json.loads. That approach breaks often: the model adds a preamble before the JSON, invents a field, returns a number as text or drops a brace. Each of those failures blows up your program in production.
Instructor, created by Jason Liu (known as jxnl), targets exactly that gap. Instead of parsing text by hand, you describe the shape you want with a Pydantic model and let the library handle the rest: it instructs the model to produce that structure, validates the response against your schema and, if something does not fit, retries. The result is that your code always receives a valid Python object with the correct types, not a string to interpret. The same type discipline that Pydantic AI brings to building agents, Instructor brings to any single model call.
Pydantic models as the output schema
The heart of Instructor is that the output schema is, quite simply, a Pydantic class. You define the fields you want with their types, patch your provider client and pass that class in response_model. What you get back is no longer text: it is an instance of your class.
pip install instructor
import instructor
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
client = instructor.from_provider("openai/gpt-4o-mini")
user = client.chat.completions.create(
response_model=User,
messages=[{"role": "user", "content": "John is 25 years old"}],
)
print(user.name) # John
print(user.age) # 25, already validated as an int
The user object is an instance of User with its fields already validated: user.age is an int, not the string "25", and your editor autocompletes it and knows its type. The from_provider factory is the recommended shortcut in recent versions: with a single string you choose provider and model, and under the hood it applies the right patch.
Automatic retries and validation
The real power shows up when you add business rules, not just types. Because the schema is Pydantic, you can use validators: if the model returns something that breaks a rule, the validator raises an error, Instructor catches it and re-asks the model with that error as a hint, until max_retries is exhausted. It is a self-correction loop without you writing any retry logic.
import instructor
from pydantic import BaseModel, field_validator
client = instructor.from_provider("openai/gpt-4o-mini")
class Record(BaseModel):
name: str
age: int
@field_validator("age")
@classmethod
def valid_age(cls, v: int) -> int:
if v < 0 or v > 150:
raise ValueError(f"Age {v} is invalid")
return v
record = client.chat.completions.create(
response_model=Record,
messages=[{"role": "user", "content": "Extract the record from the text"}],
max_retries=3,
)
If the model returned an age of 200, the validator would reject it and Instructor would resend the request with the message "Age 200 is invalid" attached, so the model fixes it on the next attempt. Beyond a plain integer, max_retries accepts a Tenacity Retrying object, the reference retry library in Python, so you can configure exponential backoff or finer stop conditions. If you would rather guarantee the format during generation itself instead of retrying afterwards, that is the route of Outlines constrained generation.
Multi-provider support and local models
One of Instructor’s big draws is that the same API works for more than 15 providers. Switching from OpenAI to Anthropic, to Gemini or to a model you run on your own machine is a matter of editing the from_provider string; the rest of the code, with its response_model and its validators, stays untouched.
# Same schema and same call, different provider
client = instructor.from_provider("anthropic/claude-sonnet-4-5")
# Or a local model served by Ollama
client = instructor.from_provider("ollama/llama3.1")
For models you run locally with Ollama or llama-cpp, this combination is especially valuable: small open models are worse at respecting a format, and the pairing of "Pydantic validation plus retries" turns an unreliable output into a correct object without you having to patch strings by hand. If you are coming from function calling with Ollama, Instructor gives you the same capability with far more comfortable ergonomics. The library is not limited to Python: the same idea exists today in TypeScript, Go, Ruby, Elixir and Rust.
Instructor versus the structured-outputs API
Since 2024, OpenAI has offered native structured outputs: with response_format and a JSON schema in strict mode, the API guarantees the response is syntactically valid JSON conforming to that schema. It is an excellent feature, and it is worth understanding how it differs from Instructor, because they do not compete on the same plane.
The native API guarantees the shape of the JSON, but stops there and only exists in some providers. Instructor works one layer above and adds three things the native API does not cover: business validators in Python (rules like "age is between 0 and 150", beyond plain type checking), retries with feedback when one of those rules fails, and an identical API for more than 15 providers, including local models. In fact, Instructor can lean on the native feature underneath when the provider offers it. In practice: if you only use OpenAI and it is enough for the JSON to have the right shape, the native API is plenty; if you want custom-rule validation, automatic retries and no lock-in to a provider, Instructor is the more complete choice.
Frequently asked questions
How does Instructor differ from Pydantic AI?
They solve nearby but distinct problems. Instructor is a lightweight layer you patch onto your provider client so that a call returns a validated object; it does not impose an architecture. Pydantic AI is a full agent framework, with tools, dependencies and state graphs, that also validates the output with types. If you only want reliable structured extraction, Instructor is enough; if you are going to build a whole agent, Pydantic AI brings more pieces.
Does it work with models I run on my own machine?
Yes. Instructor supports local models through Ollama and llama-cpp-python, with the same from_provider API you would use with a cloud provider. Since small open models respect the format less well, the combination of Pydantic validation and automatic retries is exactly what makes them usable for extraction tasks without surprises.
How much code does it take to get started?
Very little. You install with pip install instructor, define a Pydantic class with the fields you want, patch the client with instructor.from_provider(...) and add response_model to your usual call. With those four lines you already receive a typed object instead of text, and from there you can add validators and max_retries as your case demands.
Conclusion
Instructor turns the most fragile part of working with an LLM, pulling structured data out of a text response, into something predictable: you define the shape with Pydantic, the library validates the output and retries on its own when the model gets it wrong, all with the same API for more than 15 providers. With over 11,000 stars, three million downloads a month and a minimal surface you can learn in an afternoon, it is the shortest path to reliable outputs. The next step is to install it with pip install instructor, write your first Pydantic model with a validator and compare it with Outlines constrained generation to decide which fits your project best.
Sources: [1] Official Instructor documentation[1], [2] Instructor on GitHub (567-labs)[2], [3] instructor package on PyPI[3], [4] Jason Liu’s blog, creator of Instructor[4].
Sources
Source code
Access all the source code for this post on GitHub.
View on GitHub