04. Advanced: DSPy Prompt Optimization
Overview
DSPy stands for "Declarative Self-improving Language Programs". Instead of manually tweaking prompt strings, you define:
- Signature: Input/Output types
- Module: The logic flow
- Optimizer: A metric to maximize (e.g., faithfulness)
DSPy then "compiles" your program, automatically finding the best few-shot examples and instructions to maximize your metric. This is the future of prompt engineering.
Key Concepts
| Concept | Description |
|---|---|
| Signature | Defines input/output types for a task |
| Module | Encapsulates LLM calls and logic |
| Optimizer | Automatically improves prompts |
| Teleprompter | DSPy's optimization algorithm |
DSPy Signatures
import dspy
# Simple signature
class BasicQA(dspy.Signature):
"""Answer questions with short factual answers."""
question = dspy.InputField()
answer = dspy.OutputField(desc="often between 1 and 5 words")
# Complex signature with chain-of-thought
class ReasonedQA(dspy.Signature):
"""Answer questions with reasoning."""
question = dspy.InputField()
reasoning = dspy.OutputField(desc="step-by-step reasoning")
answer = dspy.OutputField()DSPy Modules
class RAGModule(dspy.Module):
def __init__(self, num_passages=3):
super().__init__()
self.retrieve = dspy.Retrieve(k=num_passages)
self.generate = dspy.ChainOfThought(ReasonedQA)
def forward(self, question):
# Retrieve relevant passages
passages = self.retrieve(question).passages
# Generate answer with retrieved context
context = "\n".join(passages)
return self.generate(question=question, context=context)Optimization with Teleprompters
from dspy.teleprompt import BootstrapFewShot
# Define a metric
def accuracy_metric(example, pred, trace=None):
return example.answer.lower() == pred.answer.lower()
# Create optimizer
teleprompter = BootstrapFewShot(
metric=accuracy_metric,
max_bootstrapped_demos=4,
max_labeled_demos=16
)
# Compile (optimize) the module
optimized_rag = teleprompter.compile(
RAGModule(),
trainset=train_examples
)Why DSPy?
Automatic Optimization: DSPy finds optimal prompts and examples without manual tuning
| Manual Prompting | DSPy |
|---|---|
| Trial and error | Systematic optimization |
| Intuition-based | Metric-driven |
| Hard to reproduce | Reproducible |
| Brittle to changes | Self-adapting |
DSPy vs Traditional Prompting
# Traditional approach
prompt = """You are a helpful assistant. Answer the question accurately.
Question: {question}
Answer:"""
# DSPy approach
class QA(dspy.Signature):
question = dspy.InputField()
answer = dspy.OutputField()
qa_module = dspy.Predict(QA)
# DSPy optimizes the actual prompt automatically!Hands-on Practice
Define Signatures
Create input/output specifications
Build Modules
Combine retrieval and generation
Set Up Metrics
Define what "good" looks like
Run Optimization
Let DSPy find optimal prompts
References
Academic Papers
- "DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines" - Khattab et al., 2023
- arXiv:2310.03714 (opens in a new tab)
- The foundational DSPy paper