Instructor
Instructor is a Python library (with multi-language bindings and even a Rust port) aiming to make getting structured JSON from LLMs extremely simple.
It’s built on Pydantic for schema definitions, similar in spirit to Pydantic AI, but taking things further by abstracting away everything - prompting, parsing, retrying, and more.
We'll show what we mean using this code example:
from pydantic import BaseModel
import instructor
class User(BaseModel):
name: str
age: int
client = instructor.from_provider("openai/gpt-4o") # choose a model/provider
user = client.chat.completions.create(
response_model=User,
messages=[{"role": "user", "content": "John is 25 years old"}],
)
print(user) # -> User(name='John', age=25)
Here is what instructor does under-the-hood:
- It sees that response_model is User, so it knows the output schema.
- It creates an underlying prompt to tell the model to output JSON with name and age.
- Since we use a commercial provider API which supports structured outputs, it uses OpenAI’s server-side structured output feature automatically. If it was an open model, it would instead include instructions or examples in the prompt to coax JSON out. Either way, the code remains the same except only the model_name parameter used to initialize the client.
- After getting the response (string), it parses it and validates against the User model.
- If parsing failes, Instructor handles it automatically by re-prompting or cleaning the output.
Thus, Instructor’s philosophy is to abstract away the differences between models. You can use the same code for both open source and closed source models by just changing the model_name parameter. It integrates with commercial provider-specific features when available, and falls back to the unconstrained method for open source models.
Some more features:
- It can cache results to avoid re-calling the model for identical prompts.
- It supports streaming responses (useful if showing partial output to a user interface).
- You can configure how many retries or whether to drop to a simpler method if the model fails structured output.
Limitations
- Abstraction layer: When things go wrong, you might have to peek into how Instructor is doing things (what prompt it sent, how it decided to parse). It’s doing a lot for you, which is great until you need to debug an edge case.
- Latency from validation/retries: Similar to other parse-and-retry approaches, if the first attempt fails, it has to do more work. Instructor is optimized to minimize this, but it can happen.
- If a provider changes their API or adds new features, Instructor needs to update to support it. There’s a bit of lag as it wraps many APIs.
Overall, Instructor is a strong choice if you are in a Python environment and want quick integration to “turn LLM into a reliable function”. It’s like making the LLM call a typed function that returns structured data.