Complete Instructor Tutorial: Structured Outputs from LLMs with Pydantic
Hey everyone, in this tutorial I want to introduce you to one of the Python libraries I think is absolutely worth learning if you work with LLMs a lot. It is called Instructor. If you have ever been frustrated because the output from a language model is sometimes clean and sometimes messy, sometimes valid JSON and sometimes with stray text tacked on at the front or back, then Instructor is the answer. I have been using this library in several production projects for a while now, and honestly it completely changed how I code with LLMs.
In this article I will cover everything from scratch, starting with why structured output matters, how to install it, basic usage, all the way to advanced features like nested models, automatic retries, streaming, and multi-provider support. I will also give you plenty of runnable Python code examples that you can try yourself. Let us get started.
Why Structured Output Matters
Before diving into Instructor, let me first talk about a problem we run into constantly when working with LLMs. Imagine you are building an application that needs to extract data from text. Say you have a customer email, and you want to pull out the name, email, and urgency level from it. The most naive approach is to just ask the LLM to return JSON.
The problem is that an LLM is fundamentally a text generator. It has no guarantee that it will produce output in a consistent format. Sometimes it returns valid JSON, sometimes it adds an intro like "Sure, here you go:" before the JSON. Sometimes it wraps everything in a markdown code block. Sometimes the data types are wrong, for example you asked for a number but it gives you a string. This becomes a real headache when you want to process that output further in your code.
The old approach usually involves manual parsing with regex, or trying json.loads() wrapped in a giant try-except. But this is extremely fragile. The moment the output format changes even slightly, your code breaks. On top of that you have to validate everything manually, like making sure the email field is actually an email, making sure age is a positive number, and so on.
This is where Instructor comes in. The idea is simple but brilliant, folks. We define the output structure we want using Pydantic, and Instructor takes care of getting the LLM to produce output matching that structure, along with the validation. If the output does not match, Instructor automatically asks the LLM to fix it. So we get output that is guaranteed to be typed and validated, ready to use directly in code. No more manual parsing that gives you headaches.
For those unfamiliar, Pydantic is a Python library for data validation based on type hints. We define a class with fields and their types, and Pydantic ensures the incoming data matches that definition. Instructor uses Pydantic as the contract between our code and the LLM.
Installation
Alright, let us get practical. Installation is super easy, just one line with pip.
pip install instructor
Instructor automatically brings along the dependencies it needs, including Pydantic. But you still need the LLM provider library, for example OpenAI or Anthropic. So I usually install them together like this.
pip install instructor openai anthropic
If you use a virtual environment (which I strongly recommend), activate your venv before installing. This keeps your project dependencies from getting mixed up with other projects.
python -m venv venv
source venv/bin/activate # on Windows: venv\Scripts\activate
pip install instructor openai
Do not forget to set up your API key. If you use OpenAI, set the environment variable OPENAIAPIKEY. If you use Anthropic, set ANTHROPICAPIKEY. I usually put mine in a .env file and load it with the python-dotenv library.
# .env file
OPENAIAPIKEY=sk-xxxxxxxxxxxxxxxx
Basic Usage
Now we get to the fun part. I will show you the most basic example first so you understand the core concept. Instructor really only has two key ideas: we patch our LLM client, then we pass a responsemodel parameter containing a Pydantic class.
Let us build a simple example. Say we want to extract information about a person from a sentence.
import instructor
from openai import OpenAI
from pydantic import BaseModel
Define the output structure we want
class Person(BaseModel):
name: str
age: int
occupation: str