Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when writing structured-output code with the Instructor Python library (from_openai/from_anthropic/from_provider client init, response_model= Pydantic class, max_retries= auto-reask, create_partial/create_iterable streaming): emit the current 1.0 API idiom — the exact calls cheaper models get wrong in the deprecated patch() / manual-JSON form.
.claude/skills/instructor-v1-api/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flashlowest | 63% | 8 |
| gemini-3.1-pro-preview | 100% | 3 |
| Model | Lift | Δ tokens | Δ turns | Cases | Verified |
|---|---|---|---|---|---|
| gemini-3.6-flashbest | +27% | +60% | 0% | 22 | 54d ago |
| gemini-3.5-flash | pending re-run | — | |||
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | — | — |
| case-07 | ✗→✓ | ▲ Improved | — | — |
| case-09 | ✗→✓ | ▲ Improved | — | — |
| case-04 | ✗→✓ | ▲ Improved | — | — |
| case-14 | ✗→✓ | ▲ Improved | — | — |
Enforces the CURRENT (1.0) Instructor public API whenever you write Python that uses the instructor library to get structured, Pydantic-validated output from an LLM. The pre-1.0 idiom (instructor.patch(client), hand-parsed JSON, hand-rolled retries) is deprecated; emit the 1.0 form below. Apply to any request to "use instructor" / "extract structured data with instructor."
from_ factory — never patch(), never a raw client. Useinstructor.from_provider("openai/gpt-4o-mini") (the unified form: "<provider>/<model>"), or a provider factory instructor.from_openai(...) / instructor.from_anthropic(...) around the provider client. The pre-1.0 instructor.patch(client) is deprecated. A raw, unwrapped OpenAI() / Anthropic() client does NOT accept response_model — it must be wrapped first.
response_model=. That keyword carries the class:response_model=User. It is NOT response_format= (that is OpenAI's own JSON-mode flag), NOT output_model=, NOT schema=, NOT pydantic_model=.
pydantic.BaseModel subclass, and the call returns the validated instance. Thecreate call returns an already-parsed, already-validated model object — read fields straight off it (result.name, result.address.city). Do NOT json.loads(response.choices[0].message.content) or index into the raw completion; Instructor has already parsed and validated it for you.
max_retries=, not a hand-written loop. On a PydanticValidationError, Instructor re-sends the error to the model and asks again, up to max_retries times (default 3): response_model=Event, max_retries=3. Never wrap the call in your own for _ in range(3): try/except loop — max_retries= is the built-in mechanism and feeds the validation error back to the model.
create_partial(...). For one object whose fields fill inprogressively, call client.chat.completions.create_partial(...) (or client.messages.create_partial / client.create_partial) and iterate the returned generator — each item is a more-complete instance. Do NOT set stream=True and stitch JSON chunks together yourself.
create_iterable(...). For a sequence of objects delivered one at atime, call create_iterable(...) and iterate it (equivalently, set response_model=Iterable[Item]). Do NOT parse one combined blob and split it by hand.
Client creation (BEFORE = deprecated pre-1.0 → AFTER = 1.0):
python# BEFORE import instructor, openai client = instructor.patch(openai.OpenAI()) # deprecated monkey-patch # AFTER import instructor client = instructor.from_provider("openai/gpt-4o-mini") # or, wrapping an existing client: client = instructor.from_openai(openai.OpenAI())
Extraction + reading fields (BEFORE = raw SDK + manual parse → AFTER = 1.0):
python# BEFORE raw = openai_client.chat.completions.create(model=..., messages=msgs) data = json.loads(raw.choices[0].message.content) # manual, unvalidated name = data["name"] # AFTER obj = client.chat.completions.create(response_model=User, messages=msgs) name = obj.name # already a validated User
Automatic retries (BEFORE = hand-rolled loop → AFTER = 1.0):
python# BEFORE for _ in range(3): try: obj = extract(); break except ValidationError: continue # AFTER obj = client.chat.completions.create(response_model=Event, max_retries=3, messages=msgs)
Streaming a single partial object vs a sequence:
python# one growing object for partial in client.chat.completions.create_partial(response_model=Report, messages=msgs): print(partial.title) # fills in as it streams # many objects, one at a time for item in client.chat.completions.create_iterable(response_model=Task, messages=msgs): handle(item)
instructor.from_openai(OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")). Never patch(); never pass the raw client to a response_model= call.
from_provider string: the argument is "<provider>/<model>", e.g. "anthropic/claude-3-5-sonnet-latest";from_provider dispatches to the right provider factory for you.
response_model: response_model=Iterable[Task] is the equivalent of create_iterable;both stream a sequence — pick one, don't hand-split a combined response.
create_with_completion(...), which returns(parsed_model, raw_completion) — still never json.loads the parsed side.
instructor.from_provider(..., async_client=True) then await client...create(...) /async for the partial/iterable stream.
from_provider(...) / from_openai(...) / from_anthropic(...).DON'T instructor.patch(client) or pass a raw unwrapped client to a response_model= call.
response_model=Model. DON'T use response_format=, output_model=, or schema=.obj.field). DON'T json.loads(response.choices[0].message.content).max_retries=N. DON'T write your own try/except retry loop.create_partial(...). DON'T stream=True + manual chunk assembly.create_iterable(...) / response_model=Iterable[...]. DON'T split a combined blob.instructor.patch(OpenAI()) — deprecated; use a from_ factory.OpenAI() / Anthropic() client and expecting response_model= to work — it must be wrapped.response_format= (OpenAI's JSON flag) instead of Instructor's response_model=.json.loads(response.choices[0].message.content) — the create call already returns a parsed instance.for/try/except retry loop instead of max_retries=.stream=True and assembling JSON by hand instead of create_partial / create_iterable.from_provider / from_openai / from_anthropic — not patch() or a raw client.response_model= (not response_format= / schema=).pydantic.BaseModel; fields read directly off the returned instance (no json.loads).max_retries= — no hand-rolled retry loop.create_partial; sequence with create_iterable / Iterable[...].| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-08 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.5-flash | verified | 7/9/2026 | +38% |
Other measured skills in the registry, with their headline benchmark lift.