instructors-0.1.0 has been yanked.
instructors
Type-safe structured output extraction from LLMs. The Rust instructor.
Define a Rust struct → instructors generates the JSON Schema → LLM returns valid JSON → you get a typed value. With automatic retry on parse failure.
Quick Start
use *;
let client = openai;
let result: = client
.extract
.model
.await?;
println!; // "John Doe"
println!; // Some("john@example.com")
println!;
Installation
[]
= "0.1"
Providers
| Provider | Constructor | Mechanism |
|---|---|---|
| OpenAI | Client::openai(key) |
response_format strict JSON Schema |
| Anthropic | Client::anthropic(key) |
tool_use with forced tool choice |
| OpenAI-compatible | Client::openai_compatible(key, url) |
Same as OpenAI (DeepSeek, Together, etc.) |
// OpenAI
let client = openai;
// Anthropic
let client = anthropic;
// DeepSeek, Together, or any OpenAI-compatible API
let client = openai_compatible;
Classification
Enums work naturally for classification tasks:
let sentiment: Sentiment = client
.extract
.await?
.value;
Nested Types
Complex nested structures with vectors, options, and enums:
let paper: Paper = client
.extract
.model
.await?
.value;
Configuration
let result: MyStruct = client
.extract
.model // override model
.system // custom system prompt
.temperature // deterministic output
.max_tokens // limit output tokens
.max_retries // retry on parse failure
.context // append to prompt
.await?
.value;
Client Defaults
Set defaults once, override per-request:
let client = openai
.with_model
.with_temperature
.with_max_retries
.with_system;
// all extractions use the defaults above
let a: TypeA = client.extract.await?.value;
let b: TypeB = client.extract.await?.value;
// override for a specific request
let c: TypeC = client.extract.model.await?.value;
Cost Tracking
Built-in token counting and cost estimation via tiktoken:
let result = client..await?;
println!;
println!;
println!;
println!;
Disable with default-features = false:
[]
= { = "0.1", = false }
How It Works
#[derive(JsonSchema)]generates a JSON Schema from your Rust type (via schemars)- The schema is transformed for the target provider:
- OpenAI: wrapped in
response_formatwith strict mode (additionalProperties: false, all fields required) - Anthropic: wrapped as a
toolwithinput_schema, forced viatool_choice
- OpenAI: wrapped in
- LLM is constrained to produce valid JSON matching the schema
- Response is deserialized with
serde_json::from_str::<T>() - On parse failure, error feedback is sent back and the request is retried