Chapter 3 Β· Section 2

What Are Modules?

Modules are the executable components that bring signatures to lifeβ€”they make the actual LM calls and can be composed into complex systems.

~10 min read

Module: The Execution Engine

A Module in DSPy is an executable component that takes a signature and adds behaviorβ€”like making LM calls, adding reasoning steps, or using tools.

πŸ’‘ Think of It Like a Function

If a signature is like a function declaration, a module is like the implementation:

# In regular Python:
def calculate_tax(income: float, rate: float) -> float:    # Declaration
    return income * rate                                     # Implementation

# In DSPy:
class TaxCalculation(dspy.Signature):                       # Declaration
    """Calculate the estimated tax."""
    income: float = dspy.InputField()
    tax_rate: float = dspy.InputField()
    tax_amount: float = dspy.OutputField()

calculator = dspy.Predict(TaxCalculation)                   # Implementation

The module wraps the signature and provides the execution logicβ€”how to actually call the LM and handle the response.

πŸ”§ What Modules Actually Do

When you call a module, several things happen behind the scenes:

1️⃣

Construct the Prompt

The module uses the signature to build a prompt from the docstring, field names, and descriptions.

2️⃣

Add Module-Specific Behavior

Depending on the module type, it may add reasoning steps, tool calls, or multiple attempts.

3️⃣

Call the Language Model

The complete prompt is sent to the configured LM (GPT-4, Claude, Llama, etc.).

4️⃣

Parse and Return Results

The LM's response is parsed according to the output fields and returned as a structured object.

πŸ“ Basic Example

Here's the simplest possible module usage:

import dspy

# 1. Configure LM
lm = dspy.LM("openai/gpt-4o-mini")
dspy.configure(lm=lm)

# 2. Define a signature
class Summarize(dspy.Signature):
    """Create a brief summary of the text."""
    text: str = dspy.InputField()
    summary: str = dspy.OutputField()

# 3. Create a module from the signature
summarizer = dspy.Predict(Summarize)

# 4. Call the module
result = summarizer(text="DSPy is a framework for programming language models...")

# 5. Access the output
print(result.summary)
πŸ’‘

Key insight: The module is callable! Just pass the input fields as keyword arguments and access outputs as attributes.

πŸ—‚οΈ Types of Modules

DSPy provides several built-in modules, each adding different behavior:

Module Behavior Best For
dspy.Predict Direct LM call, no additional steps Simple tasks, fast responses
dspy.ChainOfThought Adds reasoning before answering Complex reasoning, math, analysis
dspy.ProgramOfThought Generates and executes code Computational tasks, calculations
dspy.ReAct Uses tools with observation loops Tool use, external APIs, search
dspy.Module Base class for custom modules Complex pipelines, custom logic

πŸ”„ Same Signature, Different Modules

One powerful aspect of DSPy is that you can use the same signature with different modules to get different behaviors:

class MathProblem(dspy.Signature):
    """Solve the math problem."""
    problem: str = dspy.InputField()
    answer: str = dspy.OutputField()

# Same signature, different modules:

# Quick answer (might make mistakes)
quick_solver = dspy.Predict(MathProblem)

# With reasoning (more accurate)
reasoning_solver = dspy.ChainOfThought(MathProblem)

# With code execution (precise calculations)
code_solver = dspy.ProgramOfThought(MathProblem)

Comparing the Results

problem = "What is 847 * 293?"

# Quick answer
result1 = quick_solver(problem=problem)
print(f"Predict: {result1.answer}")

# With reasoning
result2 = reasoning_solver(problem=problem)
print(f"Reasoning: {result2.rationale}")  # Shows work
print(f"Answer: {result2.answer}")

# With code
result3 = code_solver(problem=problem)
print(f"Code: {result3.answer}")  # 248,171 (exact)

πŸ›οΈ The Module Hierarchy

All DSPy modules inherit from dspy.Module:

dspy.Module
β”œβ”€β”€ dspy.Predict              # Basic prediction
β”œβ”€β”€ dspy.ChainOfThought       # Adds reasoning
β”œβ”€β”€ dspy.ChainOfThoughtWithHint  # CoT with hints
β”œβ”€β”€ dspy.ProgramOfThought     # Code generation
β”œβ”€β”€ dspy.ReAct                # Tool use
β”œβ”€β”€ dspy.MultiChainComparison # Multiple reasoning chains
└── YourCustomModule          # Your own modules!

Because they all share the same base class, they can:

βœ…

Be Composed Together

Use multiple modules in sequence within a custom module.

βœ…

Track Parameters

DSPy automatically tracks all sub-modules for optimization.

βœ…

Be Optimized

Optimizers can improve prompts across all modules uniformly.

πŸ“ Key Takeaways

Modules execute signatures β€” they're the "how" to signatures' "what"

Different modules add different behaviors (reasoning, code, tools)

Same signature, different modules = different capabilities

Modules are callable β€” pass inputs, get outputs

All modules inherit from dspy.Module and can be composed