
Dspy Bootstrap Finetune
- 5 installs
- 11 repo stars
- Updated June 28, 2026
- lebsral/dspy-programming-not-prompting-lms-skills
Helps with ai & agent building tasks.
About
dspy-bootstrap-finetune is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- dspy-bootstrap-finetune
- AI & Agent Building
- AI-coding skill
Dspy Bootstrap Finetune by the numbers
- 5 all-time installs (skills.sh)
- Ranked #13,065 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-bootstrap-finetuneAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5 |
|---|---|
| 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
Fine-Tune LM Weights with dspy.BootstrapFinetune
Guide the user through using DSPy's BootstrapFinetune optimizer to automatically generate training data from successful reasoning traces and fine-tune a language model's weights. This is the heaviest optimization DSPy offers -- it changes the model itself, not just the prompt.
What is BootstrapFinetune
dspy.BootstrapFinetune is an optimizer that tunes LM weights rather than prompts. It works in two phases:
1. Bootstrap: Run your program on every training example, keep the traces where your metric passes. 2. Fine-tune: Send those successful traces to the model provider's fine-tuning API (or a local training loop) and train the model weights on them.
The result is a version of your program backed by a fine-tuned model that has internalized the reasoning patterns from the bootstrapped traces.
Training examples ──> Run program ──> Keep passing traces ──> Fine-tune model weightsWhen to use BootstrapFinetune
Use it when:
- You have 500+ labeled examples (1000+ is better -- more data means more successful traces to train on)
- You have already tried prompt optimization (MIPROv2, BootstrapFewShot) and hit a quality ceiling
- You want a smaller, cheaper model to match the quality of a larger one (model distillation)
- You need maximum quality and are willing to pay the one-time cost of fine-tuning
- Your domain has specialized patterns that the base model doesn't handle well out of the box
Do not use it when:
- You have fewer than 500 examples -- use
/ai-improving-accuracywith MIPROv2 or BootstrapFewShot instead - You haven't tried prompt optimization yet -- start there, it's 10x cheaper
- Your baseline accuracy is below 50% -- fix your task definition or data first
- You're still iterating on what the task is -- fine-tuning locks you into a specific behavior
- You don't have a clear, automated metric -- you can't filter traces without one
Basic usage
import dspy
lm = dspy.LM("openai/gpt-4o-mini") # or "anthropic/claude-sonnet-4-5-20250929", etc.
dspy.configure(lm=lm)
# 1. Define your program
class Classify(dspy.Signature):
"""Classify the support ticket category."""
text: str = dspy.InputField()
category: str = dspy.OutputField()
program = dspy.ChainOfThought(Classify)
# 2. Prepare labeled data (500+ examples)
trainset = [
dspy.Example(text="Can't log in", category="auth").with_inputs("text"),
dspy.Example(text="Charge me twice", category="billing").with_inputs("text"),
# ... 500+ examples
]
# 3. Define a metric
def metric(example, prediction, trace=None):
return prediction.category.lower() == example.category.lower()
# 4. Fine-tune
optimizer = dspy.BootstrapFinetune(metric=metric, num_threads=24)
finetuned = optimizer.compile(program, trainset=trainset)
# 5. Use the fine-tuned program
result = finetuned(text="My payment failed")
print(result.category)After compile finishes, finetuned is a copy of your program that uses the newly fine-tuned model. Every module in the program that was backed by a fine-tunable LM gets updated.
Teacher-student paradigm
The most powerful pattern: use an expensive, high-quality model (the teacher) to generate traces, then fine-tune a cheap model (the student) on those traces. This is model distillation.
# --- Teacher: expensive model, high quality ---
teacher_lm = dspy.LM("openai/gpt-4o") # or any strong model
dspy.configure(lm=teacher_lm)
teacher = dspy.ChainOfThought(Classify)
# Optionally optimize the teacher's prompts first for even better traces
prompt_optimizer = dspy.MIPROv2(metric=metric, auto="medium")
teacher_optimized = prompt_optimizer.compile(teacher, trainset=trainset)
# --- Student: cheap model, fine-tuned on teacher's traces ---
student_lm = dspy.LM("openai/gpt-4o-mini") # or any fine-tunable model
dspy.configure(lm=student_lm)
student = dspy.ChainOfThought(Classify)
ft_optimizer = dspy.BootstrapFinetune(metric=metric, num_threads=24)
student_finetuned = ft_optimizer.compile(
student,
trainset=trainset,
teacher=teacher_optimized, # Teacher generates the traces
)How it works with a teacher:
1. The teacher program runs on each training example using the expensive model 2. Only traces where the metric passes are kept 3. Those traces are reformatted as training data for the student model 4. The student model is fine-tuned on the teacher's successful reasoning patterns
The student learns to mimic the teacher's reasoning at a fraction of the inference cost.
Target model configuration
BootstrapFinetune fine-tunes whatever LM is configured when you call compile. To control which model gets fine-tuned:
# Fine-tune GPT-4o-mini
student_lm = dspy.LM("openai/gpt-4o-mini") # or any fine-tunable model
dspy.configure(lm=student_lm)
finetuned = optimizer.compile(student, trainset=trainset)
# Fine-tune an open-source model via Together AI
student_lm = dspy.LM("together_ai/meta-llama/Llama-3-70b-chat-hf") # or any fine-tunable model
dspy.configure(lm=student_lm)
finetuned = optimizer.compile(student, trainset=trainset)The model must support fine-tuning through its provider's API. Common options:
| Provider | Fine-tunable models | Notes |
|---|---|---|
| OpenAI | gpt-4o-mini, gpt-4o | Easiest setup, DSPy handles the API calls |
| Together AI | Llama, Mistral, etc. | Open-source models, competitive pricing |
| Local | Any HuggingFace model | Full control, needs GPU(s) |
Key parameters
dspy.BootstrapFinetune(
metric=None, # Scoring function: (example, prediction, trace) -> bool/float
multitask=True, # Share training data across predictors
train_kwargs=None, # Fine-tuning hyperparams (e.g., {"n_epochs": 2})
exclude_demos=False, # Clear few-shot demos after fine-tuning
num_threads=None, # Parallel threads for bootstrapping
)| Parameter | Type | Default | Description |
|---|---|---|---|
metric | `Callable \ | None` | None |
multitask | bool | True | When True, shares training data across predictors. When False, each predictor gets its own fine-tuning data. |
train_kwargs | `dict \ | None` | None |
exclude_demos | bool | False | If True, clears few-shot demos after fine-tuning (the model has internalized them). |
num_threads | `int \ | None` | None |
The compile method accepts:
optimizer.compile(
student, # Your dspy.Module to fine-tune
trainset, # List of dspy.Example with labeled data
teacher=None, # Optional: a teacher program for distillation
)| Parameter | Type | Default | Description |
|---|---|---|---|
student | dspy.Module | required | The program whose backing LM will be fine-tuned |
trainset | list[dspy.Example] | required | Labeled training data (500+ recommended) |
teacher | `dspy.Module \ | None` | None |
Computational cost
BootstrapFinetune is the most expensive optimizer in DSPy. Budget for three cost stages:
1. Bootstrapping (LM API calls)
Every training example gets run through your program (or the teacher). With 1000 examples and a ChainOfThought module, that's 1000+ LM calls just for bootstrapping.
- With teacher (GPT-4o): ~$5-15 for 1000 examples (depends on input/output length)
- Without teacher (GPT-4o-mini): ~$0.15-0.50 for 1000 examples
2. Fine-tuning (provider charges)
The model provider charges for training. Costs depend on the number of successful traces and their length.
- OpenAI GPT-4o-mini: ~$0.008/1K training tokens
- OpenAI GPT-4o: ~$0.025/1K training tokens
- Together AI: Varies by model, generally cheaper for open-source
3. Inference (ongoing)
Fine-tuned models may cost slightly more per token than base models (OpenAI charges ~1.5x for fine-tuned inference). But if you distilled from GPT-4o to GPT-4o-mini, the net savings are still 10-30x.
Time
- Bootstrapping: minutes to an hour (depends on dataset size and thread count)
- Fine-tuning: 30 minutes to several hours (depends on provider and dataset size)
- Total: plan for 1-4 hours end to end
When to use BootstrapFinetune vs prompt optimization
| Factor | Prompt optimization (MIPROv2) | BootstrapFinetune |
|---|---|---|
| What it changes | Prompt instructions + few-shot examples | Model weights |
| Data needed | ~200 examples | ~500+ examples |
| Cost | Low (just LM calls for optimization) | High (LM calls + fine-tuning fees) |
| Time | Minutes | Hours |
| Quality ceiling | Good, but limited by what prompts can do | Higher -- model learns domain patterns |
| Portability | Optimized prompts work with any model | Weights are locked to one model |
| Iteration speed | Fast -- re-optimize in minutes | Slow -- re-train takes hours |
| Best for | Early development, quick iteration | Production, maximum quality, cost reduction via distillation |
Recommended progression:
1. Start with dspy.BootstrapFewShot (quick, ~50 examples) 2. Graduate to dspy.MIPROv2 (better, ~200 examples) 3. Use dspy.BootstrapFinetune when prompt optimization plateaus (500+ examples) 4. Try dspy.BetterTogether for absolute maximum quality (combines prompt + weight optimization)
Save and load
# Save the fine-tuned program
finetuned.save("finetuned_classify.json")
# Load later for production
from my_module import MyProgram
production = MyProgram()
production.load("finetuned_classify.json")
result = production(text="New ticket text...")The saved file stores the fine-tuned model identifier (e.g., ft:gpt-4o-mini-2024-07-18:org::abc123) so loading automatically points to the right model.
Troubleshooting
Not enough successful traces
If only a small fraction of training examples produce passing traces, the fine-tuning data will be thin.
Fixes:
- Use a stronger teacher model (GPT-4o instead of GPT-4o-mini)
- Relax your metric temporarily (accept partial credit during bootstrapping)
- Simplify your task or break multi-step programs into single steps
- Add more training examples so even a low success rate yields enough traces
Overfitting (high train accuracy, low test accuracy)
Fixes:
- Add more training data
- Reduce fine-tuning epochs (if your provider exposes this setting)
- Use a larger base model (less prone to memorization)
- Simplify output format
Fine-tuning didn't beat prompt optimization
Fixes:
- Verify bootstrapping produced 200+ successful traces (check logs)
- Try
dspy.BetterTogetherto combine prompt and weight optimization - Confirm your metric correlates with actual quality
- Try a different base model
Gotchas
- Claude skips prompt optimization and jumps straight to fine-tuning. Fine-tuning is the heaviest, most expensive optimization in DSPy. Always try
BootstrapFewShotandMIPROv2first — they are 10-100x cheaper and often close the gap enough. Fine-tune only when prompt optimization plateaus. - Claude forgets to set `dspy.configure(lm=student_lm)` before calling `compile`. BootstrapFinetune fine-tunes whatever LM is configured at compile time. If the teacher LM is still configured, the optimizer fine-tunes the expensive model instead of the cheap student. Always switch to the student LM before calling
compile. - Claude sets `num_threads` too low for multi-predictor programs.
num_threadsmust be >= the number of fine-tuning jobs (one per unique LM across all predictors). If a program has 3 predictors all using the same LM, that is 1 job. If each uses a different LM, that is 3 jobs. BootstrapFinetune raises aValueErrorif threads are insufficient. - Claude does not set `exclude_demos=True` after fine-tuning. Once the model weights have internalized the reasoning patterns, few-shot demos in the prompt are redundant and waste tokens. Set
exclude_demos=Trueto remove them automatically, reducing prompt length and inference cost. - Claude uses BootstrapFinetune with fewer than 200 successful traces. The optimizer only keeps traces where the metric passes. If your dataset is 500 examples but only 20% pass, you get ~100 traces — too few for effective fine-tuning. Check your metric pass rate first and use a stronger teacher or relax the metric to get 200+ passing traces.
Additional resources
- dspy.BootstrapFinetune API docs
- reference.md — constructor parameters, compile() method, fine-tuning hyperparameters
- examples.md — teacher-student distillation, production cost reduction workflow
Cross-references
Install any skill: npx skills add lebsral/DSPy-Programming-not-prompting-LMs-skills --skill <name>- BootstrapFewShot for lighter optimization without fine-tuning -- see
/ai-improving-accuracy - Fine-tuning workflow for the full decision framework, prerequisites, and BetterTogether -- see
/ai-fine-tuning - Cost reduction for distillation and other strategies to cut API spend -- see
/ai-cutting-costs - For worked examples (distillation, production cost reduction), 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 a classifier running on GPT-4o that costs too much in production. I have 800 labeled examples. How do I fine-tune GPT-4o-mini to get similar quality at lower cost?",
"expected_output": "Uses dspy.BootstrapFinetune with teacher-student distillation pattern",
"assertions": [
"Uses dspy.BootstrapFinetune (not BootstrapFewShot or MIPROv2)",
"Sets up a teacher model (GPT-4o) and student model (GPT-4o-mini)",
"Calls dspy.configure(lm=student_lm) before optimizer.compile()",
"Passes teacher to compile(): optimizer.compile(student, trainset=trainset, teacher=teacher)",
"Shows how to save the fine-tuned program for production use"
]
},
{
"prompt": "Should I use BootstrapFinetune or MIPROv2? I have 150 labeled examples and want better accuracy.",
"expected_output": "Recommends MIPROv2 first since 150 examples is too few for fine-tuning",
"assertions": [
"Recommends MIPROv2 or BootstrapFewShot over BootstrapFinetune for 150 examples",
"Explains that BootstrapFinetune needs 500+ examples for effective fine-tuning",
"Suggests trying prompt optimization first since it is cheaper and faster",
"Does NOT set up BootstrapFinetune with only 150 examples"
]
},
{
"prompt": "My BootstrapFinetune run only produced 50 successful traces from 600 examples. The fine-tuned model is barely better than baseline. What went wrong?",
"expected_output": "Diagnoses low trace pass rate and suggests fixes",
"assertions": [
"Identifies low metric pass rate as the problem — 50 traces is too few for effective fine-tuning",
"Suggests using a stronger teacher model to generate higher-quality traces",
"May suggest relaxing the metric temporarily during bootstrapping",
"May suggest adding more training data so even a low pass rate yields enough traces"
]
}
]
dspy-bootstrap-finetune -- Worked Examples
Example 1: Fine-tuning a small model from a large teacher
Distill a GPT-4o teacher into a GPT-4o-mini student for a sentiment classification task. The teacher generates high-quality reasoning traces, and the student learns to replicate them at 1/30th the inference cost.
import dspy
from dspy.evaluate import Evaluate
# --- Define the task ---
class SentimentClassify(dspy.Signature):
"""Classify the sentiment of a product review."""
review: str = dspy.InputField(desc="Product review text")
sentiment: str = dspy.OutputField(desc="positive, negative, or neutral")
def metric(example, prediction, trace=None):
return prediction.sentiment.strip().lower() == example.sentiment.strip().lower()
# --- Prepare data ---
# In practice, load from a file or database. Need 500+ examples.
import json
with open("reviews_labeled.json") as f:
raw = json.load(f)
examples = [
dspy.Example(review=r["review"], sentiment=r["sentiment"]).with_inputs("review")
for r in raw
]
# Split: 80% train, 10% dev, 10% test
n = len(examples)
trainset = examples[: int(n * 0.8)]
devset = examples[int(n * 0.8) : int(n * 0.9)]
testset = examples[int(n * 0.9) :]
print(f"Train: {len(trainset)}, Dev: {len(devset)}, Test: {len(testset)}")
evaluator = Evaluate(devset=devset, metric=metric, num_threads=4, display_progress=True)
# --- Step 1: Build and optimize the teacher ---
teacher_lm = dspy.LM("openai/gpt-4o") # or any strong model
dspy.configure(lm=teacher_lm)
teacher = dspy.ChainOfThought(SentimentClassify)
# Optimize the teacher's prompts first for higher-quality traces
prompt_optimizer = dspy.MIPROv2(metric=metric, auto="medium")
teacher_optimized = prompt_optimizer.compile(teacher, trainset=trainset)
teacher_score = evaluator(teacher_optimized)
print(f"Teacher (GPT-4o, prompt-optimized): {teacher_score:.1f}%")
# --- Step 2: Measure the untuned student baseline ---
student_lm = dspy.LM("openai/gpt-4o-mini") # or any fine-tunable model
dspy.configure(lm=student_lm)
student_baseline = dspy.ChainOfThought(SentimentClassify)
baseline_score = evaluator(student_baseline)
print(f"Student baseline (GPT-4o-mini, no tuning): {baseline_score:.1f}%")
# --- Step 3: Fine-tune the student on the teacher's traces ---
student = dspy.ChainOfThought(SentimentClassify)
ft_optimizer = dspy.BootstrapFinetune(metric=metric, num_threads=24)
student_finetuned = ft_optimizer.compile(
student,
trainset=trainset,
teacher=teacher_optimized,
)
finetuned_score = evaluator(student_finetuned)
print(f"Student fine-tuned (GPT-4o-mini, distilled): {finetuned_score:.1f}%")
# --- Step 4: Compare all three on the held-out test set ---
test_evaluator = Evaluate(
devset=testset, metric=metric, num_threads=4, display_progress=True
)
print("\n--- Test set results ---")
print(f"Teacher (GPT-4o): {test_evaluator(teacher_optimized):.1f}%")
print(f"Student baseline (GPT-4o-mini): {test_evaluator(student_baseline):.1f}%")
print(f"Student fine-tuned (GPT-4o-mini): {test_evaluator(student_finetuned):.1f}%")
# --- Step 5: Save for production ---
student_finetuned.save("sentiment_finetuned.json")Key points:
- The teacher is prompt-optimized with MIPROv2 before distillation -- better teacher traces lead to a better student
- The student baseline (untuned GPT-4o-mini) gives you a floor to measure improvement against
- Always evaluate on a held-out test set, not the dev set you used during optimization
- The fine-tuned student typically retains 90-95% of teacher quality at a fraction of the cost
- The saved program file stores the fine-tuned model ID, so loading it later automatically uses the right model
Example 2: Production cost reduction via fine-tuning
Take a working production system that uses an expensive model and reduce costs by fine-tuning a cheaper model to replace it. This example shows the full workflow from measuring the current system to deploying the fine-tuned replacement.
import dspy
from dspy.evaluate import Evaluate
# --- The existing production system ---
# Assume this is already running in production with GPT-4o
class ExtractOrderInfo(dspy.Signature):
"""Extract structured order information from a customer message."""
message: str = dspy.InputField(desc="Customer support message")
order_id: str = dspy.OutputField(desc="Order ID mentioned, or 'none'")
issue_type: str = dspy.OutputField(desc="return, shipping, damage, billing, other")
urgency: str = dspy.OutputField(desc="low, medium, high")
expensive_lm = dspy.LM("openai/gpt-4o") # or any strong model
dspy.configure(lm=expensive_lm)
production_program = dspy.ChainOfThought(ExtractOrderInfo)
# --- Metric: all three fields must match ---
def metric(example, prediction, trace=None):
order_match = prediction.order_id.strip().lower() == example.order_id.strip().lower()
issue_match = prediction.issue_type.strip().lower() == example.issue_type.strip().lower()
urgency_match = prediction.urgency.strip().lower() == example.urgency.strip().lower()
return order_match and issue_match and urgency_match
# --- Collect labeled data from production logs ---
# In practice, export from your logging system. You need 500+ labeled examples.
import json
with open("support_messages_labeled.json") as f:
raw = json.load(f)
examples = [
dspy.Example(
message=r["message"],
order_id=r["order_id"],
issue_type=r["issue_type"],
urgency=r["urgency"],
).with_inputs("message")
for r in raw
]
n = len(examples)
trainset = examples[: int(n * 0.8)]
devset = examples[int(n * 0.8) : int(n * 0.9)]
testset = examples[int(n * 0.9) :]
evaluator = Evaluate(devset=devset, metric=metric, num_threads=4, display_progress=True)
test_evaluator = Evaluate(devset=testset, metric=metric, num_threads=4, display_progress=True)
# --- Step 1: Measure current production quality ---
production_score = evaluator(production_program)
print(f"Current production (GPT-4o): {production_score:.1f}%")
# --- Step 2: Check how much quality we lose with the cheap model ---
cheap_lm = dspy.LM("openai/gpt-4o-mini") # or any fine-tunable model
dspy.configure(lm=cheap_lm)
cheap_baseline = dspy.ChainOfThought(ExtractOrderInfo)
cheap_score = evaluator(cheap_baseline)
print(f"Cheap baseline (GPT-4o-mini, no tuning): {cheap_score:.1f}%")
# --- Step 3: Fine-tune the cheap model using production system as teacher ---
# Switch back to expensive LM for generating teacher traces
dspy.configure(lm=expensive_lm)
# Optionally prompt-optimize the teacher for even better traces
prompt_optimizer = dspy.MIPROv2(metric=metric, auto="light")
teacher = prompt_optimizer.compile(production_program, trainset=trainset)
teacher_score = evaluator(teacher)
print(f"Teacher (GPT-4o, prompt-optimized): {teacher_score:.1f}%")
# Now fine-tune the cheap model
dspy.configure(lm=cheap_lm)
student = dspy.ChainOfThought(ExtractOrderInfo)
ft_optimizer = dspy.BootstrapFinetune(metric=metric, num_threads=24)
student_finetuned = ft_optimizer.compile(
student,
trainset=trainset,
teacher=teacher,
)
finetuned_score = evaluator(student_finetuned)
print(f"Fine-tuned (GPT-4o-mini, distilled): {finetuned_score:.1f}%")
# --- Step 4: Final evaluation on held-out test set ---
print("\n--- Test set results (held-out) ---")
prod_test = test_evaluator(production_program)
ft_test = test_evaluator(student_finetuned)
print(f"Production (GPT-4o): {prod_test:.1f}%")
print(f"Fine-tuned (GPT-4o-mini): {ft_test:.1f}%")
print(f"Quality retained: {ft_test / max(prod_test, 0.01) * 100:.0f}%")
# --- Step 5: Cost comparison ---
# Approximate costs per 1M input tokens (as of 2024)
# GPT-4o: $2.50 input / $10.00 output
# GPT-4o-mini: $0.15 input / $0.60 output (fine-tuned: ~$0.23 / $0.90)
print("\n--- Cost comparison (per 1M messages, ~200 tokens each) ---")
gpt4o_cost = (200 * 2.50 / 1_000_000) + (100 * 10.00 / 1_000_000) # input + output
mini_ft_cost = (200 * 0.23 / 1_000_000) + (100 * 0.90 / 1_000_000)
savings = (1 - mini_ft_cost / gpt4o_cost) * 100
print(f"GPT-4o per message: ${gpt4o_cost * 1_000_000:.2f} per 1M messages")
print(f"GPT-4o-mini (fine-tuned): ${mini_ft_cost * 1_000_000:.2f} per 1M messages")
print(f"Cost reduction: {savings:.0f}%")
# --- Step 6: Save and deploy ---
student_finetuned.save("order_extraction_finetuned.json")
# To load in production:
# from my_module import OrderExtractionProgram
# program = OrderExtractionProgram()
# program.load("order_extraction_finetuned.json")Key points:
- Start by measuring your current production system's quality -- this is the bar the fine-tuned model needs to clear
- Always check the cheap model's untuned baseline first. If it's already close to the expensive model, you might not need fine-tuning at all (just prompt optimization with
/ai-improving-accuracy) - The teacher can be the existing production program or a prompt-optimized version of it. Better teacher traces produce a better student.
- The strict metric (all three fields must match) ensures only high-quality traces become training data
- Run the cost comparison before deploying to confirm the savings justify the fine-tuning effort
- If the fine-tuned model retains less than 90% of production quality, consider using
dspy.BetterTogether(see/ai-fine-tuning) or adding more training data
Condensed from dspy.ai/api/optimizers/BootstrapFinetune/. Verify against upstream for latest.
dspy.BootstrapFinetune — API Reference
Constructor
dspy.BootstrapFinetune(
metric=None, # Callable | None
multitask=True, # bool
train_kwargs=None, # dict | dict[LM, dict] | None
adapter=None, # Adapter | dict[LM, Adapter] | None
exclude_demos=False, # bool
num_threads=None, # int | None
)| Parameter | Type | Default | Description |
|---|---|---|---|
metric | `Callable | None` | None |
multitask | bool | True | When True, shares training data across all predictors. When False, each predictor gets separate fine-tuning data. |
train_kwargs | `dict | dict[LM, dict] | None` |
adapter | `Adapter | dict[LM, Adapter] | None` |
exclude_demos | bool | False | If True, clears few-shot demonstration examples after fine-tuning. Use when the fine-tuned model has internalized the patterns. |
num_threads | `int | None` | None |
Inheritance
BootstrapFinetune extends FinetuneTeleprompter.
Methods
compile()
optimizer.compile(
student, # dspy.Module (required)
trainset, # list[Example] (required)
teacher=None, # Module | list[Module] | None
) -> ModuleBootstraps training data from teacher (or student) execution traces and fine-tunes the student model's weights.
| Parameter | Type | Default | Description |
|---|---|---|---|
student | dspy.Module | required | The program whose backing LM will be fine-tuned. |
trainset | list[Example] | required | Labeled training examples (500+ recommended). |
teacher | `Module | list[Module] | None` |
Returns: Optimized dspy.Module with fine-tuned model(s) replacing the original LM(s).
Raises: ValueError if predictors lack assigned LMs or num_threads is insufficient for the number of fine-tuning jobs.
Behavior: 1. Runs teacher (or student) on each training example 2. Keeps traces where the metric passes 3. Formats passing traces as fine-tuning data 4. Calls lm.kill() on each model to free resources 5. Submits fine-tuning jobs to the provider 6. Returns the student with fine-tuned model references
get_params()
optimizer.get_params() -> dict[str, Any]Returns all configuration parameters as a dictionary.
convert_to_lm_dict() (static)
BootstrapFinetune.convert_to_lm_dict(arg) -> dict[LM, Any]Converts an argument to an LM-keyed dictionary. If already LM-indexed, returns unchanged; otherwise applies value uniformly across all LMs.
finetune_lms() (static)
BootstrapFinetune.finetune_lms(finetune_dict) -> dict[Any, LM]Executes parallel fine-tuning jobs across all LMs in the dict.
Supported providers
| Provider | Model format | Notes |
|---|---|---|
| OpenAI | openai/gpt-4o-mini, openai/gpt-4o | DSPy handles the fine-tuning API calls automatically |
| Together AI | together_ai/meta-llama/Llama-3-70b-chat-hf | Open-source models, competitive pricing |
| Local | Any HuggingFace model | Full control, requires GPU(s) |
Key behaviors
- All student predictors must have LMs assigned before
compile()is called num_threadsmust be >= the number of unique LMs across all predictors (one fine-tuning job per unique LM)- Calls
lm.kill()on each model to release resources before starting fine-tuning - The returned program stores the fine-tuned model ID (e.g.,
ft:gpt-4o-mini-2024-07-18:org::abc123) save()andload()preserve fine-tuned model references