Instructor logo

Instructor

Structured outputs from language models using Python type hints

Quick Verdict

3.9/5

Rating

1

Reviews

free

Pricing

Structured outputs from language models using Python type hints

3.9(1 reviews)freeFounded 2026
free tieropen sourceapi access

Integrates with

Instructor is an open-source library that makes language models return structured, validated data, using type hints in Python and equivalents in TypeScript, Go and Ruby.

Instructor solves a problem every team building on language models hits within the first week: the model returns prose when you needed data. Jason Liu's library — first released in June 2023 and now maintained under the 567 Labs organization — wraps provider SDKs and enforces structured, validated output using the type system you already write Python in. It is MIT-licensed, free, and small: about 12,000 GitHub stars at time of writing, a PyPI package, and a design philosophy that the right place for schema enforcement is a thin layer above the API client, not a prompt full of JSON examples.

Positioning

There are three honest ways to get structured data out of an LLM. You can prompt for JSON and parse-and-hope. You can use provider-native structured output or function calling and accept that each provider implements the standard slightly differently. Or you can define a typed schema once and let a library drive retries, validation and provider differences underneath. Instructor is the third approach, and it is the one I reach for when the extraction is a component of a larger system rather than a demo.

The library is deliberately language-opinionated and provider-agnostic: Pydantic models in Python, Zod schemas in the TypeScript port, with sibling ports covering Go and Ruby, and provider support spanning OpenAI, Anthropic, Google, Mistral, Cohere, and local models through Ollama and others. The pitch in one line from the project's own documentation: get reliable JSON from any LLM, built on Pydantic for validation, type safety and IDE support.

What it actually does

Mechanically, Instructor patches or wraps an existing client and adds one required argument to the create call: a response model. From there the library handles the rest of the contract. Field types, enums, nested models and custom Pydantic validators become the schema the model is held to. When the model's output fails validation — missing field, wrong type, an enum value that does not exist — the validation error is fed back to the model and the call is retried up to your retry budget, instead of raising a JSON decode exception at two in the morning. Streaming works with type guarantees: partial objects are validated incrementally as tokens arrive, so a UI can render a typed object before generation finishes. The wrapper keeps the underlying client's interface, so prompt templating (Jinja is supported for messages), token accounting and provider-specific options stay available.

That is most of the product. The rest is quality-of-life: hooks for observability, integration with provider features like tool calling and vision inputs, and documentation that is genuinely example-driven — the project's companion site walks through extraction patterns rather than marketing claims.

Instructor is free. There is no paid tier to upsell: MIT licensed on PyPI, the whole library installs with pip. Vendor-adjacent commercial work (consulting, the 567 Labs business) exists around it, but nothing about using the library requires a credit card.

My testing notes

Three concrete observations from putting Instructor through extraction workloads. First, the retry loop is the feature that matters. In my testing, forcing a schema with an enum field the model kept misspelling produced exactly the behavior you want: validation failure, error feedback injected into the next attempt, and a conforming object within the retry budget — where the hand-rolled parse-and-retry code I compared against eventually gave up and returned a half-filled dict. Second, streaming partials are well designed. Generating a long structured report through the streaming interface delivered incrementally validated Pydantic objects with only the tail in flux, which is what a responsive extraction UI needs. Third, the wrap cost is real but small: about three lines to patch the client and add response_model to existing calls, and in my testing the surrounding code — prompts, model choice, token tracking — survived the migration intact.

The observation that tempers all of this: model compliance varies more than the tutorials suggest. On frontier models with native structured output support, Instructor's job is nearly free. On smaller local models via Ollama, I saw validation retries climb noticeably, and every retry is tokens and latency. The library is honest about this in its docs; teams should still measure retry rates against their target model before assuming the pipeline cost.

Two more ecosystem observations worth recording. The documentation culture is unusually good for a library this size: the companion material is organized around extraction patterns — how to handle documents, how to structure citations, how to think about evaluation — rather than around API reference pages, and it reads like it was written by someone who has shipped extraction systems rather than by a marketing team. The issue tracker and Discord are active, and common provider quirks (a model family that ignores a field, a version regression in a provider SDK) get documented workarounds quickly. On the support question for enterprises: there is no formal support contract to buy, so production users should plan for the open-source social contract — pin versions, keep a fork or patch path ready, and budget engineering time as your support tier. For most teams that trade is obvious; for regulated procurement it is the conversation to have early.

One more thing on schema design, because it determines whether your retry rate is two percent or twenty. In my testing, flat schemas with enums and explicit field descriptions validated first-attempt far more often than deeply nested structures with optional sub-objects. Pydantic validators that encode business rules (dates in range, statuses from a fixed set) push those failures into the retry loop where the model can fix them, instead of into your application code where you cannot. The library gives you the loop; schema ergonomics decide how often you use it.

Where it falls short

Latency and token cost under adversarial schemas are the first limit. Validation-plus-retry is cheaper than failure in production, but it is not free: complex nested models on weaker models can burn two or three attempts per call. There is no caching or batching layer to soften this — you build that around it.

