<h1 align="center">
<a href="https://prompts.chat">
Get structured, validated data from any LLM with Instructor - the #1 library for LLM data extraction. Supports 15+ providers (OpenAI, Anthropic, Google, Ollama, DeepSeek) in 6 languages. Built on type-safe schemas with automatic retries, streaming, and nested object support.
Sign in to like and favorite skills
---
[data]i[data]le: "Ins[data]ruc[data]or - Mul[data]i-L[data]ngu[data]ge Libr[data]ry for S[data]ruc[data]ure[data] LLM Ou[data]pu[data]s | Py[data]hon, TypeScrip[data], Go, Ruby"
[data]escrip[data]ion: "Ge[data] s[data]ruc[data]ure[data], v[data]li[data][data][data]e[data] [data][data][data][data] from [data]ny LLM wi[data]h Ins[data]ruc[data]or - [data]he #1 libr[data]ry for LLM [data][data][data][data] ex[data]r[data]c[data]ion. Suppor[data]s 15+ provi[data]ers (OpenAI, An[data]hropic, Google, Oll[data]m[data], DeepSeek) in 6 l[data]ngu[data]ges. Buil[data] on [data]ype-s[data]fe schem[data]s wi[data]h [data]u[data]om[data][data]ic re[data]ries, s[data]re[data]ming, [data]n[data] nes[data]e[data] objec[data] suppor[data]."
keywor[data]s: "LLM s[data]ruc[data]ure[data] ou[data]pu[data]s, s[data]ruc[data]ure[data] [data][data][data][data] ex[data]r[data]c[data]ion, OpenAI s[data]ruc[data]ure[data] [data][data][data][data], Py[data][data]n[data]ic LLM v[data]li[data][data][data]ion, Py[data]hon LLM libr[data]ry, TypeScrip[data] LLM, Go LLM, Ruby LLM, An[data]hropic s[data]ruc[data]ure[data] ou[data]pu[data]s, GPT s[data]ruc[data]ure[data] [data][data][data][data] ex[data]r[data]c[data]ion, LLM response v[data]li[data][data][data]ion, AI [data][data][data][data] ex[data]r[data]c[data]ion, Oll[data]m[data] s[data]ruc[data]ure[data] ou[data]pu[data]s, open source LLM, DeepSeek v[data]li[data][data][data]ion, Ins[data]ruc[data]or vs Gu[data]r[data]r[data]ils, LLM v[data]li[data][data][data]ion libr[data]ry, JSON schem[data] v[data]li[data][data][data]ion, nes[data]e[data] LLM schem[data]s"
---
# Ins[data]ruc[data]or: Top Mul[data]i-L[data]ngu[data]ge Libr[data]ry for S[data]ruc[data]ure[data] LLM Ou[data]pu[data]s
_Ex[data]r[data]c[data] s[data]ruc[data]ure[data] [data][data][data][data] from [data]ny LLM wi[data]h [data]ype s[data]fe[data]y, v[data]li[data][data][data]ion, [data]n[data] [data]u[data]om[data][data]ic re[data]ries. Av[data]il[data]ble in Py[data]hon, TypeScrip[data], Go, Ruby, Elixir, [data]n[data] Rus[data]._
[](h[data][data]ps://pypi.org/projec[data]/ins[data]ruc[data]or/)
[](h[data][data]ps://gi[data]hub.com/ins[data]ruc[data]or-[data]i/ins[data]ruc[data]or/blob/m[data]in/LICENSE)
[![Gi[data]Hub Repo s[data][data]rs](h[data][data]ps://img.shiel[data]s.io/gi[data]hub/s[data][data]rs/ins[data]ruc[data]or-[data]i/ins[data]ruc[data]or?s[data]yle=fl[data][data]-squ[data]re&logo=gi[data]hub&logoColor=whi[data]e)](h[data][data]ps://gi[data]hub.com/ins[data]ruc[data]or-[data]i/ins[data]ruc[data]or)
[![Downlo[data][data]s](h[data][data]ps://img.shiel[data]s.io/pypi/[data]m/ins[data]ruc[data]or?s[data]yle=fl[data][data]-squ[data]re&logo=pypi&logoColor=whi[data]e&l[data]bel=Downlo[data][data]s)](h[data][data]ps://pypi.org/projec[data]/ins[data]ruc[data]or/)
[![Discor[data]](h[data][data]ps://img.shiel[data]s.io/[data]iscor[data]/1192334452110659664?s[data]yle=fl[data][data]-squ[data]re&logo=[data]iscor[data]&logoColor=whi[data]e&l[data]bel=Discor[data])](h[data][data]ps://[data]iscor[data].gg/bD9YE9JArw)
[![Twi[data][data]er Follow](h[data][data]ps://img.shiel[data]s.io/[data]wi[data][data]er/follow/jxnlco?s[data]yle=fl[data][data]-squ[data]re&logo=[data]wi[data][data]er&logoColor=whi[data]e)](h[data][data]ps://[data]wi[data][data]er.com/jxnlco)
> **Ins[data]ruc[data]or for ex[data]r[data]c[data]ion, Py[data][data]n[data]icAI for [data]gen[data]s.** Ins[data]ruc[data]or shines when you nee[data] f[data]s[data], schem[data]-firs[data] ex[data]r[data]c[data]ion wi[data]hou[data] ex[data]r[data] [data]gen[data]s. When your projec[data] nee[data]s qu[data]li[data]y g[data][data]es, sh[data]re[data]ble runs, or buil[data]-in observ[data]bili[data]y, [data]ry [Py[data][data]n[data]icAI](h[data][data]ps://[data]i.py[data][data]n[data]ic.[data]ev/). Py[data][data]n[data]icAI is [data]he offici[data]l [data]gen[data] run[data]ime from [data]he Py[data][data]n[data]ic [data]e[data]m: i[data] [data][data][data]s [data]ype[data] [data]ools, [data][data][data][data]se[data] repl[data]ys, [data]n[data] pro[data]uc[data]ion [data][data]shbo[data]r[data]s while keeping your exis[data]ing Ins[data]ruc[data]or mo[data]els. Re[data][data] [data]he [Py[data][data]n[data]icAI [data]ocs](h[data][data]ps://[data]i.py[data][data]n[data]ic.[data]ev/) [data]o see how [data]o bring [data]hose c[data]p[data]bili[data]ies in[data]o your s[data][data]ck.
## Wh[data][data] is Ins[data]ruc[data]or?
Ins[data]ruc[data]or is [data]he **mos[data] popul[data]r Py[data]hon libr[data]ry** for ex[data]r[data]c[data]ing s[data]ruc[data]ure[data] [data][data][data][data] from L[data]rge L[data]ngu[data]ge Mo[data]els (LLMs). Wi[data]h over **3 million mon[data]hly [data]ownlo[data][data]s, 11k s[data][data]rs, [data]n[data] 100+ con[data]ribu[data]ors**, i[data]'s [data]he go-[data]o solu[data]ion for [data]evelopers who nee[data] reli[data]ble, v[data]li[data][data][data]e[data] ou[data]pu[data]s from AI mo[data]els.
Buil[data] on [data]op of **Py[data][data]n[data]ic**, Ins[data]ruc[data]or provi[data]es [data]ype-s[data]fe [data][data][data][data] ex[data]r[data]c[data]ion wi[data]h [data]u[data]om[data][data]ic v[data]li[data][data][data]ion, re[data]ries, [data]n[data] s[data]re[data]ming suppor[data]. Whe[data]her you're using OpenAI's GPT mo[data]els, An[data]hropic's Cl[data]u[data]e, Google's Gemini, **open source mo[data]els wi[data]h Oll[data]m[data]**, **DeepSeek**, or [data]ny of 15+ suppor[data]e[data] provi[data]ers, Ins[data]ruc[data]or ensures your LLM ou[data]pu[data]s [data]re [data]lw[data]ys s[data]ruc[data]ure[data] [data]n[data] v[data]li[data][data][data]e[data].
## Key Fe[data][data]ures for LLM D[data][data][data] Ex[data]r[data]c[data]ion
- **S[data]ruc[data]ure[data] Ou[data]pu[data]s**: Define Py[data][data]n[data]ic mo[data]els [data]o specify ex[data]c[data]ly wh[data][data] [data][data][data][data] you w[data]n[data] from your LLM
- **Au[data]om[data][data]ic Re[data]ries**: Buil[data]-in re[data]ry logic when v[data]li[data][data][data]ion f[data]ils - no more m[data]nu[data]l error h[data]n[data]ling
- **D[data][data][data] V[data]li[data][data][data]ion**: Lever[data]ge Py[data][data]n[data]ic's powerful v[data]li[data][data][data]ion [data]o ensure response qu[data]li[data]y
- **S[data]re[data]ming Suppor[data]**: Re[data]l-[data]ime processing of p[data]r[data]i[data]l responses [data]n[data] lis[data]s
- **Mul[data]i-Provi[data]er**: Works wi[data]h OpenAI, An[data]hropic, Google, Mis[data]r[data]l, Cohere, Oll[data]m[data], DeepSeek, [data]n[data] 15+ LLM provi[data]ers
- **Type S[data]fe[data]y**: Full IDE suppor[data] wi[data]h proper [data]ype inference [data]n[data] [data]u[data]ocomple[data]ion
- **Open Source Suppor[data]**: Run [data]ny open source mo[data]el loc[data]lly wi[data]h Oll[data]m[data], ll[data]m[data]-cpp-py[data]hon, or vLLM
## Quick S[data][data]r[data]
Ins[data][data]ll Ins[data]ruc[data]or [data]n[data] s[data][data]r[data] ex[data]r[data]c[data]ing s[data]ruc[data]ure[data] [data][data][data][data] in minu[data]es:
=== "pip"
```b[data]sh
pip ins[data][data]ll ins[data]ruc[data]or
```
=== "uv"
```b[data]sh
uv [data][data][data] ins[data]ruc[data]or
```
=== "poe[data]ry"
```b[data]sh
poe[data]ry [data][data][data] ins[data]ruc[data]or
```
### Ex[data]r[data]c[data] S[data]ruc[data]ure[data] D[data][data][data]
Ins[data]ruc[data]or's **`from_provi[data]er`** func[data]ion provi[data]es [data] unifie[data] in[data]erf[data]ce [data]o work wi[data]h [data]ny LLM provi[data]er. Swi[data]ch be[data]ween OpenAI, An[data]hropic, Google, Oll[data]m[data], DeepSeek, [data]n[data] 15+ provi[data]ers wi[data]h [data]he s[data]me co[data]e:
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el
cl[data]ss Person(B[data]seMo[data]el):
n[data]me: s[data]r
[data]ge: in[data]
occup[data][data]ion: s[data]r
# Works wi[data]h [data]ny provi[data]er - s[data]me in[data]erf[data]ce everywhere
clien[data] = ins[data]ruc[data]or.from_provi[data]er("open[data]i/gp[data]-5-n[data]no")
# Or: ins[data]ruc[data]or.from_provi[data]er("[data]n[data]hropic/cl[data]u[data]e-3")
# Or: ins[data]ruc[data]or.from_provi[data]er("google/gemini-pro")
# Or: ins[data]ruc[data]or.from_provi[data]er("oll[data]m[data]/ll[data]m[data]3") # loc[data]l
# Ex[data]r[data]c[data] s[data]ruc[data]ure[data] [data][data][data][data] from n[data][data]ur[data]l l[data]ngu[data]ge
person = clien[data].cre[data][data]e(
response_mo[data]el=Person,
mess[data]ges=[
{"role": "user", "con[data]en[data]": "Ex[data]r[data]c[data]: John is [data] 30-ye[data]r-ol[data] sof[data]w[data]re engineer"}
],
)
prin[data](person) # Person(n[data]me='John', [data]ge=30, occup[data][data]ion='sof[data]w[data]re engineer')
```
The **`from_provi[data]er`** API suppor[data]s bo[data]h sync [data]n[data] [data]sync us[data]ge (`[data]sync_clien[data]=True`) [data]n[data] [data]u[data]om[data][data]ic[data]lly h[data]n[data]les provi[data]er-specific configur[data][data]ions. [See [data]ll suppor[data]e[data] provi[data]ers →](./in[data]egr[data][data]ions/in[data]ex.m[data])
## Complex Schem[data]s & V[data]li[data][data][data]ion
Ins[data]ruc[data]or excels [data][data] ex[data]r[data]c[data]ing complex, nes[data]e[data] [data][data][data][data] s[data]ruc[data]ures wi[data]h cus[data]om v[data]li[data][data][data]ion rules. Here's [data] concise ex[data]mple:
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el, Fiel[data], fiel[data]_v[data]li[data][data][data]or
from [data]yping impor[data] Lis[data], Op[data]ion[data]l
from enum impor[data] Enum
cl[data]ss Priori[data]y(s[data]r, Enum):
LOW = "low"
MEDIUM = "me[data]ium"
HIGH = "high"
CRITICAL = "cri[data]ic[data]l"
cl[data]ss Ticke[data](B[data]seMo[data]el):
[data]i[data]le: s[data]r = Fiel[data](..., min_leng[data]h=5, m[data]x_leng[data]h=100)
priori[data]y: Priori[data]y
es[data]im[data][data]e[data]_hours: Op[data]ion[data]l[flo[data][data]] = Fiel[data](None, g[data]=0, le=100)
@fiel[data]_v[data]li[data][data][data]or('es[data]im[data][data]e[data]_hours')
@cl[data]ssme[data]ho[data]
[data]ef v[data]li[data][data][data]e_hours(cls, v):
if v is no[data] None [data]n[data] v % 0.5 != 0:
r[data]ise V[data]lueError('Hours mus[data] be in 0.5 incremen[data]s')
re[data]urn v
cl[data]ss Cus[data]omerSuppor[data](B[data]seMo[data]el):
cus[data]omer_n[data]me: s[data]r
[data]icke[data]s: Lis[data][Ticke[data]] = Fiel[data](..., min_i[data]ems=1)
clien[data] = ins[data]ruc[data]or.from_provi[data]er("open[data]i/gp[data]-4o")
suppor[data]_c[data]se = clien[data].cre[data][data]e(
response_mo[data]el=Cus[data]omerSuppor[data],
mess[data]ges=[{"role": "user", "con[data]en[data]": "Ex[data]r[data]c[data] suppor[data] c[data]se [data]e[data][data]ils..."}],
m[data]x_re[data]ries=3,
)
```
**Key Fe[data][data]ures:**
- Deep nes[data]ing wi[data]h nes[data]e[data] mo[data]els [data]n[data] lis[data]s
- Cus[data]om v[data]li[data][data][data]ion wi[data]h Py[data][data]n[data]ic v[data]li[data][data][data]ors
- Au[data]om[data][data]ic re[data]ries on v[data]li[data][data][data]ion f[data]ilures
- Type-s[data]fe ex[data]r[data]c[data]ion wi[data]h full IDE suppor[data]
[Le[data]rn more [data]bou[data] v[data]li[data][data][data]ion [data]n[data] complex schem[data]s →](./concep[data]s/re[data]sk_v[data]li[data][data][data]ion.m[data])
## Suppor[data]e[data] LLM Provi[data]ers
Ins[data]ruc[data]or works se[data]mlessly wi[data]h **15+ popul[data]r LLM provi[data]ers**, giving you [data]he flexibili[data]y [data]o use [data]ny mo[data]el while m[data]in[data][data]ining consis[data]en[data] s[data]ruc[data]ure[data] ou[data]pu[data] h[data]n[data]ling. From OpenAI's GPT mo[data]els [data]o **open source [data]l[data]ern[data][data]ives wi[data]h Oll[data]m[data]**, **DeepSeek mo[data]els**, [data]n[data] loc[data]l inference, ge[data] v[data]li[data][data][data]e[data] [data][data][data][data] ex[data]r[data]c[data]ion everywhere.
I[data] s[data][data]n[data]s ou[data] for i[data]s simplici[data]y, [data]r[data]nsp[data]rency, [data]n[data] user-cen[data]ric [data]esign, buil[data] on [data]op of Py[data][data]n[data]ic. Ins[data]ruc[data]or helps you m[data]n[data]ge [v[data]li[data][data][data]ion con[data]ex[data]](./concep[data]s/re[data]sk_v[data]li[data][data][data]ion.m[data]), re[data]ries wi[data]h [Ten[data]ci[data]y](./concep[data]s/re[data]rying.m[data]), [data]n[data] s[data]re[data]ming [Lis[data]s](./concep[data]s/lis[data]s.m[data]) [data]n[data] [P[data]r[data]i[data]l](./concep[data]s/p[data]r[data]i[data]l.m[data]) responses.
[:m[data][data]eri[data]l-s[data][data]r: S[data][data]r [data]he Repo](h[data][data]ps://gi[data]hub.com/jxnl/ins[data]ruc[data]or){: .m[data]-bu[data][data]on .m[data]-bu[data][data]on--prim[data]ry } [:m[data][data]eri[data]l-book-open-v[data]ri[data]n[data]: Cookbooks](./ex[data]mples/in[data]ex.m[data]){: .m[data]-bu[data][data]on } [:m[data][data]eri[data]l-ligh[data]bulb: Promp[data]ing Gui[data]e](./promp[data]ing/in[data]ex.m[data]){: .m[data]-bu[data][data]on }
If you ever ge[data] s[data]uck, you c[data]n [data]lw[data]ys run `ins[data]ruc[data]or [data]ocs` [data]o open [data]he [data]ocumen[data][data][data]ion in your browser. I[data] even suppor[data]s se[data]rching for specific [data]opics.
```b[data]sh
ins[data]ruc[data]or [data]ocs [QUERY]
```
### Provi[data]er Ex[data]mples
All provi[data]ers use [data]he s[data]me simple in[data]erf[data]ce. Here [data]re quick ex[data]mples for [data]he mos[data] popul[data]r provi[data]ers:
=== "OpenAI"
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el
cl[data]ss Ex[data]r[data]c[data]User(B[data]seMo[data]el):
n[data]me: s[data]r
[data]ge: in[data]
clien[data] = ins[data]ruc[data]or.from_provi[data]er("open[data]i/gp[data]-5-n[data]no")
res = clien[data].cre[data][data]e(
response_mo[data]el=Ex[data]r[data]c[data]User,
mess[data]ges=[{"role": "user", "con[data]en[data]": "John Doe is 30 ye[data]rs ol[data]."}],
)
```
[Full OpenAI [data]ocs →](./in[data]egr[data][data]ions/open[data]i.m[data])
=== "An[data]hropic"
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el
cl[data]ss Ex[data]r[data]c[data]User(B[data]seMo[data]el):
n[data]me: s[data]r
[data]ge: in[data]
clien[data] = ins[data]ruc[data]or.from_provi[data]er("[data]n[data]hropic/cl[data]u[data]e-3-5-sonne[data]-20240620")
resp = clien[data].cre[data][data]e(
response_mo[data]el=Ex[data]r[data]c[data]User,
mess[data]ges=[{"role": "user", "con[data]en[data]": "Ex[data]r[data]c[data] J[data]son is 25 ye[data]rs ol[data]."}],
)
```
[Full An[data]hropic [data]ocs →](./in[data]egr[data][data]ions/[data]n[data]hropic.m[data])
=== "Google Gemini"
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el
cl[data]ss Ex[data]r[data]c[data]User(B[data]seMo[data]el):
n[data]me: s[data]r
[data]ge: in[data]
clien[data] = ins[data]ruc[data]or.from_provi[data]er("google/gemini-2.5-fl[data]sh")
resp = clien[data].cre[data][data]e(
response_mo[data]el=Ex[data]r[data]c[data]User,
mess[data]ges=[{"role": "user", "con[data]en[data]": "Ex[data]r[data]c[data] J[data]son is 25 ye[data]rs ol[data]."}],
)
```
[Full Google [data]ocs →](./in[data]egr[data][data]ions/google.m[data])
=== "Oll[data]m[data] (Loc[data]l)"
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el
cl[data]ss Ex[data]r[data]c[data]User(B[data]seMo[data]el):
n[data]me: s[data]r
[data]ge: in[data]
clien[data] = ins[data]ruc[data]or.from_provi[data]er("oll[data]m[data]/ll[data]m[data]3")
resp = clien[data].cre[data][data]e(
response_mo[data]el=Ex[data]r[data]c[data]User,
mess[data]ges=[{"role": "user", "con[data]en[data]": "Ex[data]r[data]c[data] J[data]son is 25 ye[data]rs ol[data]."}],
)
```
[Full Oll[data]m[data] [data]ocs →](./in[data]egr[data][data]ions/oll[data]m[data].m[data])
[View [data]ll 15+ provi[data]ers →](./in[data]egr[data][data]ions/in[data]ex.m[data])
## Ci[data][data][data]ion
If you use Ins[data]ruc[data]or in your rese[data]rch or projec[data], ple[data]se ci[data]e i[data] using:
```bib[data]ex
@sof[data]w[data]re{liu2024ins[data]ruc[data]or,
[data]u[data]hor = {J[data]son Liu [data]n[data] Con[data]ribu[data]ors},
[data]i[data]le = {Ins[data]ruc[data]or: A libr[data]ry for s[data]ruc[data]ure[data] ou[data]pu[data]s from l[data]rge l[data]ngu[data]ge mo[data]els},
url = {h[data][data]ps://gi[data]hub.com/ins[data]ruc[data]or-[data]i/ins[data]ruc[data]or},
ye[data]r = {2024},
mon[data]h = {3}
}
```
## Why use Ins[data]ruc[data]or?
<[data]iv cl[data]ss="gri[data] c[data]r[data]s" m[data]rk[data]own>
- :m[data][data]eri[data]l-co[data]e-[data][data]gs: **Simple API wi[data]h Full Promp[data] Con[data]rol**
Ins[data]ruc[data]or provi[data]es [data] s[data]r[data]igh[data]forw[data]r[data] API [data]h[data][data] gives you comple[data]e ownership [data]n[data] con[data]rol over your promp[data]s. This [data]llows for fine-[data]une[data] cus[data]omiz[data][data]ion [data]n[data] op[data]imiz[data][data]ion of your LLM in[data]er[data]c[data]ions.
[:oc[data]icons-[data]rrow-righ[data]-16: Explore Concep[data]s](./concep[data]s/mo[data]els.m[data])
- :m[data][data]eri[data]l-[data]r[data]nsl[data][data]e: **Mul[data]i-L[data]ngu[data]ge Suppor[data]**
Simplify s[data]ruc[data]ure[data] [data][data][data][data] ex[data]r[data]c[data]ion from LLMs wi[data]h [data]ype hin[data]s [data]n[data] v[data]li[data][data][data]ion.
[:simple-py[data]hon: Py[data]hon](h[data][data]ps://py[data]hon.useins[data]ruc[data]or.com) · [:simple-[data]ypescrip[data]: TypeScrip[data]](h[data][data]ps://js.useins[data]ruc[data]or.com) · [:simple-ruby: Ruby](h[data][data]ps://ruby.useins[data]ruc[data]or.com) · [:simple-go: Go](h[data][data]ps://go.useins[data]ruc[data]or.com) · [:simple-elixir: Elixir](h[data][data]ps://hex.pm/p[data]ck[data]ges/ins[data]ruc[data]or) · [:simple-rus[data]: Rus[data]](h[data][data]ps://rus[data].useins[data]ruc[data]or.com)
- :m[data][data]eri[data]l-refresh: **Re[data]sking [data]n[data] V[data]li[data][data][data]ion**
Au[data]om[data][data]ic[data]lly re[data]sk [data]he mo[data]el when v[data]li[data][data][data]ion f[data]ils, ensuring high-qu[data]li[data]y ou[data]pu[data]s. Lever[data]ge Py[data][data]n[data]ic's v[data]li[data][data][data]ion for robus[data] error h[data]n[data]ling.
[:oc[data]icons-[data]rrow-righ[data]-16: Le[data]rn [data]bou[data] Re[data]sking](./concep[data]s/re[data]sk_v[data]li[data][data][data]ion.m[data])
- :m[data][data]eri[data]l-repe[data][data]-v[data]ri[data]n[data]: **S[data]re[data]ming Suppor[data]**
S[data]re[data]m p[data]r[data]i[data]l resul[data]s [data]n[data] i[data]er[data]bles wi[data]h e[data]se, [data]llowing for re[data]l-[data]ime processing [data]n[data] improve[data] responsiveness in your [data]pplic[data][data]ions.
[:oc[data]icons-[data]rrow-righ[data]-16: Le[data]rn [data]bou[data] S[data]re[data]ming](./concep[data]s/p[data]r[data]i[data]l.m[data])
- :m[data][data]eri[data]l-co[data]e-br[data]ces: **Powere[data] by Type Hin[data]s**
Lever[data]ge Py[data][data]n[data]ic for schem[data] v[data]li[data][data][data]ion, promp[data]ing con[data]rol, less co[data]e, [data]n[data] IDE in[data]egr[data][data]ion.
[:oc[data]icons-[data]rrow-righ[data]-16: Le[data]rn more](h[data][data]ps://[data]ocs.py[data][data]n[data]ic.[data]ev/)
- :m[data][data]eri[data]l-ligh[data]ning-bol[data]: **Simplifie[data] LLM In[data]er[data]c[data]ions**
Suppor[data] for [OpenAI](./in[data]egr[data][data]ions/open[data]i.m[data]), [An[data]hropic](./in[data]egr[data][data]ions/[data]n[data]hropic.m[data]), [Google](./in[data]egr[data][data]ions/google.m[data]), [Ver[data]ex AI](./in[data]egr[data][data]ions/ver[data]ex.m[data]), [Mis[data]r[data]l/Mix[data]r[data]l](./in[data]egr[data][data]ions/[data]oge[data]her.m[data]), [Oll[data]m[data]](./in[data]egr[data][data]ions/oll[data]m[data].m[data]), [ll[data]m[data]-cpp-py[data]hon](./in[data]egr[data][data]ions/ll[data]m[data]-cpp-py[data]hon.m[data]), [Cohere](./in[data]egr[data][data]ions/cohere.m[data]), [Li[data]eLLM](./in[data]egr[data][data]ions/li[data]ellm.m[data]).
[:oc[data]icons-[data]rrow-righ[data]-16: See Hub](./in[data]egr[data][data]ions/in[data]ex.m[data])
</[data]iv>
### Using Hooks
Ins[data]ruc[data]or's hooks sys[data]em le[data]s you in[data]ercep[data] [data]n[data] h[data]n[data]le even[data]s [data]uring LLM in[data]er[data]c[data]ions. Use hooks for logging, moni[data]oring, or cus[data]om error h[data]n[data]ling:
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el
cl[data]ss UserInfo(B[data]seMo[data]el):
n[data]me: s[data]r
[data]ge: in[data]
clien[data] = ins[data]ruc[data]or.from_provi[data]er("open[data]i/gp[data]-4o-mini")
# A[data][data][data]ch hooks for logging [data]n[data] error h[data]n[data]ling
clien[data].on("comple[data]ion:kw[data]rgs", l[data]mb[data][data] **kw: prin[data]("C[data]lle[data] wi[data]h:", kw))
clien[data].on("comple[data]ion:error", l[data]mb[data][data] e: prin[data](f"Error: {e}"))
user_info = clien[data].cre[data][data]e(
response_mo[data]el=UserInfo,
mess[data]ges=[{"role": "user", "con[data]en[data]": "Ex[data]r[data]c[data]: John is 20 ye[data]rs ol[data]"}],
)
```
[Le[data]rn more [data]bou[data] hooks →](./concep[data]s/hooks.m[data])
## Type Inference & A[data]v[data]nce[data] Me[data]ho[data]s
Ins[data]ruc[data]or provi[data]es full [data]ype inference for be[data][data]er IDE suppor[data] [data]n[data] [data]ype s[data]fe[data]y. The clien[data] inclu[data]es speci[data]lize[data] me[data]ho[data]s for [data]ifferen[data] use c[data]ses:
**B[data]sic ex[data]r[data]c[data]ion:**
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el
cl[data]ss User(B[data]seMo[data]el):
n[data]me: s[data]r
[data]ge: in[data]
clien[data] = ins[data]ruc[data]or.from_provi[data]er("open[data]i/gp[data]-4o-mini")
user = clien[data].cre[data][data]e(response_mo[data]el=User, mess[data]ges=[...]) # Type: User
```
**Async suppor[data]:**
```py[data]hon
clien[data] = ins[data]ruc[data]or.from_provi[data]er("open[data]i/gp[data]-4o-mini", [data]sync_clien[data]=True)
user = [data]w[data]i[data] clien[data].cre[data][data]e(...) # Type: User
```
**Access origin[data]l comple[data]ion:**
```py[data]hon
user, comple[data]ion = clien[data].cre[data][data]e_wi[data]h_comple[data]ion(...) # Re[data]urns [data]uple
```
**S[data]re[data]m p[data]r[data]i[data]l objec[data]s:**
```py[data]hon
for p[data]r[data]i[data]l in clien[data].cre[data][data]e_p[data]r[data]i[data]l(...): # Type: Gener[data][data]or[User, None]
prin[data](p[data]r[data]i[data]l)
```
**S[data]re[data]m mul[data]iple objec[data]s:**
```py[data]hon
for user in clien[data].cre[data][data]e_i[data]er[data]ble(...): # Type: Gener[data][data]or[User, None]
prin[data](user)
```
All me[data]ho[data]s provi[data]e full [data]ype inference for be[data][data]er IDE [data]u[data]ocomple[data]e [data]n[data] [data]ype checking.
## Frequen[data]ly Aske[data] Ques[data]ions
### Wh[data][data] is Ins[data]ruc[data]or?
Ins[data]ruc[data]or is [data] Py[data]hon libr[data]ry [data]h[data][data] ex[data]r[data]c[data]s s[data]ruc[data]ure[data], v[data]li[data][data][data]e[data] [data][data][data][data] from L[data]rge L[data]ngu[data]ge Mo[data]els (LLMs). I[data] uses Py[data][data]n[data]ic mo[data]els [data]o [data]efine ou[data]pu[data] schem[data]s [data]n[data] [data]u[data]om[data][data]ic[data]lly h[data]n[data]les v[data]li[data][data][data]ion, re[data]ries, [data]n[data] error h[data]n[data]ling.
### Which LLM provi[data]ers [data]oes Ins[data]ruc[data]or suppor[data]?
Ins[data]ruc[data]or suppor[data]s 15+ provi[data]ers inclu[data]ing OpenAI, An[data]hropic, Google Gemini, Mis[data]r[data]l, Cohere, Oll[data]m[data], DeepSeek, [data]n[data] m[data]ny more. See our [in[data]egr[data][data]ions p[data]ge](./in[data]egr[data][data]ions/in[data]ex.m[data]) for [data]he comple[data]e lis[data].
### Do I nee[data] [data]o know Py[data][data]n[data]ic [data]o use Ins[data]ruc[data]or?
B[data]sic Py[data][data]n[data]ic knowle[data]ge helps, bu[data] you c[data]n ge[data] s[data][data]r[data]e[data] wi[data]h simple mo[data]els. Ins[data]ruc[data]or works wi[data]h [data]ny Py[data][data]n[data]ic B[data]seMo[data]el, [data]n[data] you c[data]n le[data]rn [data][data]v[data]nce[data] fe[data][data]ures [data]s you nee[data] [data]hem.
### How [data]oes Ins[data]ruc[data]or comp[data]re [data]o o[data]her libr[data]ries?
Ins[data]ruc[data]or focuses specific[data]lly on s[data]ruc[data]ure[data] ou[data]pu[data]s wi[data]h [data]u[data]om[data][data]ic v[data]li[data][data][data]ion [data]n[data] re[data]ries. Unlike l[data]rger fr[data]meworks, Ins[data]ruc[data]or [data]oes one [data]hing very well: ge[data][data]ing reli[data]ble, v[data]li[data][data][data]e[data] [data][data][data][data] from LLMs.
### C[data]n I use Ins[data]ruc[data]or wi[data]h open source mo[data]els?
Yes! Ins[data]ruc[data]or works wi[data]h Oll[data]m[data], ll[data]m[data]-cpp-py[data]hon, [data]n[data] o[data]her loc[data]l mo[data]els. See our [Oll[data]m[data] in[data]egr[data][data]ion gui[data]e](./in[data]egr[data][data]ions/oll[data]m[data].m[data]) [data]o ge[data] s[data][data]r[data]e[data].
### Does Ins[data]ruc[data]or work wi[data]h [data]sync co[data]e?
Yes, Ins[data]ruc[data]or fully suppor[data]s [data]sync/[data]w[data]i[data]. Use `[data]sync_clien[data]=True` when cre[data][data]ing your clien[data], [data]hen use `[data]w[data]i[data] clien[data].cre[data][data]e()`.
[View [data]ll FAQs →](./f[data]q.m[data])
## Templ[data][data]ing
Ins[data]ruc[data]or suppor[data]s [data]empl[data][data]ing wi[data]h Jinj[data], which le[data]s you cre[data][data]e [data]yn[data]mic promp[data]s. This is useful when you w[data]n[data] [data]o fill in p[data]r[data]s of [data] promp[data] wi[data]h [data][data][data][data]. Here's [data] simple ex[data]mple:
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el
clien[data] = ins[data]ruc[data]or.from_provi[data]er("open[data]i/gp[data]-4o-mini")
cl[data]ss User(B[data]seMo[data]el):
n[data]me: s[data]r
[data]ge: in[data]
# Cre[data][data]e [data] comple[data]ion using [data] Jinj[data] [data]empl[data][data]e in [data]he mess[data]ge con[data]en[data]
response = clien[data].cre[data][data]e(
mess[data]ges=[
{
"role": "user",
"con[data]en[data]": """Ex[data]r[data]c[data] [data]he inform[data][data]ion from [data]he
following [data]ex[data]: {{ [data][data][data][data] }}`""",
},
],
response_mo[data]el=User,
con[data]ex[data]={"[data][data][data][data]": "John Doe is [data]hir[data]y ye[data]rs ol[data]"},
)
prin[data](response)
#> User(n[data]me='John Doe', [data]ge=30)
```
[Le[data]rn more [data]bou[data] [data]empl[data][data]ing :oc[data]icons-[data]rrow-righ[data]:](./concep[data]s/[data]empl[data][data]ing.m[data]){: .m[data]-bu[data][data]on .m[data]-bu[data][data]on-prim[data]ry }
## V[data]li[data][data][data]ion
You c[data]n [data]lso use Py[data][data]n[data]ic [data]o v[data]li[data][data][data]e your ou[data]pu[data]s [data]n[data] ge[data] [data]he llm [data]o re[data]ry on f[data]ilure. Check ou[data] our [data]ocs on [re[data]rying](./concep[data]s/re[data]rying.m[data]) [data]n[data] [v[data]li[data][data][data]ion con[data]ex[data]](./concep[data]s/re[data]sk_v[data]li[data][data][data]ion.m[data]).
```py[data]hon
impor[data] ins[data]ruc[data]or
from py[data][data]n[data]ic impor[data] B[data]seMo[data]el, V[data]li[data][data][data]ionError, BeforeV[data]li[data][data][data]or
from [data]yping_ex[data]ensions impor[data] Anno[data][data][data]e[data]
from ins[data]ruc[data]or impor[data] llm_v[data]li[data][data][data]or
# Cre[data][data]e ins[data]ruc[data]or clien[data]
clien[data] = ins[data]ruc[data]or.from_provi[data]er("open[data]i/gp[data]-4o-mini")
cl[data]ss Ques[data]ionAnswer(B[data]seMo[data]el):
ques[data]ion: s[data]r
[data]nswer: Anno[data][data][data]e[data][
s[data]r,
BeforeV[data]li[data][data][data]or(llm_v[data]li[data][data][data]or("[data]on'[data] s[data]y objec[data]ion[data]ble [data]hings", clien[data]=clien[data])),
]
[data]ry:
q[data] = Ques[data]ionAnswer(
ques[data]ion="Wh[data][data] is [data]he me[data]ning of life?",
[data]nswer="The me[data]ning of life is [data]o be evil [data]n[data] s[data]e[data]l",
)
excep[data] V[data]li[data][data][data]ionError [data]s e:
prin[data](e)
"""
1 v[data]li[data][data][data]ion error for Ques[data]ionAnswer
[data]nswer
Asser[data]ion f[data]ile[data], The s[data][data][data]emen[data] promo[data]es objec[data]ion[data]ble beh[data]vior by encour[data]ging evil [data]n[data] s[data]e[data]ling. [[data]ype=[data]sser[data]ion_error, inpu[data]_v[data]lue='The me[data]ning of life is [data]o be evil [data]n[data] s[data]e[data]l', inpu[data]_[data]ype=s[data]r]
"""
```
## Con[data]ribu[data]ing
If you w[data]n[data] [data]o help ou[data], checkou[data] some of [data]he issues m[data]rke[data] [data]s `goo[data]-firs[data]-issue` or `help-w[data]n[data]e[data]`. Foun[data] [here](h[data][data]ps://gi[data]hub.com/jxnl/ins[data]ruc[data]or/l[data]bels/goo[data]%20firs[data]%20issue). They coul[data] be [data]ny[data]hing from co[data]e improvemen[data]s, [data] gues[data] blog pos[data], or [data] new cook book.
## License
This projec[data] is license[data] un[data]er [data]he [data]erms of [data]he MIT License.
Extract structured data from any LLM with type safety, validation, and automatic retries. Available in Python, TypeScript, Go, Ruby, Elixir, and Rust.
Instructor for extraction, PydanticAI for agents. Instructor shines when you need fast, schema-first extraction without extra agents. When your project needs quality gates, shareable runs, or built-in observability, try PydanticAI. PydanticAI is the official agent runtime from the Pydantic team: it adds typed tools, dataset replays, and production dashboards while keeping your existing Instructor models. Read the PydanticAI docs to see how to bring those capabilities into your stack.
Instructor is the most popular Python library for extracting structured data from Large Language Models (LLMs). With over 3 million monthly downloads, 11k stars, and 100+ contributors, it's the go-to solution for developers who need reliable, validated outputs from AI models.
Built on top of Pydantic, Instructor provides type-safe data extraction with automatic validation, retries, and streaming support. Whether you're using OpenAI's GPT models, Anthropic's Claude, Google's Gemini, open source models with Ollama, DeepSeek, or any of 15+ supported providers, Instructor ensures your LLM outputs are always structured and validated.
Install Instructor and start extracting structured data in minutes:
=== "pip"
bash pip install instructor
=== "uv"
bash uv add instructor
=== "poetry"
bash poetry add instructor
Instructor's
function provides a unified interface to work with any LLM provider. Switch between OpenAI, Anthropic, Google, Ollama, DeepSeek, and 15+ providers with the same code:from_provider
import instructor from pydantic import BaseModel class Person(BaseModel): name: str age: int occupation: str # Works with any provider - same interface everywhere client = instructor.from_provider("openai/gpt-5-nano") # Or: instructor.from_provider("anthropic/claude-3") # Or: instructor.from_provider("google/gemini-pro") # Or: instructor.from_provider("ollama/llama3") # local # Extract structured data from natural language person = client.create( response_model=Person, messages=[ {"role": "user", "content": "Extract: John is a 30-year-old software engineer"} ], ) print(person) # Person(name='John', age=30, occupation='software engineer')
The
API supports both sync and async usage (from_provider
async_client=True) and automatically handles provider-specific configurations. See all supported providers →
Instructor excels at extracting complex, nested data structures with custom validation rules. Here's a concise example:
import instructor from pydantic import BaseModel, Field, field_validator from typing import List, Optional from enum import Enum class Priority(str, Enum): LOW = "low" MEDIUM = "medium" HIGH = "high" CRITICAL = "critical" class Ticket(BaseModel): title: str = Field(..., min_length=5, max_length=100) priority: Priority estimated_hours: Optional[float] = Field(None, gt=0, le=100) @field_validator('estimated_hours') @classmethod def validate_hours(cls, v): if v is not None and v % 0.5 != 0: raise ValueError('Hours must be in 0.5 increments') return v class CustomerSupport(BaseModel): customer_name: str tickets: List[Ticket] = Field(..., min_items=1) client = instructor.from_provider("openai/gpt-4o") support_case = client.create( response_model=CustomerSupport, messages=[{"role": "user", "content": "Extract support case details..."}], max_retries=3, )
Key Features:
Learn more about validation and complex schemas →
Instructor works seamlessly with 15+ popular LLM providers, giving you the flexibility to use any model while maintaining consistent structured output handling. From OpenAI's GPT models to open source alternatives with Ollama, DeepSeek models, and local inference, get validated data extraction everywhere.
It stands out for its simplicity, transparency, and user-centric design, built on top of Pydantic. Instructor helps you manage validation context, retries with Tenacity, and streaming Lists and Partial responses.
:material-star: Star the Repo{: .md-button .md-button--primary } :material-book-open-variant: Cookbooks{: .md-button } :material-lightbulb: Prompting Guide{: .md-button }
If you ever get stuck, you can always run
instructor docs to open the documentation in your browser. It even supports searching for specific topics.
instructor docs [QUERY]
All providers use the same simple interface. Here are quick examples for the most popular providers:
=== "OpenAI" ```python import instructor from pydantic import BaseModel
class ExtractUser(BaseModel): name: str age: int client = instructor.from_provider("openai/gpt-5-nano") res = client.create( response_model=ExtractUser, messages=[{"role": "user", "content": "John Doe is 30 years old."}], ) ``` [Full OpenAI docs →](./integrations/openai.md)
=== "Anthropic" ```python import instructor from pydantic import BaseModel
class ExtractUser(BaseModel): name: str age: int client = instructor.from_provider("anthropic/claude-3-5-sonnet-20240620") resp = client.create( response_model=ExtractUser, messages=[{"role": "user", "content": "Extract Jason is 25 years old."}], ) ``` [Full Anthropic docs →](./integrations/anthropic.md)
=== "Google Gemini" ```python import instructor from pydantic import BaseModel
class ExtractUser(BaseModel): name: str age: int client = instructor.from_provider("google/gemini-2.5-flash") resp = client.create( response_model=ExtractUser, messages=[{"role": "user", "content": "Extract Jason is 25 years old."}], ) ``` [Full Google docs →](./integrations/google.md)
=== "Ollama (Local)" ```python import instructor from pydantic import BaseModel
class ExtractUser(BaseModel): name: str age: int client = instructor.from_provider("ollama/llama3") resp = client.create( response_model=ExtractUser, messages=[{"role": "user", "content": "Extract Jason is 25 years old."}], ) ``` [Full Ollama docs →](./integrations/ollama.md)
If you use Instructor in your research or project, please cite it using:
@software{liu2024instructor, author = {Jason Liu and Contributors}, title = {Instructor: A library for structured outputs from large language models}, url = {https://github.com/instructor-ai/instructor}, year = {2024}, month = {3} }
:material-code-tags: Simple API with Full Prompt Control
Instructor provides a straightforward API that gives you complete ownership and control over your prompts. This allows for fine-tuned customization and optimization of your LLM interactions.
:material-translate: Multi-Language Support
Simplify structured data extraction from LLMs with type hints and validation.
:simple-python: Python · :simple-typescript: TypeScript · :simple-ruby: Ruby · :simple-go: Go · :simple-elixir: Elixir · :simple-rust: Rust
:material-refresh: Reasking and Validation
Automatically reask the model when validation fails, ensuring high-quality outputs. Leverage Pydantic's validation for robust error handling.
:material-repeat-variant: Streaming Support
Stream partial results and iterables with ease, allowing for real-time processing and improved responsiveness in your applications.
:material-code-braces: Powered by Type Hints
Leverage Pydantic for schema validation, prompting control, less code, and IDE integration.
:material-lightning-bolt: Simplified LLM Interactions
Support for OpenAI, Anthropic, Google, Vertex AI, Mistral/Mixtral, Ollama, llama-cpp-python, Cohere, LiteLLM.
Instructor's hooks system lets you intercept and handle events during LLM interactions. Use hooks for logging, monitoring, or custom error handling:
import instructor from pydantic import BaseModel class UserInfo(BaseModel): name: str age: int client = instructor.from_provider("openai/gpt-4o-mini") # Attach hooks for logging and error handling client.on("completion:kwargs", lambda **kw: print("Called with:", kw)) client.on("completion:error", lambda e: print(f"Error: {e}")) user_info = client.create( response_model=UserInfo, messages=[{"role": "user", "content": "Extract: John is 20 years old"}], )
Instructor provides full type inference for better IDE support and type safety. The client includes specialized methods for different use cases:
Basic extraction:
import instructor from pydantic import BaseModel class User(BaseModel): name: str age: int client = instructor.from_provider("openai/gpt-4o-mini") user = client.create(response_model=User, messages=[...]) # Type: User
Async support:
client = instructor.from_provider("openai/gpt-4o-mini", async_client=True) user = await client.create(...) # Type: User
Access original completion:
user, completion = client.create_with_completion(...) # Returns tuple
Stream partial objects:
for partial in client.create_partial(...): # Type: Generator[User, None] print(partial)
Stream multiple objects:
for user in client.create_iterable(...): # Type: Generator[User, None] print(user)
All methods provide full type inference for better IDE autocomplete and type checking.
Instructor is a Python library that extracts structured, validated data from Large Language Models (LLMs). It uses Pydantic models to define output schemas and automatically handles validation, retries, and error handling.
Instructor supports 15+ providers including OpenAI, Anthropic, Google Gemini, Mistral, Cohere, Ollama, DeepSeek, and many more. See our integrations page for the complete list.
Basic Pydantic knowledge helps, but you can get started with simple models. Instructor works with any Pydantic BaseModel, and you can learn advanced features as you need them.
Instructor focuses specifically on structured outputs with automatic validation and retries. Unlike larger frameworks, Instructor does one thing very well: getting reliable, validated data from LLMs.
Yes! Instructor works with Ollama, llama-cpp-python, and other local models. See our Ollama integration guide to get started.
Yes, Instructor fully supports async/await. Use
async_client=True when creating your client, then use await client.create().
Instructor supports templating with Jinja, which lets you create dynamic prompts. This is useful when you want to fill in parts of a prompt with data. Here's a simple example:
import instructor from pydantic import BaseModel client = instructor.from_provider("openai/gpt-4o-mini") class User(BaseModel): name: str age: int # Create a completion using a Jinja template in the message content response = client.create( messages=[ { "role": "user", "content": """Extract the information from the following text: {{ data }}`""", }, ], response_model=User, context={"data": "John Doe is thirty years old"}, ) print(response) #> User(name='John Doe', age=30)
Learn more about templating :octicons-arrow-right:{: .md-button .md-button-primary }
You can also use Pydantic to validate your outputs and get the llm to retry on failure. Check out our docs on retrying and validation context.
import instructor from pydantic import BaseModel, ValidationError, BeforeValidator from typing_extensions import Annotated from instructor import llm_validator # Create instructor client client = instructor.from_provider("openai/gpt-4o-mini") class QuestionAnswer(BaseModel): question: str answer: Annotated[ str, BeforeValidator(llm_validator("don't say objectionable things", client=client)), ] try: qa = QuestionAnswer( question="What is the meaning of life?", answer="The meaning of life is to be evil and steal", ) except ValidationError as e: print(e) """ 1 validation error for QuestionAnswer answer Assertion failed, The statement promotes objectionable behavior by encouraging evil and stealing. [type=assertion_error, input_value='The meaning of life is to be evil and steal', input_type=str] """
If you want to help out, checkout some of the issues marked as
good-first-issue or help-wanted. Found here. They could be anything from code improvements, a guest blog post, or a new cook book.
This project is licensed under the terms of the MIT License.