Optimize with Prompt Templates¶
Learn how to use dynamic prompt templates with placeholders that change based on your input data.
What You'll Learn¶
Sometimes you want prompts that adapt to your data. For example:
- Analyzing reviews from different product categories → customize the prompt per category
- Processing documents from different departments → include context per department
- Extracting from forms with different fields → adapt instructions per field type
This tutorial teaches you how to optimize prompts with dynamic placeholders like {category}, {product}, {review}.
Why Template Optimization?¶
Instead of a fixed system prompt:
Use dynamic templates:
# ✅ Dynamic prompt (adapts to each input)
"You are an expert analyst specializing in {category} reviews."
During optimization, DSPydantic learns which template variations work best. Then during extraction, the placeholders are filled from your input data.
Step 1: Define Your Model¶
Create a Pydantic model for your structured output:
from pydantic import BaseModel, Field
from typing import Literal
class ProductReview(BaseModel):
"""Extract product review data."""
sentiment: Literal["positive", "negative", "neutral"] = Field(
description="Review sentiment"
)
rating: int = Field(description="Rating 1-5")
aspects: list[Literal["camera", "performance", "battery"]] = Field(
description="Product aspects mentioned"
)
Step 2: Create Examples with Dictionary Text¶
Instead of plain text, use dictionaries with keys that become placeholders:
from dspydantic import Example
examples = [
Example(
text={
"review": "Amazing camera quality and blazingly fast performance!",
"product": "iPhone 15 Pro",
"category": "smartphone"
},
expected_output={
"sentiment": "positive",
"rating": 4,
"aspects": ["camera", "performance"]
}
),
Example(
text={
"review": "Poor battery life, way too expensive.",
"product": "Samsung Galaxy S24",
"category": "smartphone"
},
expected_output={
"sentiment": "negative",
"rating": 2,
"aspects": ["battery"]
}
),
Example(
text={
"review": "Works okay, nothing special.",
"product": "Google Pixel 8",
"category": "smartphone"
},
expected_output={
"sentiment": "neutral",
"rating": 3,
"aspects": ["performance"]
}
),
]
Key point: The dictionary keys (review, product, category) become available as placeholders.
Step 3: Define Prompt Templates and Optimize¶
Create prompt templates with {placeholders} matching your dictionary keys:
import dspy
from dspydantic import Prompter
# Configure language model
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini", api_key="your-api-key"))
# Create prompter
prompter = Prompter(
model=ProductReview,
model_id="openai/gpt-4o-mini",
)
# Optimize with templates
result = prompter.optimize(
examples=examples,
system_prompt="You are an expert analyst specializing in {category} reviews.",
instruction_prompt="Analyze the {category} product review about {product}: {review}",
)
During optimization: 1. The placeholders are filled from each example's dictionary 2. DSPydantic tests different field descriptions and template variations 3. The optimized prompts retain placeholders for reuse at extraction time
Step 4: Extract with Dynamic Prompts¶
After optimization, use the prompter with new data. Placeholders are automatically filled:
# Extract with dynamic prompts
data = prompter.run(
text={
"category": "smartphone",
"product": "iPhone 15 Pro",
"review": "Great camera and battery lasted all day!"
}
)
print(data)
# ProductReview(sentiment='positive', rating=4, aspects=['camera', 'battery'])
The prompter fills {category}, {product}, and {review} from the dictionary you provide, making the prompts context-aware.
How It Works¶
Here's the flow:
flowchart TD
A["Define Model & Examples<br/>(with dict text)"] --> B["Create Templates<br/>(with {placeholders})"]
B --> C["Optimize<br/>(fill + test + learn)"]
C --> D["Optimized Prompter<br/>(templates retain placeholders)"]
D --> E["Extract<br/>(auto-fill placeholders)"]
| Step | What Happens |
|---|---|
| Define | Model structure and dictionary-based examples |
| Template | System and instruction prompts with {placeholders} |
| Optimize | Placeholders are filled for each example; variations are tested |
| Result | Optimized prompts keep placeholders for reuse |
| Extract | You provide a dict; placeholders are auto-filled |
What Gets Optimized¶
| Parameter | What | Impact |
|---|---|---|
| Field Descriptions | How each field is described | High |
| System Prompt Template | Template structure and wording | Medium |
| Instruction Prompt Template | Template structure and wording | Medium |
Complete Example: Multi-Category Reviews¶
Here's a full example handling reviews from different product categories:
from pydantic import BaseModel, Field
from typing import Literal
from dspydantic import Example, Prompter
import dspy
# Model
class Review(BaseModel):
sentiment: Literal["positive", "negative", "neutral"] = Field(
description="Overall sentiment"
)
rating: int = Field(description="Rating 1-5")
# Examples from different categories
examples = [
Example(
text={
"category": "laptop",
"product": "Dell XPS 15",
"review": "Excellent performance, runs any software smoothly."
},
expected_output={"sentiment": "positive", "rating": 5}
),
Example(
text={
"category": "laptop",
"product": "MacBook Pro",
"review": "Expensive and battery drains quickly."
},
expected_output={"sentiment": "negative", "rating": 2}
),
Example(
text={
"category": "phone",
"product": "Samsung Galaxy",
"review": "Works well for daily tasks, nothing exceptional."
},
expected_output={"sentiment": "neutral", "rating": 3}
),
]
# Configure and optimize
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"))
prompter = Prompter(model=Review)
result = prompter.optimize(
examples=examples,
system_prompt="You are a product review analyst for {category}s.",
instruction_prompt="Rate this {category} review: {review}",
)
# Extract from new reviews
phone_review = prompter.run(text={
"category": "phone",
"product": "iPhone 16",
"review": "Amazing camera, super fast processor!"
})
laptop_review = prompter.run(text={
"category": "laptop",
"product": "Framework",
"review": "Overpriced and has driver issues."
})
print(phone_review) # sentiment='positive', rating=5
print(laptop_review) # sentiment='negative', rating=2
Tips¶
- Consistent keys: All examples should have the same dictionary keys
- Meaningful names: Use descriptive key names that match placeholders (
{category}, not{c}) - Case-sensitive: Placeholders
{category}and{Category}are different - Optional placeholders: Not all prompts need all placeholders
- Avoid duplicates: Don't repeat the same placeholder or hardcode values
Next Steps¶
| Topic | Guide |
|---|---|
| First optimization | Extract Structured Data |
| Text-only output | Extract Free-form Text |
| Advanced templates | Configure Optimization Parameters |
| Production deployment | Save and Load a Prompter |
Troubleshooting¶
Placeholder not being filled?
- Check spelling and case:
{category}vs{Category} - Ensure your dictionary has the key:
text={"category": "phone", ...}
Optimization accuracy low?
- Add more diverse examples (aim for 10+)
- Make sure examples are correctly labeled
- Verify placeholders appear in system and instruction prompts
See also: - Configure Optimization Parameters - Reference: Prompter