Chapter 1 ยท Section 4

Your First DSPy Program

Let's write your first DSPy program! This hands-on section will walk you through creating a simple question-answering application step by step.

~15 min read

๐ŸŽฏ What We'll Build

We'll create a program that:

  • Takes a question as input
  • Uses a language model to generate an answer
  • Returns the answer

This is the "Hello World" of DSPy!

๐Ÿ“ The Complete Program

Here's the full program. Don't worry if you don't understand everything yetโ€”we'll break it down step by step.

hello_dspy.py
"""
Your First DSPy Program
A simple question-answering application
"""

import os
from dotenv import load_dotenv
import dspy

# Load environment variables
load_dotenv()

def main():
    # Step 1: Configure the language model
    lm = dspy.LM(
        model="openai/gpt-4o-mini",
        api_key=os.getenv("OPENAI_API_KEY")
    )
    dspy.configure(lm=lm)

    # Step 2: Define the task signature
    class QuestionAnswer(dspy.Signature):
        """Answer questions with factual information."""
        question: str = dspy.InputField()
        answer: str = dspy.OutputField()

    # Step 3: Create a predictor
    qa = dspy.Predict(QuestionAnswer)

    # Step 4: Use it!
    question = "What is the capital of France?"
    result = qa(question=question)

    # Step 5: Display the result
    print(f"Question: {question}")
    print(f"Answer: {result.answer}")

if __name__ == "__main__":
    main()

๐Ÿ” Step-by-Step Breakdown

โš™๏ธ

Configure the Language Model

lm = dspy.LM(
    model="openai/gpt-4o-mini",
    api_key=os.getenv("OPENAI_API_KEY")
)
dspy.configure(lm=lm)

What's happening:

  • dspy.LM() creates a language model instance
  • We specify which model to use (gpt-4o-mini)
  • We provide the API key from environment variables
  • dspy.configure() sets this as the default LM

Think of this as: Setting up your "engine" that powers all DSPy operations.

๐Ÿ“‹

Define the Task Signature

class QuestionAnswer(dspy.Signature):
    """Answer questions with factual information."""
    question: str = dspy.InputField()
    answer: str = dspy.OutputField()

What's happening:

  • We create a class that inherits from dspy.Signature
  • The docstring describes what the task does
  • question is an input field (what we provide)
  • answer is an output field (what we want back)

Think of this as: A contract that says "Give me a question, I'll give you an answer."

๐Ÿ”จ

Create a Predictor

qa = dspy.Predict(QuestionAnswer)

What's happening:

  • dspy.Predict is a module that makes predictions
  • We pass our QuestionAnswer signature to it
  • This creates a predictor that can answer questions

Think of this as: Creating a function that implements our contract.

โ–ถ๏ธ

Use It!

question = "What is the capital of France?"
result = qa(question=question)

What's happening:

  • We call our predictor like a function
  • We pass the question as a keyword argument
  • DSPy automatically generates a prompt, calls the LM, and returns the result

Think of this as: Just using the function we created!

๐Ÿ“ค

Display the Result

print(f"Answer: {result.answer}")

What's happening:

  • result is a prediction object
  • We access the answer field (from our signature)
  • DSPy has extracted this from the LM's response

Think of this as: Getting the output from our function.

โ–ถ๏ธ Running Your Program

1. Save the File

Save the code above as hello_dspy.py.

2. Ensure Your Environment is Ready

# Activate virtual environment
source venv/bin/activate

# Check .env file exists with API key
cat .env

3. Run It!

python hello_dspy.py

4. Expected Output

Question: What is the capital of France?
Answer: Paris

๐Ÿ”ฎ What's Happening Behind the Scenes?

When you run this program, DSPy:

Generates a prompt

based on your signature:

Answer questions with factual information.

---

Question: What is the capital of France?
Answer:

Calls the language model

with this prompt

Parses the response

and extracts the answer

Returns a structured result

with the answer field populated

๐Ÿ’ก

You didn't write the promptโ€”DSPy did it for you!

๐Ÿงช Experimenting

Try modifying the program to explore DSPy:

Experiment 1: Different Questions

questions = [
    "What is the capital of France?",
    "Who invented the telephone?",
    "What is 25 multiplied by 4?",
]

for question in questions:
    result = qa(question=question)
    print(f"Q: {question}")
    print(f"A: {result.answer}\n")

Experiment 2: Add Field Descriptions

class QuestionAnswer(dspy.Signature):
    """Answer questions with factual information."""
    question: str = dspy.InputField()
    answer: str = dspy.OutputField(desc="concise answer in one sentence")

The description helps guide the model's response format!

Experiment 3: Multiple Output Fields

class DetailedQA(dspy.Signature):
    """Answer questions with details."""
    question: str = dspy.InputField()
    answer: str = dspy.OutputField()
    confidence: str = dspy.OutputField(desc="high, medium, or low")
    explanation: str = dspy.OutputField(desc="brief reasoning")

Experiment 4: Use Chain of Thought

# Change one line!
qa = dspy.ChainOfThought(QuestionAnswer)

# Now it shows reasoning
result = qa(question="What is the capital of France?")
print(f"Reasoning: {result.rationale}")
print(f"Answer: {result.answer}")

Just one line change adds step-by-step reasoning!

๐Ÿ“ Understanding the Code Structure

Typical DSPy program structure:

# 1. Imports
import dspy
from dotenv import load_dotenv

# 2. Configuration
load_dotenv()
lm = dspy.LM(...)
dspy.configure(lm=lm)

# 3. Signature Definition
class MyTask(dspy.Signature):
    input_field: str = dspy.InputField()
    output_field: str = dspy.OutputField()

# 4. Module Creation
module = dspy.Predict(MyTask)

# 5. Usage
result = module(input_field="...")
print(result.output_field)

This pattern will be consistent across all DSPy programs!

๐Ÿ“ Summary

You've learned:

  • โœ… How to configure DSPy with a language model
  • โœ… How to define a signature (task specification)
  • โœ… How to create a predictor with dspy.Predict
  • โœ… How to use the predictor to generate results
  • โœ… The basic structure of DSPy programs

Key concepts:

  • Signatures define inputs and outputs
  • Modules (like Predict) implement the behavior
  • Configuration sets up the language model
  • Results are structured objects with named fields