Discover proven methods to extract clean, parseable data from LLMs, avoiding messy text parsing pitfalls. Explore prompting strategies, JSON mode, Pydantic, and advanced libraries for production-ready applications.
## Why Do We Need Structured Outputs from LLMs?
Large language models (LLMs) excel at generating human-like text, but what happens when you need data in a specific format, like JSON or a database-ready schema? Imagine building an app that classifies customer feedback into categories or extracts entities from resumes—free-form text responses often lead to parsing headaches, errors, and unreliable results.
Consider a real-world scenario: You're developing a sentiment analysis tool. You prompt an LLM: "Analyze this review and output positive, negative, or neutral." It might respond with "This is positive!" instead of just "positive," breaking your downstream code. This inconsistency scales poorly in production. Structured outputs solve this by enforcing schemas, ensuring outputs are machine-readable and deterministic.
### Question: What Problems Arise with Unstructured Text?
**Answer:** LLMs hallucinate formats, add extra text, or vary structures across responses.
**Exploration:** In practice, parsing text with regex or string matching fails ~20-30% of the time due to verbosity or creativity. For example:
```python
response = "The sentiment is positive, with high enthusiasm."
# Regex might miss this
```
Structured methods boost reliability to near 100%, critical for agents, RAG systems, or data pipelines.
## Basic Technique: Enhanced Prompting Strategies
Start simple—no extra libraries needed. Guide the LLM with clear instructions, examples, and delimiters.
### How to Craft Robust Prompts?
- **Specify exact format:** "Output ONLY valid JSON: {"category": "value"}"
- **Use examples (few-shot):** Provide 2-3 input-output pairs.
- **Add safeguards:** "Do not add explanations. If unsure, output null."
**Practical Example:** Classifying support tickets.
```plaintext
Prompt:
Classify the issue type from this ticket. Output ONLY JSON {"issue_type": "bug|feature|other"}
Ticket: Button doesn't work.
Expected: {"issue_type": "bug"}
```
This works ~90% on simple tasks but falters on complex schemas. For deeper dives, check the [course notebook on prompting](https://github.com/deeplearning-ai/short-course-structured-llm-output/blob/main/notebooks/01_prompting_structured_outputs.ipynb).
## JSON Mode: OpenAI's Built-in Solution
OpenAI's `response_format: {type: "json_object"}` forces JSON output (GPT-4o-mini and later).
### Question: When Does JSON Mode Shine?
**Answer:** For arbitrary schemas without tool definitions.
**Exploration:** Combine with a system prompt defining the schema.
```python
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o-mini",
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": "Output JSON with keys: sentiment (pos/neg/neu), confidence (0-1)."},
{"role": "user", "content": "I love this product!"}
]
)
print(response.choices[0].message.content) # {"sentiment": "pos", "confidence": 0.95}
```
Limitations: No nested objects perfectly; OpenAI-only. Success rate: 99%+ on supported models. Notebook: [JSON mode demo](https://github.com/deeplearning-ai/short-course-structured-llm-output/blob/main/notebooks/02_json_mode.ipynb).
## Parallel Function Calling: Structured Extraction at Scale
OpenAI's tools/functions allow defining schemas for multiple extractions simultaneously.
### How to Implement Parallel Calls?
1. Define tool schemas with `type: "function"`, `parameters` as JSON schema.
2. Request `tool_choice: "auto"` or specific.
3. Parse `tool_calls` from response.
**Example: Multi-label Extraction**
```python
tools = [{
"type": "function",
"function": {
"name": "extract_info",
"parameters": {
"type": "object",
"properties": {
"urgency": {"type": "string", "enum": ["low", "medium", "high"]},
"category": {"type": "string"}
}
}
}
}]
# Call API with tools
```
**Real-World Application:** Agentic workflows extracting actions from user queries. Handles parallelism better than serial prompting. Notebook: [Function calling](https://github.com/deeplearning-ai/short-course-structured-llm-output/blob/main/notebooks/03_function_calling_structured_outputs.ipynb).
## Pydantic + Instructor: Pythonic Schema Enforcement
For Python devs, Pydantic models + [Instructor](https://github.com/jxnl/instructor) patch OpenAI/Anthropic clients to validate outputs.
### Question: Why Pydantic?
**Answer:** Type-safe models with validation.
**Exploration:** Define a class, Instructor ensures output matches or retries.
```python
from pydantic import BaseModel
from instructor import from_openai
from openai import OpenAI
class Issue(BaseModel):
issue_type: str
priority: int
client = from_openai(OpenAI())
result = client.messages.create(
model="gpt-4o-mini",
response_model=Issue,
messages=[{"role": "user", "content": "Fix login bug urgently."}]
)
print(result) # Issue(issue_type='bug', priority=3)
```
Adds value: Handles errors gracefully, supports partial fills. Cross-provider (OpenAI, Anthropic). Notebook: [Instructor example](https://github.com/deeplearning-ai/short-course-structured-llm-output/blob/main/notebooks/04_pydantic_instructor.ipynb).
## Outlines: Regex-Guided Generation
[Outlines](https://github.com/outlines-dev/outlines) uses regex/JSON schema to constrain logits during generation.
**Practical Use:** Generate valid JSON without post-parsing.
```python
import outlines
model = outlines.models.OpenAI("gpt-4o-mini")
response = model.generate(
"Extract entities:",
schema=outlines.schemas.json(["name", "age"])
)
```
Faster, more efficient for known schemas. Great for edge devices.
## LMQL: Query Language for LLMs
[LMQL](https://lmql.ai/) lets you write SQL-like programs for structured gen.
**Example:**
```lmql
ARG max_tokens=100
"Classify: "
issue in "bug feature question"
"-> " issue
STOPS AT
"."
```
Compiles to constrained decoding. Notebook available in the [main repo](https://github.com/deeplearning-ai/short-course-structured-llm-output).
## Guidance & DSPy: Advanced Orchestration
[Guidance](https://github.com/guidance-ai/guidance) (Microsoft) and DSPy offer templating and optimization.
**Guidance Snippet:**
```python
import guidance
from guidance import models, gen, select
llm = models.LlamaCpp("llama-3-8b-instruct.gguf")
llm += select(options=["bug", "feature"])
```
DSPy compiles prompts for structured tasks. Ideal for pipelines.
## Choosing the Right Tool
| Method | Pros | Cons | Best For |
|--------|------|------|----------|
| Prompting | Simple, no deps | Brittle | Prototypes |
| JSON Mode | Reliable, fast | OpenAI-only | Simple JSON |
| Function Calling | Parallel, semantic | Schema limits | Agents |
| Instructor | Pythonic, robust | OpenAI/Anthropic | Apps |
| Outlines/LMQL | Constrained gen | Learning curve | Efficiency |
## Production Tips
- **Validate always:** Use Pydantic post-generation.
- **Fallbacks:** Retry with different models.
- **Monitor:** Track parse success rates.
- **Scale:** Combine with vector DBs for RAG-structured hybrids.
Explore all notebooks in the [DeepLearning.AI repo](https://github.com/deeplearning-ai/short-course-structured-llm-output) to run experiments yourself. This course equips you to build dependable LLM apps—start prompting better today!
---
<div style="text-align: center; margin-top: 2rem;">
<a href="https://www.deeplearning.ai/short-courses/getting-structured-llm-output/" target="_blank" rel="noopener noreferrer" class="view-full-resource-btn" style="display: inline-block; background-color: #f97316; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600; transition: background-color 0.2s;">View Full Resource</a>
</div>