A declarative specification of input/output behavior of a DSPy module. They tell the LM what to do, not how to do it.
Function Signatures: describe input/output types.
DSPy Signatures: declare + initialize behavior.
Field names in DSPy signatures are semantically meaningful. They define the roles of inputs and outputs.
# Example semantic roles
"question" != "answer"
"sql_query" != "python_code"
"document" != "summary"
- Modular and clean code
- LM calls optimized into high-quality prompts or finetunes
- Adaptive, reproducible behavior
- DSPy compiler handles prompt/finetune optimization
- Often leads to better prompts than human-written ones
DSPy optimizers can try more configurations and tune metrics directly for better results.
Signatures can be short strings with argument names and optional types.
# Question Answering
signature_qa = "question -> answer"
# Sentiment Classification (default type is str)
signature_sentiment = "sentence -> sentiment: bool"
# Summarization
signature_summary = "document -> summary"
Signatures can include multiple input/output fields with specific types.
# Retrieval-Augmented QA
rag_signature = "context: list[str], question: str -> answer: str"
# Multiple-Choice QA with Reasoning
mcqa_signature = "question, choices: list[str] -> reasoning: str, selection: int"
Use the instructions keyword argument for runtime variable instructions.
import dspy
# Define a toxicity classifier with instructions
toxicity = dspy.Predict(
dspy.Signature(
"comment -> toxic: bool",
instructions=(
"Mark as 'toxic' if the comment includes insults, "
"harassment, or sarcastic derogatory remarks."
),
)
)
# Example usage
comment = "you are beautiful."
result = toxicity(comment=comment).toxic
print(f"Comment: '{comment}'\nToxic: {result}")
# Expected: Toxic: False
An example using the inline signature for sentiment classification.
import dspy
# Assume dspy.LM is configured
# dspy.configure(lm=dspy.OpenAI(model='gpt-3.5-turbo'))
sentence = "it's a charming and often affecting journey."
# Define and use the classifier
classify = dspy.Predict('sentence -> sentiment: bool')
sentiment_result = classify(sentence=sentence).sentiment
print(f"Sentence: '{sentence}'")
print(f"Sentiment: {sentiment_result}")
# Expected: Sentiment: True
Using dspy.ChainOfThought which expands the signature with a reasoning field.
import dspy
# Assume dspy.LM is configured
# dspy.configure(lm=dspy.OpenAI(model='gpt-3.5-turbo'))
document = """The 21-year-old made seven appearances for the Hammers and netted his
only goal for them in a Europa League qualification round match against Andorran
side FC Lustrains last season. Lee had two loan spells in League One last term,
with Blackpool and then Colchester United. He scored twice for the U's but was
unable to save them from relegation. The length of Lee's contract with the
promoted Tykes has not been revealed. Find all the latest football transfers on
our dedicated page."""
summarize = dspy.ChainOfThought('document -> summary')
response = summarize(document=document)
print("--- Summary ---")
print(response.summary)
# Possible Output: The 21-year-old Lee made seven appearances...
dspy.ChainOfThought automatically adds a reasoning field for the LM's thought process.
import dspy
# Assume 'response' is from the previous Summarization Example
# print(response.summary)
# Access the reasoning field
# Needs a model configured to support ChainOfThought (e.g., GPT-3.5/4)
print("\n--- Reasoning ---")
# Example reasoning from the previous summarization output
print("Reasoning:", response.reasoning)
# Possible Output: Reasoning: We need to highlight Lee's performance for West Ham...
For advanced tasks needing more verbosity.
Inherit from dspy.Signature and use a docstring for task clarification.
import dspy
from typing import Literal
class CustomSignature(dspy.Signature):
"""Clarify the overall task here."""
input_field: str
output_field: bool
Use dspy.InputField and dspy.OutputField to provide hints (desc) and constraints.
import dspy
from typing import Literal
class AdvancedSignature(dspy.Signature):
"""An example signature with descriptions."""
question: str = dspy.InputField(desc="The user's query.")
result: Literal['A', 'B'] = dspy.OutputField(
desc="Choose A or B based on the question."
)
Example using Literal for constrained output types.
import dspy
from typing import Literal
# Assume dspy.LM is configured
# dspy.configure(lm=dspy.OpenAI(model='gpt-3.5-turbo'))
class Emotion(dspy.Signature):
"""Classify emotion."""
sentence: str = dspy.InputField()
sentiment: Literal['sadness', 'joy', 'love', 'anger', 'fear', 'surprise'] = dspy.OutputField()
sentence = "i started feeling a little vulnerable when the giant spotlight started blinding me"
# Define and use the classifier
classify = dspy.Predict(Emotion)
prediction = classify(sentence=sentence)
print(f"Sentence: '{sentence}'")
print(f"Predicted emotion: {prediction.sentiment}")
# Possible Output: Predicted emotion: fear
A more complex example evaluating if text is faithful to provided context, extracting evidence.
import dspy
# Assume dspy.LM is configured
# dspy.configure(lm=dspy.OpenAI(model='gpt-3.5-turbo'))
class CheckCitationFaithfulness(dspy.Signature):
"""Verify that the text is based on the provided context."""
context: str = dspy.InputField(desc="facts here are assumed to be true")
text: str = dspy.InputField()
faithfulness: bool = dspy.OutputField()
evidence: dict[str, list[str]] = dspy.OutputField(desc="Supporting evidence for claims")
context = "The 21-year-old made seven appearances for the Hammers and netted his only goal for them in a Europa League qualification round match against Andorran side FC Lustrains last season. Lee had two loan spells in League One last term, with Blackpool and then Colchester United. He scored twice for the U's but was unable to save them from relegation."
text = "Lee scored 3 goals for Colchester United."
faithfulness_checker = dspy.ChainOfThought(CheckCitationFaithfulness)
result = faithfulness_checker(context=context, text=text)
print(f"Text: '{text}'")
print(f"Faithful: {result.faithfulness}")
print(f"Reasoning: {result.reasoning}")
print(f"Evidence: {result.evidence}")
# Possible Output: Faithful: False, Reasoning: '...text states Lee scored 3 goals... context states 'He scored twice'....'
Using dspy.Image for multi-modal tasks.
import dspy
# Assume dspy.LM is configured for multi-modal tasks (e.g., GPT-4o, LLaVA)
# dspy.configure(lm=dspy.OpenAI(model='gpt-4o'))
class DogPictureSignature(dspy.Signature):
"""Output the dog breed of the dog in the image."""
image_1: dspy.Image = dspy.InputField(desc="An image of a dog")
answer: str = dspy.OutputField(desc="The dog breed of the dog in the image")
image_url = "https://picsum.photos/id/237/200/300" # A random image URL, likely a dog pic
# or will generate a generic answer.
# Actual dog image should be used for best results.
classify_dog = dspy.Predict(DogPictureSignature)
prediction_dog = classify_dog(image_1=dspy.Image.from_url(image_url))
print(f"Image URL: {image_url}")
print(f"Predicted breed: {prediction_dog.answer}")
# Possible Output: Predicted breed: Labrador Retriever (depends on image content)
DSPy signatures support a wide range of types for robust and clear definitions.
str, int, bool, floatlist[str], dict[str, int], Optional[float], Union[str, int]BaseModel classesdspy.Image, dspy.HistoryMyContainer.Query)Define Pydantic models for structured input/output types.
import dspy
import pydantic
# Simple custom type
class QueryResult(pydantic.BaseModel):
text: str
score: float
# Signature using a custom type
signature_simple_custom = dspy.Signature("query: str -> result: QueryResult")
print(f"Simple Custom Type Signature: {signature_simple_custom}")
# Nested custom types using dot notation
class MyContainer:
class Query(pydantic.BaseModel):
text: str
class Score(pydantic.BaseModel):
score: float
signature_nested_custom = dspy.Signature("query: MyContainer.Query -> score: MyContainer.Score")
print(f"Nested Custom Type Signature: {signature_nested_custom}")
Signatures are the building blocks for more complex DSPy pipelines.
DSPy enables you to define behavior once and let the compiler handle efficient execution.