| name | outlines |
| description | Guarantee valid JSON/XML/code structure during generation, use Pydantic models for type-safe outputs, support local models (Transformers, vLLM), and maximize inference speed with Outlines - dottxt.ai's structured generation library |
| version | 1.0.0 |
| author | Orchestra Research |
| license | MIT |
| tags | ["Prompt Engineering","Outlines","Structured Generation","JSON Schema","Pydantic","Local Models","Grammar-Based Generation","vLLM","Transformers","Type Safety"] |
| dependencies | ["outlines","transformers","vllm","pydantic"] |
Outlines: Structured Text Generation
When to Use This Skill
Use Outlines when you need to:
- Guarantee valid JSON/XML/code structure during generation
- Use Pydantic models for type-safe outputs
- Support local models (Transformers, llama.cpp, vLLM)
- Maximize inference speed with zero-overhead structured generation
- Generate against JSON schemas automatically
- Control token sampling at the grammar level
GitHub Stars: 8,000+ | From: dottxt.ai (formerly .txt)
Installation
pip install outlines
pip install outlines transformers
pip install outlines llama-cpp-python
pip install outlines vllm
Quick Start
Basic Example: Classification
import outlines
from typing import Literal
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
prompt = "Sentiment of 'This product is amazing!': "
generator = outlines.generate.choice(model, ["positive", "negative", "neutral"])
sentiment = generator(prompt)
print(sentiment)
With Pydantic Models
from pydantic import BaseModel
import outlines
class User(BaseModel):
name: str
age: int
email: str
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
prompt = "Extract user: John Doe, 30 years old, john@example.com"
generator = outlines.generate.json(model, User)
user = generator(prompt)
print(user.name)
print(user.age)
print(user.email)
Core Concepts
1. Constrained Token Sampling
Outlines uses Finite State Machines (FSM) to constrain token generation at the logit level.
How it works:
- Convert schema (JSON/Pydantic/regex) to context-free grammar (CFG)
- Transform CFG into Finite State Machine (FSM)
- Filter invalid tokens at each step during generation
- Fast-forward when only one valid token exists
Benefits:
- Zero overhead: Filtering happens at token level
- Speed improvement: Fast-forward through deterministic paths
- Guaranteed validity: Invalid outputs impossible
import outlines
class Person(BaseModel):
name: str
age: int
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, Person)
result = generator("Generate person: Alice, 25")
2. Structured Generators
Outlines provides specialized generators for different output types.
Choice Generator
generator = outlines.generate.choice(
model,
["positive", "negative", "neutral"]
)
sentiment = generator("Review: This is great!")
JSON Generator
from pydantic import BaseModel
class Product(BaseModel):
name: str
price: float
in_stock: bool
generator = outlines.generate.json(model, Product)
product = generator("Extract: iPhone 15, $999, available")
print(type(product))
Regex Generator
generator = outlines.generate.regex(
model,
r"[0-9]{3}-[0-9]{3}-[0-9]{4}"
)
phone = generator("Generate phone number:")
Integer/Float Generators
int_generator = outlines.generate.integer(model)
age = int_generator("Person's age:")
float_generator = outlines.generate.float(model)
price = float_generator("Product price:")
3. Model Backends
Outlines supports multiple local and API-based backends.
Transformers (Hugging Face)
import outlines
model = outlines.models.transformers(
"microsoft/Phi-3-mini-4k-instruct",
device="cuda"
)
generator = outlines.generate.json(model, YourModel)
llama.cpp
model = outlines.models.llamacpp(
"./models/llama-3.1-8b-instruct.Q4_K_M.gguf",
n_gpu_layers=35
)
generator = outlines.generate.json(model, YourModel)
vLLM (High Throughput)
model = outlines.models.vllm(
"meta-llama/Llama-3.1-8B-Instruct",
tensor_parallel_size=2
)
generator = outlines.generate.json(model, YourModel)
OpenAI (Limited Support)
model = outlines.models.openai(
"gpt-4o-mini",
api_key="your-api-key"
)
generator = outlines.generate.json(model, YourModel)
4. Pydantic Integration
Outlines has first-class Pydantic support with automatic schema translation.
Basic Models
from pydantic import BaseModel, Field
class Article(BaseModel):
title: str = Field(description="Article title")
author: str = Field(description="Author name")
word_count: int = Field(description="Number of words", gt=0)
tags: list[str] = Field(description="List of tags")
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, Article)
article = generator("Generate article about AI")
print(article.title)
print(article.word_count)
Nested Models
class Address(BaseModel):
street: str
city: str
country: str
class Person(BaseModel):
name: str
age: int
address: Address
generator = outlines.generate.json(model, Person)
person = generator("Generate person in New York")
print(person.address.city)
Enums and Literals
from enum import Enum
from typing import Literal
class Status(str, Enum):
PENDING = "pending"
APPROVED = "approved"
REJECTED = "rejected"
class Application(BaseModel):
applicant: str
status: Status
priority: Literal["low", "medium", "high"]
generator = outlines.generate.json(model, Application)
app = generator("Generate application")
print(app.status)
Common Patterns
Pattern 1: Data Extraction
from pydantic import BaseModel
import outlines
class CompanyInfo(BaseModel):
name: str
founded_year: int
industry: str
employees: int
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, CompanyInfo)
text = """
Apple Inc. was founded in 1976 in the technology industry.
The company employs approximately 164,000 people worldwide.
"""
prompt = f"Extract company information:\n{text}\n\nCompany:"
company = generator(prompt)
print(f"Name: {company.name}")
print(f"Founded: {company.founded_year}")
print(f"Industry: {company.industry}")
print(f"Employees: {company.employees}")
Pattern 2: Classification
from typing import Literal
import outlines
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.choice(model, ["spam", "not_spam"])
result = generator("Email: Buy now! 50% off!")
categories = ["technology", "business", "sports", "entertainment"]
category_gen = outlines.generate.choice(model, categories)
category = category_gen("Article: Apple announces new iPhone...")
class Classification(BaseModel):
label: Literal["positive", "negative", "neutral"]
confidence: float
classifier = outlines.generate.json(model, Classification)
result = classifier("Review: This product is okay, nothing special")
Pattern 3: Structured Forms
class UserProfile(BaseModel):
full_name: str
age: int
email: str
phone: str
country: str
interests: list[str]
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, UserProfile)
prompt = """
Extract user profile from:
Name: Alice Johnson
Age: 28
Email: alice@example.com
Phone: 555-0123
Country: USA
Interests: hiking, photography, cooking
"""
profile = generator(prompt)
print(profile.full_name)
print(profile.interests)
Pattern 4: Multi-Entity Extraction
class Entity(BaseModel):
name: str
type: Literal["PERSON", "ORGANIZATION", "LOCATION"]
class DocumentEntities(BaseModel):
entities: list[Entity]
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, DocumentEntities)
text = "Tim Cook met with Satya Nadella at Microsoft headquarters in Redmond."
prompt = f"Extract entities from: {text}"
result = generator(prompt)
for entity in result.entities:
print(f"{entity.name} ({entity.type})")
Pattern 5: Code Generation
class PythonFunction(BaseModel):
function_name: str
parameters: list[str]
docstring: str
body: str
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, PythonFunction)
prompt = "Generate a Python function to calculate factorial"
func = generator(prompt)
print(f"def {func.function_name}({', '.join(func.parameters)}):")
print(f' """{func.docstring}"""')
print(f" {func.body}")
Pattern 6: Batch Processing
def batch_extract(texts: list[str], schema: type[BaseModel]):
"""Extract structured data from multiple texts."""
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, schema)
results = []
for text in texts:
result = generator(f"Extract from: {text}")
results.append(result)
return results
class Person(BaseModel):
name: str
age: int
texts = [
"John is 30 years old",
"Alice is 25 years old",
"Bob is 40 years old"
]
people = batch_extract(texts, Person)
for person in people:
print(f"{person.name}: {person.age}")
Backend Configuration
Transformers
import outlines
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
model = outlines.models.transformers(
"microsoft/Phi-3-mini-4k-instruct",
device="cuda",
model_kwargs={"torch_dtype": "float16"}
)
model = outlines.models.transformers("meta-llama/Llama-3.1-8B-Instruct")
model = outlines.models.transformers("mistralai/Mistral-7B-Instruct-v0.3")
model = outlines.models.transformers("Qwen/Qwen2.5-7B-Instruct")
llama.cpp
model = outlines.models.llamacpp(
"./models/llama-3.1-8b.Q4_K_M.gguf",
n_ctx=4096,
n_gpu_layers=35,
n_threads=8
)
model = outlines.models.llamacpp(
"./models/model.gguf",
n_gpu_layers=-1
)
vLLM (Production)
model = outlines.models.vllm("meta-llama/Llama-3.1-8B-Instruct")
model = outlines.models.vllm(
"meta-llama/Llama-3.1-70B-Instruct",
tensor_parallel_size=4
)
model = outlines.models.vllm(
"meta-llama/Llama-3.1-8B-Instruct",
quantization="awq"
)
Best Practices
1. Use Specific Types
class Product(BaseModel):
name: str
price: float
quantity: int
in_stock: bool
class Product(BaseModel):
name: str
price: str
quantity: str
2. Add Constraints
from pydantic import Field
class User(BaseModel):
name: str = Field(min_length=1, max_length=100)
age: int = Field(ge=0, le=120)
email: str = Field(pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$")
class User(BaseModel):
name: str
age: int
email: str
3. Use Enums for Categories
class Priority(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
class Task(BaseModel):
title: str
priority: Priority
class Task(BaseModel):
title: str
priority: str
4. Provide Context in Prompts
prompt = """
Extract product information from the following text.
Text: iPhone 15 Pro costs $999 and is currently in stock.
Product:
"""
prompt = "iPhone 15 Pro costs $999 and is currently in stock."
5. Handle Optional Fields
from typing import Optional
class Article(BaseModel):
title: str
author: Optional[str] = None
date: Optional[str] = None
tags: list[str] = []
Comparison to Alternatives
| Feature | Outlines | Instructor | Guidance | LMQL |
|---|
| Pydantic Support | ✅ Native | ✅ Native | ❌ No | ❌ No |
| JSON Schema | ✅ Yes | ✅ Yes | ⚠️ Limited | ✅ Yes |
| Regex Constraints | ✅ Yes | ❌ No | ✅ Yes | ✅ Yes |
| Local Models | ✅ Full | ⚠️ Limited | ✅ Full | ✅ Full |
| API Models | ⚠️ Limited | ✅ Full | ✅ Full | ✅ Full |
| Zero Overhead | ✅ Yes | ❌ No | ⚠️ Partial | ✅ Yes |
| Automatic Retrying | ❌ No | ✅ Yes | ❌ No | ❌ No |
| Learning Curve | Low | Low | Low | High |
When to choose Outlines:
- Using local models (Transformers, llama.cpp, vLLM)
- Need maximum inference speed
- Want Pydantic model support
- Require zero-overhead structured generation
- Control token sampling process
When to Choose Outlines vs Instructor
Decision Tree
Are you using LOCAL models (Transformers, llama.cpp, vLLM)?
├─ YES → Use **Outlines**
│ └─ Benefits: Zero overhead, grammar-based generation, maximum speed
│
└─ NO → Are you using API models (Anthropic, OpenAI, Google)?
├─ YES → Use **Instructor**
│ └─ Benefits: Automatic retry, multi-provider support, easier setup
│
└─ NO → Do you need BOTH local and cloud?
└─ YES → Use **Instructor** (supports both via provider abstraction)
Comparison Table
| Feature | Outlines | Instructor |
|---|
| Local Models | ✅ Excellent | ⚠️ Limited |
| API Models | ⚠️ Manual | ✅ Excellent |
| Zero Overhead | ✅ Yes | ❌ No |
| Automatic Retry | ❌ No | ✅ Yes |
| Multi-Provider | ⚠️ Manual | ✅ Built-in |
| Learning Curve | Medium | Low |
| Performance | 1.2-2x faster | Standard |
| Setup Complexity | Medium | Low |
Use Cases for TRAE_Extractor-app
Use Outlines when:
- Running local models via Docker Model Runner
- Need maximum inference speed for captioning
- Generating structured data from local LLMs
- Want zero-overhead validation
- Using llama.cpp or vLLM for inference
Use Instructor when:
- Using cloud providers (Anthropic, OpenAI, Google, Perplexity)
- Need automatic retry on API failures
- Working with multi-provider setup
- Want easier setup and maintenance
- Need both local and cloud support
Docker Model Runner Integration
Pattern for Using Outlines with Docker Model Runner
import outlines
from outlines.models import llamacpp
model = llamacpp(
"./models/llama-3.1-8b.Q4_K_M.gguf",
n_ctx=4096,
n_gpu_layers=35
)
generator = outlines.generate.json(model, CaptionSchema)
async def generate_caption(image_description: str) -> CaptionSchema:
try:
caption = generator(f"Generate caption for: {image_description}")
return caption
except Exception as e:
logger.warning(f"Local model failed: {e}, falling back to cloud")
return await generate_caption_cloud(image_description)
async def generate_caption_cloud(image_description: str) -> CaptionSchema:
from instructor import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
return client.chat.completions.create(
model="gpt-4o-mini",
response_model=CaptionSchema,
messages=[{"role": "user", "content": image_description}]
)
Fallback Strategy: Local → Cloud
import outlines
from instructor import OpenAI
import logging
logger = logging.getLogger(__name__)
class HybridCaptionGenerator:
"""Hybrid generator using local Outlines with cloud Instructor fallback"""
def __init__(self, local_model_path: str, cloud_api_key: str):
self.local_model = outlines.models.llamacpp(
local_model_path,
n_ctx=4096,
n_gpu_layers=35
)
self.cloud_client = OpenAI(api_key=cloud_api_key)
self.use_local = True
async def generate(self, prompt: str, schema: type):
"""Generate with automatic fallback to cloud"""
if self.use_local:
try:
generator = outlines.generate.json(self.local_model, schema)
result = generator(prompt)
logger.info(f"Generated caption using local model")
return result
except Exception as e:
logger.warning(f"Local model failed: {e}, switching to cloud")
self.use_local = False
return await self.generate(prompt, schema)
:
generator = outlines.generate.json(.cloud_client, schema)
result = generator(prompt)
logger.info()
result
():
.use_local =
logger.info()
Benchmark Performance: Local vs Cloud
import time
import outlines
from instructor import OpenAI
async def benchmark_caption_generation():
"""Compare local vs cloud performance"""
prompts = [
"A beautiful sunset at the beach",
"A mountain landscape with snow",
"A city skyline at night"
]
local_model = outlines.models.llamacpp(
"./models/llama-3.1-8b.Q4_K_M.gguf",
n_ctx=4096,
n_gpu_layers=35
)
local_generator = outlines.generate.json(local_model, CaptionSchema)
local_times = []
for prompt in prompts:
start = time.time()
result = local_generator(prompt)
elapsed = time.time() - start
local_times.append(elapsed)
cloud_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
cloud_generator = outlines.generate.json(cloud_client, CaptionSchema)
cloud_times = []
for prompt in prompts:
start = time.time()
result = cloud_generator(prompt)
elapsed = time.time() - start
cloud_times.append(elapsed)
avg_local = sum(local_times) / len(local_times)
avg_cloud = sum(cloud_times) / len(cloud_times)
speedup = avg_cloud / avg_local
print(f"Local average: {avg_local:.2f}s")
print(f"Cloud average: {avg_cloud:.2f}s")
print(f"Speedup: {speedup:.2f}x faster")
()
When to choose alternatives:
- Instructor: Need API models with automatic retrying
- Guidance: Need token healing and complex workflows
- LMQL: Prefer declarative query syntax
Performance Characteristics
Speed:
- Zero overhead: Structured generation as fast as unconstrained
- Fast-forward optimization: Skips deterministic tokens
- 1.2-2x faster than post-generation validation approaches
Memory:
- FSM compiled once per schema (cached)
- Minimal runtime overhead
- Efficient with vLLM for high throughput
Accuracy:
- 100% valid outputs (guaranteed by FSM)
- No retry loops needed
- Deterministic token filtering
Resources
See Also
references/json_generation.md - Comprehensive JSON and Pydantic patterns
references/backends.md - Backend-specific configuration
references/examples.md - Production-ready examples