Jangada AIJangada AI

Structured output (Pydantic)

A single parse() call returns a validated Pydantic instance, regardless of how each provider implements it under the hood.

from pydantic import BaseModel
from jangada_ai import LLM

class Person(BaseModel):
    name: str
    age: int

llm = LLM("openai", "gpt-4o-mini")
comp = llm.parse("Extract: João is 30 years old.", Person)
print(comp.parsed.name, comp.parsed.age)   # João 30
  • comp.parsed → the Pydantic instance. Reliable: if some SDK returns parsed=None with valid JSON in .text, jangada validates the text against the schema automatically (no manual model_validate_json needed).
  • comp.text → the raw JSON returned.
  • comp.usage / comp.cost → tokens and estimated cost.

🔁 JSON off-schema → failover. Output that doesn't match the model raises errors.OutputValidationError and tries the next model in with_fallback (it won't retry the same one). Fallback covers API errors and malformed output.

max_tokens has a high default of 8192 since v1.4.5. Extractions that exceed this limit may still truncate JSON. In that case jangada raises errors.TruncatedError (message: "raise max_tokens") before attempting to validate — you don't get a confusing cut-off-JSON error from Pydantic. The fix is to pass a higher max_tokens — see Generation parameters.

Async

comp = await llm.aparse("Extract: ...", Person)

How each provider resolves it

ProviderMechanism
OpenAIchat.completions.parse(response_format=Model)
Groqjson_schema when the model supports it; otherwise JSON Object mode
Geminiconfig.response_schema=Model → resp.parsed
Anthropictool-forcing (pinned tool_choice) → validates tool_use

You don't need to know which is which — parse()/aparse() take care of it. Use Pydantic v2 (model_json_schema(), model_validate).

Groq — works on any model. Only some Groq models accept json_schema (e.g., openai/gpt-oss-*, llama-4-scout). For the rest (e.g., llama-3.3-70b-versatile), jangada automatically falls back to JSON Object mode: it injects the schema into the instruction, asks for a JSON object, and validates with Pydantic. You call parse() the same way — without knowing what the model supports.

It works together with Vision and Documents: pass images= or files= in the same parse() call.

Example

examples/structured_example.py — runnable script.

On this page