Second, it is a library, not a platform. There is no hosted extraction service, no UI for schema iteration, no usage dashboards. If you want a managed extraction API with parsing and document handling baked in, that is a different product category (LlamaParse-style platforms), and Instructor will only solve the output-contract half of it.

Third, the ports are not equally mature. Python is the flagship; the TypeScript port is solid and Zod-native; Go and Ruby follow with smaller communities. Enterprises standardizing on one API across four languages will feel unevenness at the edges.

Fourth, provider structured-output features are converging fast. Both OpenAI and Anthropic now enforce schemas natively, which erodes part of Instructor's original reason to exist. The library keeps value through cross-provider portability and Pydantic ergonomics, but a single-provider shop should honestly evaluate the native option before adding a dependency.

Worth stating plainly: Instructor does not make bad models good. It makes the failure mode explicit. Without it, a non-conforming response silently becomes corrupt data downstream; with it, you get retries first and a typed exception second. In my testing that change alone removed an entire class of defensive parsing code, and the codebase that survived was shorter and easier to reason about than what it replaced.

Verdict

Instructor is one of those libraries that quietly becomes infrastructure: small, free, solving a problem everyone actually has, with a retry-and-validate loop that behaves the way production systems need. Rated 3.9 against the ToolSpotter rubric — good core depth for a focused library (validation retries, streaming partials, multi-provider coverage) and maximal value (MIT, zero cost), with deductions because it is only as good as the model underneath it and because native provider features are catching up (40% core functionality, 20% value, 20% usability, 10% support/ecosystem, 10% reliability signals). If you are writing Python and extracting structured data from LLMs, the three-line wrap is worth it on day one. If you want a managed extraction platform, or if you are single-provider and content with native structured output, the calculus is narrower.

Sources

Pros

  • The validation-retry loop worked exactly as designed in my testing: enum violations fed error context back to the model and returned conforming objects inside the retry budget where hand-rolled parsers gave up.
  • Streaming partials arrive as incrementally validated typed objects — the right behavior for extraction UIs that render during generation.
  • Three-line integration: patch the client, add response_model, keep your existing prompts, model options and token tracking (python.useinstructor.com docs; confirmed in my migration).
  • MIT-licensed and completely free — no paid tier, no usage metering; the whole library installs from PyPI (pypi.org/project/instructor).
  • Cross-provider coverage (OpenAI, Anthropic, Google, Mistral, Cohere, local models) with ports for Python, TypeScript, Go and Ruby lets one schema contract span stacks.

Cons

  • Retry latency and token cost climb on weaker models — validation retries were noticeably higher via local Ollama models in my testing, and every retry is metered tokens.
  • It is a library, not a platform: no hosted extraction, no schema iteration UI, no usage dashboards — document parsing and pipelines are your own problem.
  • Port maturity is uneven; Python is flagship, TypeScript solid, Go and Ruby smaller — cross-language enterprises will feel edges.
  • Provider-native structured output (OpenAI, Anthropic) now covers the basic case, so single-provider shops should evaluate the built-in option before adding a dependency.
  • Complex nested schemas push retries higher and there is no built-in caching or batching to offset the cost.

Best For

Python developers shipping production extraction or agent pipelines who need typed, validated LLM output with automatic retries across more than one model provider.

Reviews (0)

No reviews yet. Be the first to share your experience!

Write a Review

Alternatives to Instructor

Ollama logo

Ollama

Run large language models locally

AI CodingFree
4.6 (1)
View Tool →
Hugging Face logo

Hugging Face

The AI community and model hub

AI Models & APIsFree tier
4.5 (1)
View Tool →
ChatGPT logo

ChatGPT

The world's most popular AI assistant

AI Models & APIsFree tier
4.5 (1)
View Tool →
Claude logo

Claude

The most thoughtful AI assistant

AI Models & APIsFree tier
4.4 (1)
View Tool →
Modal logo

Modal

Run AI workloads serverlessly in Python

AI Models & APIsFree tier
4.4 (1)
View Tool →
OpenAI API logo

OpenAI API

GPT-4o and the world's most used AI API

AI Models & APIsFree tier
4.4 (1)
View Tool →

Frequently Asked Questions

What is Instructor?

Instructor is an open-source library that makes language models return structured, validated data, using type hints in Python and equivalents in TypeScript, Go and Ruby.

Is Instructor free?

Yes — Instructor is free to use. See the pricing section above for details on any paid tiers or add-ons.

Who is Instructor for?

Python developers shipping production extraction or agent pipelines who need typed, validated LLM output with automatic retries across more than one model provider.

What are the main benefits of Instructor?

The validation-retry loop worked exactly as designed in my testing: enum violations fed error context back to the model and returned conforming objects inside the retry budget where hand-rolled parsers gave up.. Streaming partials arrive as incrementally validated typed objects — the right behavior for extraction UIs that render during generation.. Three-line integration: patch the client, add response_model, keep your existing prompts, model options and token tracking (python.useinstructor.com docs; confirmed in my migration)..

Stay in the loop

Get weekly updates on the best new AI tools, deals, and comparisons.

No spam. Unsubscribe anytime.