How It Works
The high-level flow is straightforward:- You describe the shape of the data you need (a response model).
- You provide input text, chat messages, or even another object.
- Instructor calls the LLM, extracts structured JSON, deserializes it into your model, validates the result, and retries if necessary.
User class, instructs the
LLM to respond in that format, maps the JSON back into a User instance, and runs any
validation rules before returning the object.
Core Concepts
Instructor keeps its model intentionally small. There are only a handful of concepts you need to understand to be productive.Response Model
The response model defines the shape you want back from the LLM. It is the contract between your code and the model. Common choices:- A PHP class — the most typical approach. Instructor derives a JSON schema from the class’s typed properties automatically.
- A JSON schema array — useful when the shape is dynamic or defined at runtime.
- Helper wrappers —
Scalarfor single values,Sequencefor lists of objects, andMaybefor results that may not exist.
Request
A request combines your input with a response model and optional parameters. TheStructuredOutput class provides two equivalent styles for building one.
The compact style passes everything through with():
StructuredOutput is immutable — every method returns
a new instance, so you can safely branch from a shared base.
Runtime
StructuredOutputRuntime owns provider setup and runtime behavior. It holds the LLM
connection, retry policy, output mode, event dispatcher, and pipeline extension points
such as custom validators, transformers, deserializers, and extractors.
You typically create a runtime once and share it across many requests:
StructuredOutput creates one from default settings
automatically.
Execution
Execution is lazy. Callingwith() or the fluent methods only builds a description of
the work. The LLM is not contacted until you read the result.
Three classes participate in execution:
| Class | Role |
|---|---|
StructuredOutput | Builds the request and delegates to the runtime |
PendingStructuredOutput | A lazy handle returned by create(). Execution starts when you call get(), response(), stream(), or any other read method |
StructuredOutputStream | Handles streaming. Yields partial objects as the LLM generates tokens, then provides the final validated result |
Validation and Retries
After the LLM responds, Instructor deserializes the JSON into your response model and runs validation. If validation fails and retries are configured, Instructor sends the validation errors back to the LLM and asks it to correct its response. Validation uses Symfony validation attributes by default:Where To Go Next
- Why Use Instructor? — the motivation behind a schema-first approach
- Usage — the day-to-day API reference
- Data Model — choosing the right response model
- Validation — validation rules and custom validators
- Streaming — working with partial results