AI & Engineering

Dynamic Prompt Engineering with DSPy: Moving Beyond Hardcoded Prompt Templates

Program LLMs dynamically. A complete developer's guide to compiling optimal prompt signatures and pipelines using Stanford's DSPy framework.

Sachin Sharma
Sachin SharmaCreator
May 31, 2026
5 min read
Dynamic Prompt Engineering with DSPy: Moving Beyond Hardcoded Prompt Templates
Featured Resource
Quick Overview

Program LLMs dynamically. A complete developer's guide to compiling optimal prompt signatures and pipelines using Stanford's DSPy framework.

Dynamic Prompt Engineering with DSPy: Moving Beyond Hardcoded Prompt Templates

For the past few years, building an "LLM application" has followed a notoriously fragile cycle:

  1. 2.
    Write a long, descriptive string of instructions: "You are a helpful assistant. Please extract X, format as Y, do not include Z..."
  2. 4.
    Test it on 5 user inputs.
  3. 6.
    Deploy to production.
  4. 8.
    Discover that when you upgrade your model (e.g. from GPT-3.5 to GPT-4, or switching to Claude 3.5 Sonnet), your carefully tuned prompt breaks completely.
  5. 10.
    Spend another weekend manually tweaking adjectives, adding more few-shot examples, and crossing your fingers.

This paradigm is called "prompt engineering." It is fragile, unscientific, highly model-dependent, and behaves more like alchemy than software engineering.

In 2026, we have a revolutionary alternative: DSPy (Declarative Self-improving Language Programs). Developed by researchers at Stanford, DSPy shifts AI development from manually tuning fragile prompt strings to programming declarative pipelines.

In this guide, we'll explore how DSPy programmatically compiles optimal prompts, automates few-shot example selection, and builds resilient LLM pipelines.


⚡ 1. The Core Philosophy of DSPy: Separation of Concerns

DSPy introduces the identical division of concerns that revolutionized frontend web development (CSS vs HTML) and database management: separating the flow of the program from the raw instruction prompts.

Instead of writing a massive monolithic string containing instructions, few-shot examples, and formatting directives, in DSPy you define:

  1. 2.
    Signatures: Declarative definitions of what the pipeline takes as input and what it outputs.
  2. 4.
    Modules: Structural classes (like Predict, ChainOfThought, or ReAct) that carry out the signature.
  3. 6.
    Teleprompters (Optimizers): Dynamic compilers that read your signatures, run tests over a tiny validation dataset, and programmatically generate the optimal instructions and few-shot examples for any chosen LLM.
[Signatures (Input/Output)] ──> [Modules (ChainOfThought)] ──> [Optimizer (Teleprompter)]
                                                                          │ (Auto-Tuning)
[Optimal Prompts / Few-Shots] <─── [Evaluate on Validation Data] <────────┘

🏗️ 2. Writing a Declarative Pipeline in DSPy

Let's implement a dynamic customer support ticket classifier and summarizer.

Step A: Define the Signature

Rather than writing instruction strings, we specify input and output fields:

python
import dspy # Define what our system receives and what it must output class SupportTicketSignature(dspy.Signature): """Analyze a customer support ticket, classify its sentiment, and extract actionable steps.""" ticket_text = dspy.InputField(desc="The raw email or message sent by the customer") sentiment = dspy.OutputField(desc="Should be Positive, Neutral, or Negative") urgency = dspy.OutputField(desc="Score from 1 to 5 based on customer frustration") actionable_steps = dspy.OutputField(desc="Bullet points of concrete tasks for our support team")

Step B: Build the Declarative Module

Now, we build a pipeline class utilizing the ChainOfThought reasoning module:

python
class SupportAnalyzer(dspy.Module): def __init__(self): super().__init__() # Use ChainOfThought reasoning for our signature! self.analyzer = dspy.ChainOfThought(SupportTicketSignature) def forward(self, ticket_text): # Run pipeline return self.analyzer(ticket_text=ticket_text)

🛠️ 3. Compiling the Pipeline: The Optimizer (Teleprompter)

Here is where the magic happens. We don't write prompts. Instead, we write a small validation dataset (e.g. 20 examples of tickets and their desired classifications) and let DSPy compile the optimal prompt for us.

We use the BootstrapFewShot optimizer. It will run our pipeline, evaluate outputs against our dataset, dynamically select the absolute best few-shot examples, and format them into the perfect prompt structure for our model:

python
from dspy.teleprompt import BootstrapFewShot # 1. Initialize our LLM (e.g. Llama 3 running locally, or OpenAI GPT-4) llama_model = dspy.LM('ollama_chat/llama3', api_base='http://localhost:11434') dspy.configure(lm=llama_model) # 2. Define a small training set (inputs and expected outputs) trainset = [ dspy.Example( ticket_text="My server crashed and I lost all database backups! Help immediately!", sentiment="Negative", urgency="5", actionable_steps="- Restore database replica - Spin up crash backup server" ).with_inputs('ticket_text'), # ... Add 10-20 more minimal examples ] # 3. Define our validation metric def validate_output(example, pred, trace=None): # Simply check if sentiment and urgency match expected goals return example.sentiment == pred.sentiment and example.urgency == pred.urgency # 4. Instantiate the Optimizer optimizer = BootstrapFewShot(metric=validate_output) # 5. Compile! compiled_analyzer = optimizer.compile(SupportAnalyzer(), trainset=trainset)

📈 4. The Output: How DSPy Compiles Prompts

When you run compiled_analyzer(ticket_text="..."), DSPy will execute the prompt utilizing the programmatically compiled structure.

If you inspect the compiled prompt via llama_model.inspect_history(n=1), you will see that DSPy generated a highly detailed, few-shot prompt containing:

  • A clear instruction header derived mathematically from field descriptors.
  • The exact selection of few-shot examples that scored the highest in validation tests.
  • Structured formatting tags that enforce clean parsing.

If you decide to switch models from Llama 3 to Claude 3.5, you do not rewrite a single line of prompt code. You simply swap the configured model and run optimizer.compile() again. DSPy will automatically rebuild a completely customized, highly optimized prompt layout suited specifically to Claude's neural architecture!


🏁 5. Conclusion: Prompts as Compiled Code

Manual prompt engineering is an obsolete pattern. As AI applications scale, we must treat prompts like compiled assets—declarative structures programmed in code, evaluated over rigorous datasets, and compiled dynamically for our targeted model runtimes. By adopting DSPy, you decouple program flow from instruction alchemy, building resilient, scalable, and self-improving AI pipelines.

Sachin Sharma

Sachin Sharma

Software Developer

Building digital experiences at the intersection of design and code. Sharing weekly insights on engineering, productivity, and the future of tech.