skills/dspy-signatures/SKILL.md
Use when you need to define the input/output contract for an LM call — choosing between inline and class-based signatures, adding type constraints, or using Pydantic models for structured outputs. Common scenarios - defining input and output fields for an LM call, adding type constraints to outputs, using Pydantic models for complex structured output, choosing between inline string signatures and class-based signatures, or declaring field descriptions that guide the model. Related - ai-parsing-data, ai-following-rules, dspy-predict, dspy-modules. Also used for dspy.Signature, dspy.InputField, dspy.OutputField, define LM call interface, typed outputs in DSPy, Pydantic model as signature, inline vs class signature, field descriptions in DSPy, structured output schema, input output contract for LLM, how to define DSPy signature, type hints in signatures, class-based signature DSPy.
npx skillsauth add lebsral/dspy-programming-not-prompting-lms-skills dspy-signaturesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Guide the user through defining DSPy Signatures — typed declarations of what goes into and comes out of an LM call.
Ask the user before diving in:
Then jump to the relevant section below.
A Signature declares the input/output contract for an LM call -- field names, types, and descriptions. DSPy compiles it into an optimized prompt automatically. You define the I/O spec; DSPy handles the prompting.
| Style | When to use | Example |
|-------|-------------|---------|
| Inline | Quick one-liner, 1-2 inputs, 1 output, string types | "question -> answer" |
| Class-based | Multiple fields, type constraints, descriptions, Pydantic outputs | class Classify(dspy.Signature) |
Rule of thumb: Start inline for prototyping. Switch to class-based when you need type constraints, field descriptions, or more than one output.
Inline signatures are strings with -> separating inputs from outputs: "question -> answer", "text -> label: bool". Supported type suffixes: str (default), int, float, bool, list[str].
Class-based signatures give you type constraints, field descriptions, and a docstring that acts as the task instruction. Use them when you need more than a one-liner.
Both InputField and OutputField accept these parameters:
class Example(dspy.Signature):
"""Demonstrate field options."""
# desc: describes the field to the LM (shows up in the prompt)
text: str = dspy.InputField(desc="The document to analyze")
# prefix: overrides the field label in the prompt (default is the field name)
summary: str = dspy.OutputField(prefix="Summary:")
# desc + type constraint combined
category: str = dspy.OutputField(
desc="The document category",
type_=Literal["news", "blog", "research"]
)
desc — a natural language description. Helps the LM understand what the field means. Use this when the field name alone is ambiguous.prefix — overrides the label shown in the prompt. Defaults to the field name followed by a colon.type_ — alternative way to set type constraint directly on OutputField (instead of using Python type annotation).For complex or nested structured output, use a Pydantic BaseModel as the output type. DSPy handles serialization and validation automatically.
import dspy
from pydantic import BaseModel, Field
from typing import Optional
lm = dspy.LM("openai/gpt-4o-mini") # or "anthropic/claude-sonnet-4-5-20250929", etc.
dspy.configure(lm=lm)
class LineItem(BaseModel):
description: str
quantity: int
unit_price: float
class Invoice(BaseModel):
vendor: str
date: str = Field(description="Invoice date in YYYY-MM-DD format")
total: float
items: list[LineItem]
notes: Optional[str] = None
class ParseInvoice(dspy.Signature):
"""Extract structured invoice data from the raw text."""
text: str = dspy.InputField(desc="Raw invoice text")
invoice: Invoice = dspy.OutputField(desc="Parsed invoice data")
parser = dspy.ChainOfThought(ParseInvoice)
result = parser(text="Invoice from Acme Corp, Jan 15 2025. 2x Widget ($10 each), 1x Gadget ($25). Total: $45.")
print(result.invoice.vendor) # Acme Corp
print(result.invoice.items[0]) # LineItem(description='Widget', quantity=2, unit_price=10.0)
print(result.invoice.total) # 45.0
When to use Pydantic outputs:
Optional fields for data that may not be presentThe docstring is the most important part of a class-based signature. DSPy uses it as the primary instruction to the LM.
# Vague — the LM doesn't know what "classify" means in your context
class Bad(dspy.Signature):
"""Classify the text."""
text: str = dspy.InputField()
label: str = dspy.OutputField()
# Clear — tells the LM exactly what to do
class Good(dspy.Signature):
"""Classify the customer support message into a department for routing.
Consider the primary intent, not just keywords."""
message: str = dspy.InputField(desc="Customer support message")
department: Literal["billing", "technical", "account", "general"] = dspy.OutputField()
For runtime customization without defining new classes:
# Override instructions at call time (inline signatures)
predict = dspy.Predict("question -> answer", instructions="Answer in exactly one sentence.")
# Programmatically modify a class-based signature
MySignature = MySignature.with_instructions("New instructions for this run")
# Add/remove fields dynamically
MySignature = MySignature.append("confidence", dspy.OutputField(), type_=float)
MySignature = MySignature.delete("unused_field")
DSPy also supports special input types: dspy.Image for image inputs and dspy.History for conversation history.
"question -> answer" captures your task, an inline signature is clearer and shorter. Do not over-engineer with a class when a string works.text -> summary works better than input -> output because DSPy uses field names directly in the generated prompt. Choose descriptive names.tuple() wrapping for dynamic values -- use Literal[tuple(["a", "b"])] not Literal[["a", "b"]] when constructing from a list at runtime.desc values are NOT optimized -- DSPy optimizers (GEPA, MIPROv2, COPRO) tune the Signature docstring and/or few-shot demos, but InputField(desc=...), OutputField(desc=...), and Pydantic Field(description=...) values are fixed. If your structured output task relies heavily on field descriptions for guidance, see /dspy-gepa for a workaround that flattens field descriptions into the instruction for optimization.Install any skill:
npx skills add lebsral/DSPy-Programming-not-prompting-LMs-skills --skill <name>
/dspy-predict (Predict), /dspy-chain-of-thought (ChainOfThought), /dspy-modules (custom modules)/ai-parsing-data/ai-sorting/ai-do if you do not have it — it routes any AI problem to the right skill and is the fastest way to work: npx skills add lebsral/DSPy-Programming-not-prompting-LMs-skills --skill ai-dotools
See what is happening during optimizer.compile() instead of waiting blind. Use when you want to watch optimization progress, see scores as they come in, know if your optimizer is working, check if optimization is stuck, understand why optimization is taking too long, get live progress during compile, monitor convergence, detect overfitting during optimization, interpret optimization results, or pick the right tool for watching optimization. Also used for optimizer progress bar, is my optimizer doing anything, optimization seems stuck, how long will optimization take, watch GEPA run, watch MIPROv2 run, live optimization dashboard, optimizer not improving, scores not going up, optimization taking forever, see what optimizer is doing, debug slow optimization, optimization visibility, optimizer metrics, track compile progress, optimization observability.
testing
Use when you want the highest-quality prompt optimization DSPy offers — jointly optimizes instructions and few-shot demos, with auto=light/medium/heavy presets. Common scenarios - you want the best possible accuracy from prompt optimization, jointly tuning instructions and few-shot demonstrations, using auto presets for different compute budgets, or when COPRO or BootstrapFewShot alone are not reaching your accuracy target. Related - ai-improving-accuracy, dspy-copro, dspy-bootstrap-few-shot. Also used for dspy.MIPROv2, best DSPy optimizer, highest quality optimization, auto=light medium heavy, joint instruction and demo optimization, most powerful prompt optimizer, MIPROv2 vs COPRO vs BootstrapFewShot, which optimizer should I use, state of the art prompt optimization, when to use MIPROv2, optimize both instructions and examples, heavy optimization for production, best optimizer for accuracy.
testing
Use LangWatch for DSPy auto-tracing and real-time optimizer progress. Use when you want to set up LangWatch, langwatch.dspy.init, auto-tracing DSPy, real-time optimization dashboard, optimizer progress tracking, app.langwatch.ai, or DSPy optimizer dashboard. Also used for langwatch setup, pip install langwatch, langwatch trace, optimizer progress, real-time optimization, watch optimizer run, LangWatch self-hosted, langwatch docker, langwatch vs langtrace, langwatch autotrack_dspy.
data-ai
Use when you want to optimize instructions without few-shot examples — a lightweight alternative to COPRO when you do not have or do not want to use demonstrations. Common scenarios - optimizing instructions when you do not have or do not want to use few-shot demonstrations, lightweight instruction search as a first step, tasks where examples in the prompt confuse the model, or when you want fast instruction optimization without the cost of COPRO. Related - ai-improving-accuracy, dspy-copro, dspy-miprov2. Also used for dspy.GEPA, instruction optimization without demos, lightweight prompt optimization, optimize instructions only, no few-shot examples needed, GEPA vs COPRO, quick instruction search, when demonstrations hurt performance, zero-shot optimization, instruction-only optimizer, simplest instruction tuner, fast prompt optimization, skip few-shot and just tune instructions, optimize Pydantic field descriptions, GEPA structured output, GEPA does not optimize field desc.