Guaranteed structured output from any LLM — with automatic retries and Pydantic validation.
pip install structout-llmLLMs don't always return valid JSON. They add markdown fences, extra text, wrong types, missing fields. Your code breaks. You add manual parsing. It breaks again.
structout-llm fixes this — automatically.
from pydantic import BaseModel
from structout import extract
class Person(BaseModel):
name: str
age: int
city: str
result = extract(
instruction="Extract person details",
schema=Person,
provider="openai",
model="gpt-4o",
api_key="sk-...",
text="John Doe is 28 years old and lives in Mumbai."
)
print(result.data.name) # "John Doe"
print(result.data.age) # 28
print(result.attempts) # 1
print(result.latency_ms) # 1243.5| Provider | Install | Models |
|---|---|---|
| OpenAI | pip install openai |
gpt-4o, gpt-4o-mini, ... |
| Anthropic | pip install anthropic |
claude-sonnet-4, claude-haiku-4 |
| Gemini | pip install google-genai |
gemini-2.5-flash, gemini-1.5-pro |
- ✅ Auto retry — retries with error context when validation fails
- ✅ Pydantic validation — full type safety and field validation
- ✅ JSON extraction — handles markdown fences, extra text, trailing commas
- ✅ Safe mode —
extract_safe()never raises, returns error in result - ✅ Metrics — tokens, latency, attempts tracked per call
- ✅ Provider agnostic — same API for OpenAI, Anthropic, Gemini
# extract() raises ExtractionError if all retries fail
try:
result = extract(instruction, schema, provider, model, api_key)
except ExtractionError as e:
print(f"Failed after {e.attempts} attempts: {e.message}")
# extract_safe() never raises — check result.success instead
result = extract_safe(instruction, schema, provider, model, api_key)
if not result.success:
print(f"Failed: {result.error}")result.data # Validated Pydantic model instance
result.success # True if extraction succeeded
result.attempts # How many retries were needed
result.tokens_in # Input tokens used
result.tokens_out # Output tokens used
result.latency_ms # Total time in milliseconds
result.raw_output # Raw LLM response string
result.error # Error message if failed, else NoneMIT