DSPyDSPy 3.3 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
24 small wins to finish your pathNext lesson

Your own modules: steps in plain Python

A dspy.Module is a class whose forward method calls other modules with ordinary Python. DSPy finds the predictors inside, so an optimizer can tune them.

Example
class Desk(dspy.Module):
    def __init__(self):
        super().__init__()
        self.triage = dspy.Predict(Triage)
        self.reply = dspy.Predict("ticket, category -> reply")

    def forward(self, ticket):
        category = self.triage(ticket=ticket).category
        reply = self.reply(ticket=ticket, category=category).reply
        return dspy.Prediction(category=category, reply=reply)

Sub-modules are created in __init__ and used in forward. Here the ticket is sorted first, and the category is passed to a second step that writes the reply. forward returns a Prediction with whatever fields the caller needs.

Example
desk = Desk()
result = desk(ticket="My parcel never arrived")
print(result.category)
print(result.reply)

You call the module, not forward: desk(ticket=...) runs forward inside DSPy's bookkeeping, which records usage and calls callbacks. Calling desk.forward(...) directly skips it.

Example
for name, predictor in desk.named_predictors():
    print(name, "->", predictor.signature.signature)

named_predictors walks the attributes and finds every Predict, including the one inside a ChainOfThought. Optimizers use exactly this to decide what to change. Assigning a module to self is all it takes to register it.

Any Python in between

forward is normal code: loops, if statements, calls to a database or an API. A ticket sorted as account could skip the reply step and go straight to a person. DSPy only needs the model calls to go through modules.

Try it yourself
  • Skip the reply step when the category is account, and return reply=None.
  • Replace self.triage with dspy.ChainOfThought(Triage) and print named_predictors again.
  • Call desk.forward(ticket=...) and compare.

Slow is fine. Stopping is the only problem.