How do you get reliably structured (JSON) output from an LLM through LangChain, and what failure modes remain?
Quick Answer
Use with_structured_output with a Pydantic schema — it uses the provider's native tool/JSON mode and validates the result. Remaining failures: models emitting prose around JSON on non-native paths, schema-valid-but-wrong values, refusals, and truncation on long outputs — so validate, retry with feedback, and design a dead-letter path.
Detailed Answer
The modern path binds a Pydantic model (or JSON schema) via with_structured_output: for providers with native structured output it uses function/tool-calling or JSON mode, so the model is constrained at the API level rather than asked nicely in a prompt, and the response parses into a typed object. This eliminates the classic 'Here's your JSON:' prefix breakage that plagued prompt-and-parse approaches. What can still go wrong: (1) semantically wrong but schema-valid data — validation must include business rules (Pydantic validators), not just types; (2) refusals or safety responses instead of the schema; (3) truncation when max_tokens clips a long array mid-object; (4) enum drift — the model inventing category values, mitigated by Literal types; (5) on self-hosted models without native JSON mode, you're back to parser + retry (OutputFixingParser-style loops or grammar-constrained decoding in vLLM). Production pattern: schema binding + strict Pydantic validators + bounded retry with the validation error fed back + metric/dead-letter on final failure rather than a 500.
Code Example
class Ticket(BaseModel):
severity: Literal['low','medium','high','critical']
component: str
summary: str = Field(max_length=200)
extractor = model.with_structured_output(Ticket)
try:
t = extractor.invoke(f'Classify: {alert_text}')
except ValidationError as e:
t = extractor.invoke(f'Classify: {alert_text}\nPrevious attempt invalid: {e}')Interview Tip
The senior move is enumerating what schema binding does NOT fix — schema-valid-but-wrong values and truncation — and naming the dead-letter path for terminal failures.