
Dspy Labeled Few Shot
- 7 installs
- 11 repo stars
- Updated June 28, 2026
- lebsral/dspy-programming-not-prompting-lms-skills
Helps with ai & agent building tasks.
About
dspy-labeled-few-shot is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- dspy-labeled-few-shot
- AI & Agent Building
- AI-coding skill
Dspy Labeled Few Shot by the numbers
- 7 all-time installs (skills.sh)
- Ranked #12,545 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/lebsral/dspy-programming-not-prompting-lms-skills --skill dspy-labeled-few-shotAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 7 |
|---|---|
| repo stars | ★ 11 |
| Last updated | June 28, 2026 |
| Repository | lebsral/dspy-programming-not-prompting-lms-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Hand-Picked Demonstrations with dspy.LabeledFewShot
Guide the user through using dspy.LabeledFewShot -- the simplest DSPy optimizer. It takes labeled examples you provide and attaches them as few-shot demonstrations to your program's predictors. No bootstrapping, no metric, no LM calls during optimization.
What is LabeledFewShot
dspy.LabeledFewShot is an optimizer that takes a set of labeled training examples and injects them directly as few-shot demonstrations into every predictor in your DSPy program.
- No metric required -- unlike other optimizers, it does not evaluate or filter examples
- No LM calls during compilation -- it just copies your examples into the prompt
- Deterministic -- uses a fixed random seed (0) for reproducible example selection
- Fast -- compilation is instant because there is no search or bootstrapping step
Under the hood, compile() creates a copy of your program, iterates over each predictor, and assigns up to k examples from your training set as that predictor's demos.
When to use LabeledFewShot
Use LabeledFewShot when... | Use something else when... |
|---|---|
| You have hand-curated, high-quality examples | You want the optimizer to discover good examples (BootstrapFewShot) |
| You want a quick baseline before trying fancier optimizers | You need instruction tuning too (MIPROv2) |
| You need full control over which demonstrations the LM sees | You have enough data to let DSPy search (BootstrapFewShotWithRandomSearch) |
| Your task is simple enough that a few good examples suffice | Quality requires filtering examples by a metric |
| You want deterministic, reproducible behavior | You want the optimizer to explore different combinations |
Rule of thumb: Use LabeledFewShot as your first optimization step. If accuracy is not high enough, upgrade to BootstrapFewShot which evaluates examples against a metric and keeps only the ones that work.
API reference
Constructor
dspy.LabeledFewShot(k=16)| Parameter | Type | Default | Description |
|---|---|---|---|
k | int | 16 | Maximum number of demonstration examples to include per predictor |
compile()
optimizer.compile(student, *, trainset, sample=True)| Parameter | Type | Default | Description |
|---|---|---|---|
student | dspy.Module | required | The DSPy program to optimize |
trainset | list[dspy.Example] | required | Labeled examples to use as demonstrations |
sample | bool | True | True = randomly sample k examples; False = take the first k sequentially |
Returns: A copy of student with demonstrations attached to each predictor.
If trainset is empty, the student is returned unmodified.
Basic usage
import dspy
from typing import Literal
# Configure any LM provider
lm = dspy.LM("openai/gpt-4o-mini") # or "anthropic/claude-sonnet-4-5-20250929", etc.
dspy.configure(lm=lm)
# 1. Define your signature
class ClassifyIntent(dspy.Signature):
"""Classify the user message into an intent category."""
message: str = dspy.InputField(desc="User message")
intent: Literal["question", "complaint", "praise", "request"] = dspy.OutputField()
# 2. Build your program
classify = dspy.Predict(ClassifyIntent)
# 3. Create hand-picked training examples
trainset = [
dspy.Example(message="How do I reset my password?", intent="question").with_inputs("message"),
dspy.Example(message="This is broken and I want a refund", intent="complaint").with_inputs("message"),
dspy.Example(message="Your team was incredibly helpful!", intent="praise").with_inputs("message"),
dspy.Example(message="Please update my billing address", intent="request").with_inputs("message"),
dspy.Example(message="What formats do you export to?", intent="question").with_inputs("message"),
dspy.Example(message="The app crashes every time I open it", intent="complaint").with_inputs("message"),
]
# 4. Compile with LabeledFewShot
optimizer = dspy.LabeledFewShot(k=4)
optimized = optimizer.compile(classify, trainset=trainset)
# 5. Use the optimized program -- it now includes few-shot demos in every call
result = optimized(message="Can you send me last month's invoice?")
print(result.intent) # requestHow example selection works
When sample=True (the default):
- DSPy randomly selects
kexamples fromtrainsetusing a fixed seed (0) - Every predictor in your program gets the same set of demos
- The selection is reproducible across runs because of the fixed seed
When sample=False:
- DSPy takes the first
kexamples fromtrainsetin order - Use this when the order of your examples matters or you want exact control
If your trainset has fewer than k examples, all examples are used.
Choosing k
The k parameter controls how many demonstrations appear in the prompt.
- Smaller k (2-4): Lower token cost, faster inference. Good when your examples are diverse and high-quality.
- Larger k (8-16): More context for the LM. Good when the task has many edge cases or subtle distinctions.
- Default (16): A reasonable starting point. Reduce if you hit token limits or want faster responses.
Keep in mind that each demonstration adds tokens to every LM call. For long input/output fields, use a smaller k to stay within context limits.
Using sample=False for ordered examples
When you want precise control over which examples appear, disable sampling:
# Place your best, most representative examples first
trainset = [
dspy.Example(message="What's your return policy?", intent="question").with_inputs("message"),
dspy.Example(message="This product is defective", intent="complaint").with_inputs("message"),
dspy.Example(message="Love the new feature!", intent="praise").with_inputs("message"),
dspy.Example(message="Please cancel my subscription", intent="request").with_inputs("message"),
# ... more examples, ordered by importance
]
optimizer = dspy.LabeledFewShot(k=4)
optimized = optimizer.compile(classify, trainset=trainset, sample=False)
# The first 4 examples are used as demos, in orderSaving and loading an optimized program
After compilation, save the optimized program so you can reuse it without recompiling:
# Save
optimized.save("intent_classifier.json")
# Load later
loaded = dspy.Predict(ClassifyIntent)
loaded.load("intent_classifier.json")
result = loaded(message="How do I upgrade my plan?")Multi-predictor programs
LabeledFewShot attaches demos to every predictor in your program. This works with multi-step pipelines too:
class SupportRouter(dspy.Module):
def __init__(self):
self.classify = dspy.Predict(ClassifyIntent)
self.respond = dspy.ChainOfThought("message, intent -> response")
def forward(self, message):
intent = self.classify(message=message).intent
return self.respond(message=message, intent=intent)
router = SupportRouter()
# Both self.classify and self.respond get demos from the same trainset
optimizer = dspy.LabeledFewShot(k=3)
optimized_router = optimizer.compile(router, trainset=trainset)Note: every predictor receives demos from the same trainset. If your predictors have different signatures, make sure your training examples include all fields needed across all predictors, or consider compiling predictors separately.
When to upgrade to BootstrapFewShot
LabeledFewShot is a great starting point, but it has limitations:
1. No quality filtering -- it uses your examples as-is, even if some are misleading or ambiguous 2. No metric evaluation -- it cannot tell which examples actually help the LM perform better 3. Same demos for all predictors -- it does not tailor demonstrations per predictor
dspy.BootstrapFewShot addresses all three. It runs your program on each training example, evaluates with a metric, and keeps only the demonstrations that led to correct outputs. The upgrade is straightforward:
# Before: LabeledFewShot (no metric needed)
optimizer = dspy.LabeledFewShot(k=4)
optimized = optimizer.compile(program, trainset=trainset)
# After: BootstrapFewShot (needs a metric)
def metric(example, prediction, trace=None):
return prediction.intent == example.intent
optimizer = dspy.BootstrapFewShot(metric=metric, max_bootstrapped_demos=4)
optimized = optimizer.compile(program, trainset=trainset)Gotchas
1. Claude forgets `.with_inputs()` on training examples. Without .with_inputs("field_name"), DSPy does not know which fields are inputs vs labels. The demonstrations appear malformed in the prompt — the LM sees all fields as input, which confuses it. Always call .with_inputs() on every dspy.Example in your trainset. 2. Claude uses LabeledFewShot when the user needs metric-driven selection. LabeledFewShot uses examples as-is with no quality filtering. If the user mentions "accuracy is low" or "some examples are noisy," recommend BootstrapFewShot instead — it evaluates examples against a metric and keeps only the ones that help. 3. Claude sets `k` larger than the trainset without explaining the behavior. When k exceeds len(trainset), DSPy silently uses all available examples. This is fine, but Claude should tell the user: "You have 5 examples and k=16, so all 5 will be used as demos." 4. Claude creates separate trainsets for multi-predictor programs. LabeledFewShot assigns the same demos to every predictor. If predictors have different signatures, the examples need all fields across all signatures, or the user should compile predictors separately. Claude sometimes splits the trainset incorrectly — explain the shared-demo behavior.
Additional resources
- dspy.LabeledFewShot API docs
- For API details, see reference.md
- For worked examples, see examples.md
Cross-references
Install any skill: npx skills add lebsral/DSPy-Programming-not-prompting-LMs-skills --skill <name>- Creating training examples (dspy.Example, with_inputs, datasets) -- see
/dspy-data - Defining signatures (inline and class-based, typed fields) -- see
/dspy-signatures - BootstrapFewShot for metric-driven demo selection -- see
/ai-improving-accuracy - Evaluating your program to measure if LabeledFewShot is enough -- see
/dspy-evaluate - Building modules with multiple predictors -- see
/dspy-modules - For worked examples, see examples.md
- Install `/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-do
[
{
"prompt": "I have 10 hand-picked examples for classifying support tickets. I want to use them directly as few-shot demos without any bootstrapping. How do I set this up in DSPy?",
"expected_output": "Uses dspy.LabeledFewShot to compile the program with the curated examples as demonstrations",
"assertions": [
"Uses dspy.LabeledFewShot, not BootstrapFewShot",
"Creates dspy.Example objects with .with_inputs() to mark input fields",
"Calls optimizer.compile(program, trainset=trainset)",
"Does NOT define a metric — LabeledFewShot does not need one",
"Sets k to a reasonable value based on the number of examples"
]
},
{
"prompt": "I have a set of gold-standard examples ordered from most important to least important. I want the first 5 to always be used as demonstrations, in that exact order. How?",
"expected_output": "Uses LabeledFewShot with sample=False and k=5 to take the first 5 examples in order",
"assertions": [
"Uses dspy.LabeledFewShot(k=5)",
"Passes sample=False to compile()",
"Explains that sample=False takes the first k examples sequentially instead of random sampling"
]
},
{
"prompt": "I tried LabeledFewShot with my examples but accuracy is not good enough. What should I try next?",
"expected_output": "Recommends upgrading to BootstrapFewShot which filters examples using a metric",
"assertions": [
"Recommends dspy.BootstrapFewShot as the next step",
"Explains that BootstrapFewShot evaluates examples against a metric and keeps only the ones that work",
"Shows how to define a simple metric function",
"Shows the compile() call with metric and trainset"
]
}
]
dspy-labeled-few-shot -- Worked Examples
Example 1: Curated demos for customer support classification
Use hand-picked examples to teach the LM your company's specific classification rules. Each example demonstrates a category with a representative ticket, giving the LM clear patterns to follow.
import dspy
from typing import Literal
class ClassifyTicket(dspy.Signature):
"""Classify a customer support ticket into a department and urgency level."""
ticket: str = dspy.InputField(desc="Customer support ticket text")
department: Literal["billing", "technical", "account", "shipping", "general"] = dspy.OutputField()
urgency: Literal["low", "medium", "high", "critical"] = dspy.OutputField()
# --- Curated training examples ---
# Pick examples that cover each category and show edge cases your team
# has discussed. Quality matters more than quantity here.
trainset = [
# Billing -- clear examples of payment and invoice issues
dspy.Example(
ticket="I was charged twice for my subscription this month",
department="billing",
urgency="high",
).with_inputs("ticket"),
dspy.Example(
ticket="Can I get a copy of last quarter's invoices?",
department="billing",
urgency="low",
).with_inputs("ticket"),
# Technical -- bugs, crashes, integration problems
dspy.Example(
ticket="The API returns 500 errors whenever I send a batch request over 100 items",
department="technical",
urgency="high",
).with_inputs("ticket"),
dspy.Example(
ticket="Is there a way to export data as Parquet instead of CSV?",
department="technical",
urgency="low",
).with_inputs("ticket"),
# Account -- login, permissions, profile changes
dspy.Example(
ticket="I can't log in after resetting my password, it says account locked",
department="account",
urgency="critical",
).with_inputs("ticket"),
dspy.Example(
ticket="Please add my colleague as an admin on our team workspace",
department="account",
urgency="medium",
).with_inputs("ticket"),
# Shipping -- delivery, tracking, address changes
dspy.Example(
ticket="My order was marked delivered but I never received it",
department="shipping",
urgency="high",
).with_inputs("ticket"),
dspy.Example(
ticket="Can I change the delivery address for order #4821?",
department="shipping",
urgency="medium",
).with_inputs("ticket"),
# General -- everything else
dspy.Example(
ticket="Do you offer discounts for nonprofits?",
department="general",
urgency="low",
).with_inputs("ticket"),
dspy.Example(
ticket="What are your support hours over the holidays?",
department="general",
urgency="low",
).with_inputs("ticket"),
]
# --- Compile and use ---
lm = dspy.LM("openai/gpt-4o-mini") # or any LiteLLM-supported provider
dspy.configure(lm=lm)
classifier = dspy.Predict(ClassifyTicket)
# Use k=6 to include a good spread without overloading the prompt
optimizer = dspy.LabeledFewShot(k=6)
optimized = optimizer.compile(classifier, trainset=trainset)
# Classify new tickets
test_tickets = [
"My credit card was declined but the charge still shows as pending",
"The dashboard keeps showing a blank page on Firefox",
"I need to transfer ownership of the account to my business partner",
"When will my replacement item ship?",
]
for ticket in test_tickets:
result = optimized(ticket=ticket)
print(f"[{result.urgency}] {result.department}: {ticket}")
# Save for production use
optimized.save("ticket_classifier.json")Key points:
- Each category has at least two examples showing different urgency levels, so the LM learns both fields
- Examples are chosen to represent real ambiguous cases your team has resolved (e.g., "account locked" is critical, not just high)
k=6gives enough variety without burning too many tokens per classification callwith_inputs("ticket")marks which field is the input -- the rest are treated as labels for demonstrations- Save the compiled program so you do not need to recompile on every server restart
Example 2: Hand-picked examples for consistent formatting
Use curated demonstrations to enforce a specific output format that the LM should follow consistently. This is useful when you need structured, predictable output that matches your application's conventions.
import dspy
from pydantic import BaseModel, Field
class ChangelogEntry(BaseModel):
title: str = Field(description="Short imperative-mood title, max 60 chars")
category: str = Field(description="One of: added, changed, fixed, removed, security")
description: str = Field(description="One-sentence user-facing description")
breaking: bool = Field(description="Whether this is a breaking change")
class FormatChangelog(dspy.Signature):
"""Convert a raw git commit message into a structured changelog entry.
Use imperative mood for the title (e.g., 'Add export button' not 'Added export button').
Descriptions should be written for end users, not developers."""
commit_message: str = dspy.InputField(desc="Raw git commit message")
entry: ChangelogEntry = dspy.OutputField()
# --- Curated demonstrations ---
# These examples define the exact formatting conventions you want.
# The LM learns your style from these patterns.
trainset = [
dspy.Example(
commit_message="feat: add CSV export to the analytics dashboard\n\nUsers have been requesting CSV downloads for months. This adds an export button to the top-right of the dashboard that downloads the current filtered view.",
entry=ChangelogEntry(
title="Add CSV export to analytics dashboard",
category="added",
description="You can now export your analytics data as a CSV file directly from the dashboard.",
breaking=False,
),
).with_inputs("commit_message"),
dspy.Example(
commit_message="fix: resolve race condition in webhook delivery\n\nWebhooks were occasionally delivered out of order when multiple events fired within the same millisecond. Added a sequence counter to ensure ordering.",
entry=ChangelogEntry(
title="Fix webhook delivery ordering",
category="fixed",
description="Webhooks are now guaranteed to arrive in the correct order, even when multiple events fire simultaneously.",
breaking=False,
),
).with_inputs("commit_message"),
dspy.Example(
commit_message="BREAKING: remove legacy v1 API endpoints\n\nv1 has been deprecated since March 2024. All remaining v1 callers have been migrated. Removing to reduce maintenance burden.",
entry=ChangelogEntry(
title="Remove legacy v1 API endpoints",
category="removed",
description="The deprecated v1 API has been removed. Please use v2 endpoints instead.",
breaking=True,
),
).with_inputs("commit_message"),
dspy.Example(
commit_message="refactor: switch password hashing from bcrypt to argon2id\n\nArgon2id is the current OWASP recommendation. Existing passwords will be rehashed on next login.",
entry=ChangelogEntry(
title="Upgrade password hashing to Argon2id",
category="security",
description="Password hashing has been upgraded to Argon2id for improved security. No action required -- your password will be updated automatically on next login.",
breaking=False,
),
).with_inputs("commit_message"),
dspy.Example(
commit_message="feat: redesign settings page with tabbed navigation\n\nReplaces the long scrolling settings page with a tabbed layout. Tabs: General, Notifications, Integrations, Security, Billing.",
entry=ChangelogEntry(
title="Redesign settings page with tabbed layout",
category="changed",
description="The settings page now uses tabs for easier navigation between General, Notifications, Integrations, Security, and Billing sections.",
breaking=False,
),
).with_inputs("commit_message"),
]
# --- Compile and use ---
lm = dspy.LM("openai/gpt-4o-mini") # or any LiteLLM-supported provider
dspy.configure(lm=lm)
formatter = dspy.Predict(FormatChangelog)
# Use sample=False to include the examples in the exact order above,
# ensuring the LM sees a representative spread of categories
optimizer = dspy.LabeledFewShot(k=5)
optimized = optimizer.compile(formatter, trainset=trainset, sample=False)
# Format new commit messages
commits = [
"feat: add team-wide notification preferences\n\nAdmins can now set default notification settings for the entire team. Individual users can still override.",
"fix(auth): SSO login fails when email contains a plus sign\n\nThe email parser was treating '+' as a special character. Now properly URL-decodes before matching.",
"BREAKING: change /api/users response from array to paginated object\n\nResponses now include { data: [...], pagination: { page, per_page, total } }. Clients must update to handle the new envelope format.",
]
for commit in commits:
result = optimized(commit_message=commit)
entry = result.entry
prefix = "BREAKING: " if entry.breaking else ""
print(f"[{entry.category}] {prefix}{entry.title}")
print(f" {entry.description}")
print()
# Save for use in CI pipeline
optimized.save("changelog_formatter.json")Key points:
- Demonstrations define your formatting conventions by example -- imperative mood, user-facing language, correct categorization
sample=Falsepreserves the deliberate ordering so the LM sees one example of each category- Pydantic
BaseModeloutput ensures the LM returns structured, validated data - The
breakingboolean flag shows that demonstrations can teach nuanced classification alongside formatting - This pattern works well in CI pipelines where you need consistent, machine-readable changelog entries from raw commits
Condensed from dspy.ai/api/optimizers/LabeledFewShot. Verify against upstream for latest.
dspy.LabeledFewShot — API Reference
Constructor
dspy.LabeledFewShot(k=16)| Parameter | Type | Default | Description |
|---|---|---|---|
k | int | 16 | Maximum number of demonstration examples to include per predictor |
compile()
optimizer.compile(student, *, trainset, sample=True)| Parameter | Type | Default | Description |
|---|---|---|---|
student | dspy.Module | required | The DSPy program to optimize (a copy is made) |
trainset | list[dspy.Example] | required | Labeled examples to use as demonstrations |
sample | bool | True | True = randomly sample k examples (fixed seed 0); False = take first k in order |
Returns: A deep copy of student with up to k demonstrations attached to each predictor's demos attribute. If trainset is empty, returns the student unmodified.
Key methods
| Method | Description |
|---|---|
compile(student, *, trainset, sample=True) | Attach demos to all predictors in the student program |
get_params() | Returns list of (name, param) tuples for all named parameters |
Behavior details
- Uses
random.Random(0)for reproducible sampling whensample=True - Iterates over all
NamedPredictorsin the student and assigns the same set of demos to each - No metric is required — examples are used as-is without evaluation
- No LM calls during compilation — this is purely a data-copying step
compile()creates adeepcopyof the student before modifying it
Save / Load
# Save optimized program
optimized.save("my_program.json")
# Load later
program = dspy.Predict(MySignature)
program.load("my_program.json")