The signature system defines the input/output structure for DSPy modules using natural language descriptions and typed fields. Signatures serve as the interface between program logic and language models, enabling type-safe and self-documenting AI operations.
Base class for defining task signatures with typed input and output fields.
class Signature:
"""
Defines input/output structure for DSPy modules.
Signatures can be created in three ways:
1. String notation: "input1, input2 -> output1, output2"
2. Class-based with field definitions
3. Dynamic creation via make_signature()
"""
instructions: str
"""Task instructions describing what the module should do."""
input_fields: dict
"""Dictionary mapping input field names to field definitions."""
output_fields: dict
"""Dictionary mapping output field names to field definitions."""
fields: dict
"""Combined dictionary of all fields (inputs + outputs)."""
def prepend(self, name: str, field, type_):
"""
Add field at the beginning of the signature.
Args:
name (str): Field name
field: Field definition
type_: Field type
"""
pass
def append(self, name: str, field, type_):
"""
Add field at the end of the signature.
Args:
name (str): Field name
field: Field definition
type_: Field type
"""
pass
def with_instructions(self, instructions: str):
"""
Create copy of signature with new instructions.
Args:
instructions (str): New task instructions
Returns:
New Signature instance with updated instructions
"""
pass
def with_updated_fields(self, name: str, **kwargs):
"""
Create copy with updated field properties.
Args:
name (str): Field name to update
**kwargs: Properties to update (desc, prefix, etc.)
Returns:
New Signature instance with updated field
"""
pass
def dump_state(self) -> dict:
"""
Serialize signature to dictionary.
Returns:
Dictionary representation of signature state
"""
pass
@staticmethod
def load_state(state: dict):
"""
Load signature from serialized state.
Args:
state (dict): Serialized signature state
Returns:
Signature instance
"""
passUsage:
import dspy
# String signature (simplest)
sig = "question -> answer"
# Class-based signature
class QASignature(dspy.Signature):
"""Answer questions with detailed reasoning."""
question: str = dspy.InputField(desc="Question to answer")
answer: str = dspy.OutputField(desc="Detailed answer")
# With custom instructions
class SummarizeSignature(dspy.Signature):
"""Summarize the given text in one sentence."""
text: str = dspy.InputField()
summary: str = dspy.OutputField(desc="One-sentence summary")
# Modify signature
new_sig = QASignature.with_instructions("Answer questions briefly.")Define input fields for signatures with descriptions, prefixes, and validation.
def InputField(
desc: str = None,
prefix: str = None,
format: callable = None,
parser: callable = None,
**kwargs
):
"""
Create an input field for signatures.
Args:
desc (str | None): Human-readable description of the field
prefix (str | None): Display prefix for the field in prompts
format (callable | None): Function to format field value for display
parser (callable | None): Function to parse field value from string
**kwargs: Additional Pydantic Field parameters (default, ge, le, etc.)
Returns:
Pydantic FieldInfo instance configured as input field
"""
passUsage:
import dspy
from pydantic import BaseModel
class QuestionAnswering(dspy.Signature):
"""Answer questions based on context."""
# Basic input field
question: str = dspy.InputField()
# Input field with description
context: str = dspy.InputField(desc="Background information")
# Input field with custom prefix
user_query: str = dspy.InputField(
prefix="Query:",
desc="User's search query"
)
# Input field with validation
temperature: float = dspy.InputField(
desc="Temperature setting",
ge=0.0,
le=2.0,
default=1.0
)
# Output field
answer: str = dspy.OutputField(desc="Answer to the question")
# With custom types
class City(BaseModel):
name: str
country: str
class CityLookup(dspy.Signature):
"""Find information about a city."""
query: str = dspy.InputField(desc="City name or description")
city: City = dspy.OutputField(desc="City information")Define output fields for signatures with descriptions and formatting.
def OutputField(
desc: str = None,
prefix: str = None,
format: callable = None,
parser: callable = None,
**kwargs
):
"""
Create an output field for signatures.
Args:
desc (str | None): Human-readable description of the field
prefix (str | None): Display prefix for the field in prompts
format (callable | None): Function to format field value for display
parser (callable | None): Function to parse field value from string
**kwargs: Additional Pydantic Field parameters
Returns:
Pydantic FieldInfo instance configured as output field
"""
passUsage:
import dspy
class MultiOutputSignature(dspy.Signature):
"""Generate multiple outputs from input."""
text: str = dspy.InputField()
# Multiple output fields
summary: str = dspy.OutputField(desc="Brief summary")
sentiment: str = dspy.OutputField(desc="Positive, negative, or neutral")
keywords: str = dspy.OutputField(desc="Comma-separated keywords")
# Output with custom prefix
confidence: float = dspy.OutputField(
prefix="Confidence Score:",
desc="Confidence from 0.0 to 1.0"
)Create signatures programmatically from string specifications or field dictionaries.
def make_signature(
signature,
instructions: str = None,
custom_types: dict = None
):
"""
Create a signature dynamically from string or dictionary.
Args:
signature (str | dict | type): Signature specification
- str: "input1, input2 -> output1, output2"
- dict: {"field_name": FieldInfo, ...}
- type: Existing Signature class
instructions (str | None): Task instructions
custom_types (dict | None): Mapping of type names to Python types
Returns:
Signature class
"""
passUsage:
import dspy
from pydantic import BaseModel
# From string
sig1 = dspy.make_signature("question -> answer")
# From string with instructions
sig2 = dspy.make_signature(
"question -> answer",
"Answer questions concisely and accurately."
)
# From string with typed fields
sig3 = dspy.make_signature("question: str, context: str -> answer: str, confidence: float")
# With custom types
class Location(BaseModel):
city: str
country: str
coordinates: tuple
sig4 = dspy.make_signature(
"query -> location: Location",
custom_types={"Location": Location}
)
# From dictionary
sig5 = dspy.make_signature(
{
"text": dspy.InputField(desc="Input text"),
"summary": dspy.OutputField(desc="Summary"),
},
instructions="Summarize the text"
)Ensure input is a valid signature, converting strings as needed.
def ensure_signature(signature):
"""
Ensure input is a valid Signature class.
Converts string specifications to Signature classes if needed.
Passes through existing Signature classes unchanged.
Args:
signature (str | type): Signature or string specification
Returns:
Signature class
"""
passUsage:
import dspy
# Ensure string becomes signature
sig = dspy.ensure_signature("question -> answer")
# Pass through existing signature
class MySignature(dspy.Signature):
question: str = dspy.InputField()
answer: str = dspy.OutputField()
sig = dspy.ensure_signature(MySignature) # Returns MySignature unchangedAutomatically generate readable prefixes from field names.
def infer_prefix(name: str) -> str:
"""
Infer a human-readable prefix from field name.
Converts snake_case and camelCase to Title Case.
Args:
name (str): Field name
Returns:
Formatted prefix string
"""
passUsage:
import dspy
# Automatically inferred prefixes
dspy.infer_prefix("question") # "Question"
dspy.infer_prefix("user_query") # "User Query"
dspy.infer_prefix("contextPassages") # "Context Passages"
# Used automatically when prefix not specified
class MySignature(dspy.Signature):
user_query: str = dspy.InputField() # Prefix: "User Query"
final_answer: str = dspy.OutputField() # Prefix: "Final Answer"Backward-compatible field definitions. Prefer InputField/OutputField for new code.
class OldField:
"""Legacy field definition (deprecated)."""
def __init__(self, desc: str = None, **kwargs):
"""
Create legacy field.
Args:
desc (str | None): Field description
**kwargs: Additional parameters
"""
pass
class OldInputField(OldField):
"""Legacy input field (deprecated)."""
pass
class OldOutputField(OldField):
"""Legacy output field (deprecated)."""
passMetaclass that handles dynamic signature creation and field processing.
class SignatureMeta(type):
"""
Metaclass for Signature class.
Handles:
- Processing field annotations
- Separating input and output fields
- Inheriting instructions and fields from parent classes
- Converting string signatures to typed signatures
"""
passSimple input-to-output transformations:
import dspy
# Single input, single output
"question -> answer"
# Multiple inputs, single output
"context, question -> answer"
# Single input, multiple outputs
"text -> summary, sentiment, keywords"
# Multiple inputs and outputs
"context, question -> answer, confidence, sources"Signatures with explicit types for validation:
import dspy
class TypedSignature(dspy.Signature):
"""Answer questions with confidence scoring."""
question: str = dspy.InputField()
context: list[str] = dspy.InputField(desc="List of context passages")
answer: str = dspy.OutputField()
confidence: float = dspy.OutputField(desc="Score from 0.0 to 1.0")
sources: list[int] = dspy.OutputField(desc="Indices of used passages")Signatures with images, audio, or other media types:
import dspy
class ImageQA(dspy.Signature):
"""Answer questions about images."""
image: dspy.Image = dspy.InputField()
question: str = dspy.InputField()
answer: str = dspy.OutputField()
class AudioTranscription(dspy.Signature):
"""Transcribe audio to text."""
audio: dspy.Audio = dspy.InputField()
transcript: str = dspy.OutputField()Signatures for chat and dialogue systems:
import dspy
class ChatSignature(dspy.Signature):
"""Generate conversational responses."""
history: dspy.History = dspy.InputField(desc="Previous messages")
message: str = dspy.InputField(desc="Current user message")
response: str = dspy.OutputField(desc="Assistant response")
class RAGChat(dspy.Signature):
"""Chat with document retrieval."""
history: dspy.History = dspy.InputField()
question: str = dspy.InputField()
context: str = dspy.InputField(desc="Retrieved passages")
response: str = dspy.OutputField()
citations: list[int] = dspy.OutputField(desc="Citation indices")Signatures with custom Pydantic models:
import dspy
from pydantic import BaseModel
class Entity(BaseModel):
name: str
type: str
confidence: float
class Relation(BaseModel):
source: str
target: str
relation_type: str
class KnowledgeExtraction(dspy.Signature):
"""Extract structured knowledge from text."""
text: str = dspy.InputField()
entities: list[Entity] = dspy.OutputField()
relations: list[Relation] = dspy.OutputField()Signatures for agents with tool access:
import dspy
class AgentSignature(dspy.Signature):
"""Agent that uses tools to answer questions."""
question: str = dspy.InputField()
available_tools: list[str] = dspy.InputField()
reasoning: str = dspy.OutputField(desc="Step-by-step reasoning")
tool_calls: dspy.ToolCalls = dspy.OutputField()
answer: str = dspy.OutputField()Signatures for generating and executing code:
import dspy
class CodeGeneration(dspy.Signature):
"""Generate Python code to solve a problem."""
problem: str = dspy.InputField()
constraints: str = dspy.InputField(desc="Code requirements")
code: dspy.Code = dspy.OutputField(desc="Python code")
explanation: str = dspy.OutputField(desc="Code explanation")
class CodeDebug(dspy.Signature):
"""Debug and fix Python code."""
code: dspy.Code = dspy.InputField()
error: str = dspy.InputField(desc="Error message")
fixed_code: dspy.Code = dspy.OutputField()
changes: str = dspy.OutputField(desc="Description of fixes")Modify signatures at runtime for dynamic behavior:
import dspy
# Base signature
class BaseQA(dspy.Signature):
question: str = dspy.InputField()
answer: str = dspy.OutputField()
# Add field at runtime
sig = BaseQA.append("confidence", dspy.OutputField(), float)
# Update instructions
sig = sig.with_instructions("Answer questions with high confidence.")
# Update field properties
sig = sig.with_updated_fields("answer", desc="Detailed answer with examples")Build on existing signatures:
import dspy
class BaseSignature(dspy.Signature):
"""Base question answering."""
question: str = dspy.InputField()
answer: str = dspy.OutputField()
class ExtendedSignature(BaseSignature):
"""Extended with confidence and reasoning."""
reasoning: str = dspy.OutputField(desc="Chain of thought")
confidence: float = dspy.OutputField()Save and load signature definitions:
import dspy
import json
# Create signature
class MySignature(dspy.Signature):
"""Custom signature."""
input: str = dspy.InputField()
output: str = dspy.OutputField()
# Serialize
state = MySignature.dump_state()
with open("signature.json", "w") as f:
json.dump(state, f)
# Load
with open("signature.json", "r") as f:
state = json.load(f)
loaded_sig = dspy.Signature.load_state(state)