agentsclimarketplace

Agentsop dspy

Skill agentsope/SkillAlchemy/skills/agentsop-dspy

Operating SOP for DSPy (Stanford NLP) — the declarative framework for "programming, not prompting" language models. Activate when the user says any of: "use DSPy", "compile a prompt", "optimize prompts/programs", "MIPRO/MIPROv2", "BootstrapFewShot", "GEPA", "Signatures + Modules", "teleprompter", "auto-tune prompts for a different LM", or whenever a brittle hand-crafted prompt pipeline needs to be turned into a *compiled*, measurable, swappable program. Do NOT activate for one-shot prompt tweaks, no-metric exploratory work, or pipelines where prompts must remain human-authored verbatim — use raw prompting or LangChain templates instead.From its SKILL.md

Install
npx -y skills add agentsope/SkillAlchemy --skill agentsop-dspy

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • runs commandsInstructs the agent to run 4 commands, including `dspy.inspect_history(n=3)` and 3 more.

SKILL.md

28.8 KB, ~7.4k tokens by cl100k_base, as published. Nobody here has run it

DSPy SOP — Programming, Not Prompting

"DSPy isn't a prompt-optimization agent framework. It's the LLM compiler for the shortest, cleanest code." — Eito Miyamura [eito.substack.com/p/dspy-the-most-misunderstood-agent]

"Prompts are effectively the weights of an LLM application." — Core philosophy [arxiv.org/abs/2310.03714]


1. 何时激活 (When to activate)

Activate this skill when any of the following triggers are present in the user's intent or codebase:

TriggerSignal
Imports / mentionsimport dspy, dspy.Signature, dspy.ChainOfThought, dspy.ReAct, Predict, MIPROv2, BootstrapFewShot, GEPA, teleprompter, compile( on an LM program
Tasks"auto-tune this prompt", "I want to swap GPT-4 for a smaller model without re-engineering prompts", "I have 50/200/1000 labeled examples — optimize this", "compile a pipeline for our metric", "distill GPT-4 into Llama-3-8B"
SymptomsHand-written prompts grow past ~50 lines; brittleness on model swap; the team manually tunes few-shot examples; a metric exists but isn't being used to drive prompt design
Cross-skill bridgesLangGraph node calls an LLM and needs better prompts → wrap the node body in a DSPy module. LlamaIndex retriever feeds a reranker → DSPy-compile the reranker against a labeled set

Do NOT activate when:

  • The task is one-shot ("just answer this question once") — use raw client.messages.create.
  • No evaluation metric is possible and none is willing to be built — DSPy without a metric is just verbose prompting.
  • Prompts must remain human-authored verbatim for compliance, audit, or stylistic reasons.
  • The team is in rapid exploration mode where the task signature itself is changing daily — compile only after the signature stabilizes [dspy.ai/learn/optimization/overview/].

2. 核心心智模型 (Core mental model)

DSPy's full name is Declarative Self-improving Python. The three primitives form a PyTorch-like compile chain [arxiv.org/abs/2310.03714]:

┌─────────────┐    ┌──────────┐    ┌──────────────┐    ┌─────────┐
│  Signature  │ →  │  Module  │ →  │ Teleprompter │ →  │ Compile │
│ (what)      │    │ (how)    │    │ (optimizer)  │    │ (tune)  │
└─────────────┘    └──────────┘    └──────────────┘    └─────────┘
   I/O spec       Predict/CoT/      MIPROv2/GEPA/      Bake demos
   field names     ReAct/PoT        BootstrapFewShot   + instructions
   = semantic     = strategy        = search algorithm  into JSON

Three mental shifts the agent must internalize:

  1. Prompts are weights. The prompt string is not the artifact you ship — the compiled program (a JSON of demonstrations + instructions + structural choices) is. You ship program.json, not a .txt prompt [dspy.ai/tutorials/saving/].

  2. Signatures carry semantic load. question -> answer is not the same as query -> response. DSPy uses the field names as the only natural-language hint the optimizer has about intent before it sees data. Name them like you'd name function parameters in well-written code [dspy.ai/learn/programming/signatures/].

  3. Compile is a hyperparameter search, not a one-shot call. Compilation runs hundreds-to-thousands of LM calls (typically $2–$3 USD, 6–20 minutes, 3.2k API calls in the reference run). Costs scale with num_trials × |trainset| × |program LM calls| [dspy.ai/faqs/].

The PyTorch analogy is load-bearing. Signatures ≈ nn.Module.forward() shape contract. Modules ≈ nn.Linear / nn.Transformer. Teleprompters ≈ torch.optim.Adam. compile() ≈ training loop. save()/load() ≈ checkpoint.


3. SOP 工作流 (SOP workflow)

The DSPy team is explicit about a three-stage gate [dspy.ai/learn/]:

"It's unproductive to launch optimization runs using a poorly designed program or a bad metric."

Do not skip stages. Each stage has an exit criterion.

Stage 1 — Programming (no optimizer yet)

  1. Pin the task as a Signature. Start inline ("question -> answer"); upgrade to a class-based dspy.Signature with InputField(desc=...) / OutputField(desc=...) when types matter or fields need disambiguation.
  2. Pick the lowest-power Module that works. Default to dspy.ChainOfThought. Use dspy.Predict for trivial classification, dspy.ReAct only when tools are needed, dspy.ProgramOfThought for arithmetic-heavy tasks [dspy.ai/learn/programming/modules/].
  3. Compose with plain Python control flow. Subclass dspy.Module, instantiate sub-modules in __init__, call them in forward(). No special DSL.
  4. Run zero-shot on 5–10 hand-picked examples. Look at outputs with dspy.inspect_history(n=3).

Exit criterion: the un-optimized program produces plausible outputs on 5+ examples. Not great — plausible.

Stage 2 — Evaluation (no optimizer yet)

  1. Build a dev set. Documented sweet spot: 30 examples = minimum useful, 300 = recommended, 200+ required for MIPROv2 to avoid overfitting [dspy.ai/learn/optimization/overview/].
  2. Write a metric: def metric(example, pred, trace=None) -> float|bool. Start with exact-match; only escalate to LLM-as-judge when the task demands it (open-ended generation, multi-criteria).
  3. Run dspy.Evaluate(devset=dev, metric=metric, num_threads=16) and record a baseline score.

Exit criterion: baseline score is stable across two runs (cache-free) AND the metric agrees with human judgment on 10 spot-checks.

Stage 3 — Optimization (compile)

  1. Pick optimizer by data + signal regime (Section 4 table). Decide which model optimizes vs. which model is the task model — they can differ.
  2. Use the unusual 20/80 split (20% train, 80% val) for prompt-based optimizers. GEPA uses standard ML splits (maximize train) [dspy.ai/learn/optimization/overview/].
  3. Start auto="light". Only escalate to "medium"/"heavy" if dev-set gains flatten and budget allows.
  4. Save the compiled program: compiled.save("v1.json") for state, or compiled.save("./v1/", save_program=True) for whole-program (preferred for production with metadata) [dspy.ai/tutorials/saving/].
  5. Deploy via FastAPI (dspy.asyncify) or MLflow (mlflow.dspy.log_model) [dspy.ai/tutorials/deployment/].

Exit criterion: compiled program beats baseline on a held-out test set (not the val set used in optimization) by ≥ task-relevant delta.

When to iterate back

Loop to Stage 1 if optimization plateaus. Per the docs: "Is your task well-defined? Do you need more data? Should your evaluation metric change?" — these are the questions to re-ask, not "should I try a different optimizer?" [dspy.ai/learn/optimization/overview/].


4. 操作模型 (Trigger / Action / Output / Evidence)

4.1 Choose the optimizer

TriggerActionOutputEvidence
≤10 labeled examplesBootstrapFewShot(metric=m, max_bootstrapped_demos=4, max_rounds=1)Compiled program with self-generated demos[dspy.ai/learn/optimization/optimizers/]
30–50 examplesBootstrapFewShotWithRandomSearchBest-of-N candidate programs[dspy.ai/learn/optimization/optimizers/]
200+ examples, willing to spend computeMIPROv2(metric=m, auto="light") then escalateJointly-tuned instructions + few-shot demos via Bayesian optimization[dspy.ai/api/optimizers/MIPROv2/]
Need zero-shot prompts (no demos in final)MIPROv2(..., max_bootstrapped_demos=0, max_labeled_demos=0)Instruction-only optimization[dspy.ai/learn/optimization/optimizers/]
Have textual error feedback (test diffs, schema violations, judge rationales)dspy.GEPA(metric=m_with_feedback)Reflection-evolved prompts; sample-efficient[dspy.ai/tutorials/gepa_ai_program/], [arxiv.org/abs/2507.19457]
Already optimized with MIPROv2 / want to ship a smaller modelChain into BootstrapFinetune(student=small_lm, teacher=optimized)Finetuned weights (not just prompts)[dspy.ai/api/optimizers/BootstrapFinetune/]
Just want labeled demos in prompt (no search)LabeledFewShot(k=8)Trivial — fastest, cheapest, weakest[dspy.ai/cheatsheet/]

4.2 Module selection

TriggerActionWhy
Simple input → outputdspy.Predict(Sig)Lowest overhead
Reasoning helpsdspy.ChainOfThought(Sig)Default choice per docs
Math / counting / parsingdspy.ProgramOfThought(Sig)Code execution grounds the answer
Tools (search, calc, API)dspy.ReAct(Sig, tools=[...])Built-in tool loop
Ensemble for hard casesdspy.MultiChainComparison or dspy.majorityVote across N CoT samples

4.3 Metric design

TriggerActionCaveat
Exact answer expectedlambda ex, pred: ex.answer.lower() == pred.answer.lower()Cheap, deterministic
Open-ended generationLLM-as-judge with dspy.ChainOfThought(JudgeSig)Watch for self-preference bias, recency bias, score-ID bias [arxiv.org/pdf/2509.26072]
Multi-criteria (factuality + tone + length)Sub-judge each dim, return bool during optimization (trace is not None) and float during evaluationDocumented pattern [dspy.ai/learn/evaluation/metrics/]
Have rich error contextReturn dspy.Prediction(score=..., feedback="missing field X") and use GEPATextual feedback is GEPA's superpower [dspy.ai/api/optimizers/GEPA/overview/]

4.4 Cost guardrails

TriggerActionReference
Before any MIPROv2 callEstimate: auto="light" ≈ a few $; auto="heavy" on 1000+ examples can hit tens of $[dspy.ai/faqs/]
Budget tightUse a cheap optimizer LM (e.g. gpt-4o-mini) to optimize prompts for a more expensive task LM — community-reported parity [github.com/stanfordnlp/dspy/issues/1596]
Compile stuck mid-trialCheck issue #1970 pattern; reduce minibatch_size or kill and restart with smaller num_trials
Need reproducibilitydspy.configure(track_usage=True) + log program.get_lm_usage()

5. 困境决策案例 (Dilemma cases — ≥3)

Case A — "Optimizer cost vs gain: when is it worth compiling?"

困境 (Dilemma): User has a 3-stage RAG pipeline. Hand-tuned prompts already hit 72% on dev. MIPROv2 auto="heavy" would cost ~$40 and 4 hours. Worth it?

约束 (Constraints):

  • 250 labeled examples (above MIPROv2 200-example floor) [dspy.ai/learn/optimization/optimizers/].
  • Prompts already manually iterated — diminishing returns suspected.
  • Pipeline LM = GPT-4o ($-per-call adds up at trial scale).

决策步骤 (Decision steps):

  1. Check whether the prompts were ever validated against the metric, or just eye-balled. If eye-balled, even auto="light" (~$2) typically yields 10–30%+ on hand-tuned baselines per the paper's GPT-3.5/Llama2 results (25%/65% lift over standard few-shot) [arxiv.org/abs/2310.03714].
  2. Run auto="light" first as a cheap signal. The docs explicitly recommend "start with moderate values, observe behavior, and scale up only if you see clear gains" [github.com/stanfordnlp/dspy issue #1596].
  3. If light gives <2% lift, do not escalate to heavy. Instead, revisit Stage 1: is the signature ambiguous? Is the program structure (3 stages) actually right?
  4. If light gives 5–10% lift, run medium. Only escalate to heavy if data ≥ 300 and you have a held-out test set distinct from val.
  5. Use gpt-4o-mini as the optimizer LM even when the task LM is gpt-4o. Community evidence: parity at fraction of cost [github.com/stanfordnlp/dspy issue #1596].

结果 (Outcome): Typical: light exposes whether more compute helps. Often the answer is "no — fix the program/metric first."

可提取的操作 (Extractable operation): Never start compilation at auto="heavy". Always probe with light and use a cheap optimizer LM.


Case B — "Swap the underlying LM: recompile, transfer, or both?"

困境: Compiled program for GPT-4o works at 85%. Need to switch to Llama-3-8B for cost. Re-use the GPT-4o-compiled program.json or recompile?

约束:

  • Compiled program contains demos + instructions that may exceed the smaller model's context coherence.
  • Recompile cost ≈ another $2–5.
  • The DSPy doctrine: "If you optimize a complex pipeline for GPT-4, it usually breaks on a smaller model like Llama-3-8b" [acldigital.com — Death to Prompting].

决策步骤:

  1. Always recompile when changing the task LM family. This is the headline value prop of DSPy: "swap the LLM definition and re-compile your program" [ganeshkedari.substack.com/p/stop-writing-prompts-a-guide-to-dspy].
  2. The optimizer will discover the smaller model needs more examples / simpler reasoning steps and adjusts automatically — you do not edit prompts.
  3. Use BootstrapFinetune as a follow-on: optimize prompts on the big model, then distill into a 1B–7B student. Typical setup: student=Llama-3.2-1B-Instruct, teacher=gpt-4o-mini [dspy.ai/api/optimizers/BootstrapFinetune/].
  4. If demos in the saved program reference GPT-4o-style verbose CoT, the small model may parrot length without reasoning. Recompile is mandatory, not optional.
  5. Keep both program.gpt4o.json and program.llama8b.json checked in; A/B in production.

结果: Recompiled programs typically recover 70–90% of the larger-model performance at 1/10–1/50 the per-call cost. The "transfer without recompile" path is reliably worse.

可提取的操作: Treat the compiled program as a (program × LM) pair. Changing the LM invalidates the artifact — recompile.


Case C — "Metric design: proxy correctness vs ground truth"

困境: Open-ended customer-support response task. No exact-match metric possible. LLM-as-judge "feels right" but the team worries the judge will be biased toward verbose, hedged outputs.

约束:

  • 400 labeled examples with a reference response (not the unique correct response — one acceptable response).
  • Production users penalize verbosity.
  • DSPy will optimize toward whatever the metric rewards. A bad metric becomes a bad program at scale.

决策步骤:

  1. Refuse to ship a single-LLM-judge as the optimization metric. Document evidence: LLM judges exhibit self-preference, recency, rubric-order, and provenance biases [arxiv.org/pdf/2506.02592, arxiv.org/pdf/2509.26072].
  2. Decompose the judge into orthogonal sub-judges, each a dspy.Predict(Assess) call with a single yes/no question (factual? on-topic? concise? non-hedging?). Documented pattern [dspy.ai/learn/evaluation/metrics/].
  3. Use trace is not None to return bool during compile, float during eval — same metric function, two modes. Avoids the optimizer overfitting to score noise.
  4. Spot-check the metric on 20 examples with a human judge first. If sub-judges disagree with human on >20% of cases, fix the metric before compiling. Garbage metric → garbage compiled program.
  5. If sub-judge feedback is rich (e.g. "answer was verbose"), pipe textual feedback into dspy.GEPA instead of MIPROv2 — GEPA leverages text feedback for faster, more sample-efficient convergence [dspy.ai/api/optimizers/GEPA/overview/, arxiv.org/abs/2507.19457].
  6. Add a length penalty as a separate scalar in the metric — don't rely on the judge to penalize verbosity (judges over-prefer length).

结果: Multi-dimension metric with explicit length penalty + GEPA's textual feedback typically beats single-judge + MIPROv2 by 10–13% on AIME-style benchmarks [arxiv.org/abs/2507.19457] and is the empirically robust path.

可提取的操作: Never compile against a metric you haven't human-validated on ≥ 20 spot-checks. Decompose multi-criteria metrics. Prefer GEPA when you can express textual feedback.


Case D — "Compile-time hang / stuck trial — abort or wait?"

困境: MIPROv2 compile stuck mid-trial (no progress logs for 30 min). Reported pattern in issue #1970 [github.com/stanfordnlp/dspy/issues/1970]. Abort and restart, or wait?

约束:

  • $15 spent so far on the run.
  • Sunk cost vs. wasted further spend.
  • Possible causes: a single example triggers rate limits / context-length overflow / a tool call hangs.

决策步骤:

  1. Check dspy.inspect_history(n=3) — does the last LM call show truncation or rate-limit error?
  2. If context-length: reduce max_bootstrapped_demos and max_labeled_demos (default 4 each); the docs explicitly cite this as the #1 context-length fix [dspy.ai/faqs/].
  3. If rate-limit: lower num_threads in the underlying Evaluate; add retry/backoff in the LM client.
  4. If neither, abort. Restart with smaller minibatch_size (default 35; try 16) and smaller num_trials. Hanging is a known failure mode without graceful resume.
  5. Save partial progress: even mid-compile, student retains best demo candidates — check compiled._predictors state.

可提取的操作: Compile is not atomic. Treat long hangs as failure. The cost of restart < cost of indefinite wait.


6. 反模式与边界 (Anti-patterns & boundaries)

Anti-patterns

  1. Compiling without a metric. Without a metric, DSPy collapses to verbose prompt templating. The Predict module requires nothing; the optimizers require a metric. If you cannot write a metric, you cannot optimize, period [dspy.ai/learn/optimization/overview/].
  2. Compiling on 5 examples. Below ~30 examples, you're not training — you're memorizing. The 20/80 train/val split exists because "prompt-based optimizers often overfit to small training sets" [dspy.ai/learn/optimization/overview/].
  3. Editing the compiled JSON by hand. It's plain JSON and readable — but human edits invalidate the assumption that the artifact was metric-optimized. Re-compile or don't touch.
  4. Using LLM-as-judge as the only metric for any open-ended task. See Case C. Biases are documented and reproducible [arxiv.org/pdf/2506.02592].
  5. Starting at auto="heavy". Always probe with light first [Case A].
  6. Treating DSPy modules as agents. ReAct is a thin tool-loop, not a multi-agent framework. For long-running, stateful, branching workflows: combine DSPy with LangGraph (see Section 7).
  7. Ignoring program structure when optimization stalls. If MIPROv2 light + medium both flatline, the bottleneck is almost always the program graph (wrong decomposition, wrong module choice) not the optimizer [dspy.ai/learn/optimization/overview/].
  8. Re-using GPT-4-compiled programs on Llama-8B. See Case B.
  9. Skipping the unusual 20/80 split. The reversed ratio is intentional and prevents prompt-overfitting [dspy.ai/learn/optimization/overview/].
  10. Forgetting cache=False in Lambda / stateless deploys. Caches default to a writable dir and break in serverless [dspy.ai/faqs/].

Boundaries (when NOT to use DSPy)

  • One-shot tasks. "Summarize this email once" → raw API call. The compile loop has no payoff.
  • The task signature is still changing daily. Compile only after the I/O contract stabilizes; otherwise you're paying compile cost for prompts you'll throw away.
  • Compliance/audit requires verbatim human-authored prompts. Optimized prompts are machine-generated artifacts; some regulated contexts disallow this.
  • No labeled data and no labelable proxy. Without a metric, the framework can't help you. (Note: even 30 examples can work — but you need some signal.)
  • You need rich agent observability with LangFuse-style traces today. Native integration is limited; bolt-on via MLflow tracing works but is not first-class [eito.substack.com].
  • Streaming partial outputs is essential. DSPy supports dspy.streamify from 2.6.0+ but it's newer than the rest of the stack — verify your version [dspy.ai/tutorials/deployment/].

7. 生态对照 (Ecosystem context)

Layer positioning

DSPy is not the same layer as LangChain / LlamaIndex / LangGraph. It sits underneath them as a compiler for the individual LM calls inside those orchestration layers [langwatch.ai/blog/best-ai-agent-frameworks-in-2025-...].

┌──────────────────────────────────────────────┐
│  Orchestration:  LangGraph, CrewAI            │ ← graphs, agents, state
├──────────────────────────────────────────────┤
│  Retrieval:      LlamaIndex                   │ ← ingestion, indexing
├──────────────────────────────────────────────┤
│  Compiler:       DSPy                         │ ← signatures, modules, compile
├──────────────────────────────────────────────┤
│  Generation:     Guidance, LMQL, Outlines     │ ← single-call grammar control
├──────────────────────────────────────────────┤
│  Inference:      vLLM, llama.cpp, Anthropic   │ ← serving
└──────────────────────────────────────────────┘

vs LangChain

  • LangChain: orchestration, batteries-included, hand-authored prompts. 71 lines for a typical agent.
  • DSPy: compile-the-prompt, 30 lines for the same task [eito.substack.com — code comparison].
  • Together: rare. LangChain's prompt templates collide with DSPy's compilation model. Pick one per pipeline; if you must combine, isolate DSPy modules behind clean Python interfaces inside LangChain chains.

vs LangGraph

  • LangGraph = stateful graph orchestration (nodes, edges, checkpointing, human-in-loop).
  • DSPy = the LM call inside a node.
  • Together: highly complementary. Pattern: each LangGraph node's body invokes a compiled DSPy program. LangGraph handles state and routing; DSPy handles prompt quality [rajapatnaik.com/blog/2025/10/23/langgraph-dspy-gepa-researcher]. Quote from acldigital.com: "DSPy fits into the Prompt Management & Optimization layer—bringing software engineering discipline to prompting" while LangGraph fits the orchestration layer.

vs LlamaIndex

  • LlamaIndex = data ingestion + retrieval + query engines.
  • DSPy = optimizes the generator / reranker / synthesizer component.
  • Together: standard pattern. LlamaIndex retrieves passages → DSPy-compiled Predict(context, question -> answer) synthesizes. JetBlue's chatbot uses exactly this split — retrieval quality + answer quality as separate metrics, DSPy optimizes both [databricks.com/blog/optimizing-databricks-llm-pipelines-dspy].

vs Guidance / LMQL / Outlines

  • These control one LM call at the token level (grammars, regex, JSON schema).
  • DSPy controls multi-call programs at the optimization level.
  • Together: orthogonal. Use Outlines for "force valid JSON"; use DSPy for "make the JSON-emitting prompt good." DSPy's typed OutputField already pushes the LM toward structure but doesn't guarantee grammar conformance [dspy.ai/faqs/].

vs raw prompt engineering

  • Raw prompts win when: one-shot, signature unstable, no metric, audit constraints (Section 6).
  • DSPy wins when: pipeline ≥ 2 LM calls, you have ≥ 30 labeled examples, you'll swap models or scale, you have a metric (even an LLM-judge one — but harden it per Case C).

Production case study evidence

  • JetBlue + Databricks: RAG chatbot. Before DSPy = manual prompt tuning on retrieval/answer quality metrics. After = DSPy directly optimizes those metrics, faster development cycle [tastytechbytes.com/databricks-dspy-jetblue-ai-chatbot].
  • Haize Labs: automated LLM red-teaming.
  • In production at: Shopify, Databricks, Dropbox, JetBlue, Moody's, AWS, Sephora, VMware [dspy.ai].
  • Tobi Lütke (Shopify CEO): "Both DSPy and (especially) GEPA are currently severely under hyped in the AI context engineering world" [eito.substack.com].

Quick-reference appendix

Minimal end-to-end (verbatim from cheatsheet) [dspy.ai/cheatsheet/]

import dspy

# 1. Signature
class BasicQA(dspy.Signature):
    """Answer questions with short factoid answers."""
    question: str = dspy.InputField()
    answer: str = dspy.OutputField(desc="often between 1 and 5 words")

# 2. Module
qa = dspy.ChainOfThought(BasicQA)

# 3. Metric
def metric(ex, pred, trace=None):
    return ex.answer.lower() in pred.answer.lower()

# 4. Compile
from dspy.teleprompt import MIPROv2
optimizer = MIPROv2(metric=metric, auto="light")
compiled = optimizer.compile(qa, trainset=trainset)

# 5. Save / load
compiled.save("v1.json")

Decision tree (one screen)

Have a metric? ─── No ──► Stop. Build a metric first. (Or skip DSPy.)
   │
   Yes
   │
Have ≥ 30 examples? ─── No ──► Stop. Collect more data, or use LabeledFewShot(k=8) as floor.
   │
   Yes
   │
Have textual error feedback? ─── Yes ──► dspy.GEPA
   │
   No
   │
≤ 10 examples? ──► BootstrapFewShot
30–50?         ──► BootstrapFewShotWithRandomSearch
50–200?        ──► MIPROv2(auto="light", max_bootstrapped_demos=4)
200+?          ──► MIPROv2(auto="light" → "medium" if gains; "heavy" only if 300+ and budget)
Need to ship small model? ──► chain BootstrapFinetune after MIPROv2

Anatomy of a compiled program.json

After compiled.save("v1.json"), the file is plain JSON. Per-predictor it contains [dspy.ai/tutorials/saving/]:

{
  "predictor_name": {
    "signature_instructions": "Given the context, answer the question with a short factoid...",
    "signature_prefix": "Answer:",
    "extended_signature_instructions": "...",
    "demos": [
      {"question": "...", "reasoning": "...", "answer": "..."},
      ...
    ],
    "signature": {
      "instructions": "...",
      "fields": [{"prefix": "Question:", "description": "..."},  ...]
    }
  }
}

What changes when you compile:

  • Instructions are rewritten by the optimizer (MIPROv2 proposes; Bayesian search picks).
  • Demos are bootstrapped: the teacher program is run on trainset, metric filters keep the good ones.
  • Signature shape does NOT change — that's your code's job.

What does NOT change between LMs (so you can read across artifacts):

  • The signature field names.
  • The metric.
  • The program's Python structure (which modules call which).

What DOES change between LMs (so you can't reuse):

  • The instructions (smaller LMs need simpler, more explicit wording).
  • The demos (smaller LMs benefit from more, simpler demos; larger LMs benefit from fewer, richer ones).

Constraint primitives — dspy.Assert vs dspy.Suggest

For self-refining pipelines [dspy.ai/learn/programming/7-assertions/, arxiv.org/pdf/2312.13382]:

# Hard: halts after max retries with dspy.AssertionError
dspy.Assert(len(pred.answer) < 100, "Answer must be < 100 chars")

# Soft: retries with feedback in prompt, logs failure, continues
dspy.Suggest(is_valid_json(pred.output), "Output must be valid JSON")

When a constraint fails, DSPy backtracks to the previous module and re-runs with the error message injected into the prompt. This is self-refinement at inference time — distinct from compile-time optimization.

Use Assert during development (catch bugs hard). Use Suggest in production (degrade gracefully).

Key citations

  • DSPy paper (ICLR 2024): [arxiv.org/abs/2310.03714]
  • GEPA paper (ICLR 2026 oral): [arxiv.org/abs/2507.19457]
  • DSPy Assertions paper: [arxiv.org/pdf/2312.13382]
  • Docs hub: [dspy.ai/learn/]
  • Optimizer guide: [dspy.ai/learn/optimization/optimizers/]
  • FAQ: [dspy.ai/faqs/]
  • Deployment: [dspy.ai/tutorials/deployment/]
  • JetBlue case study: [databricks.com/blog/optimizing-databricks-llm-pipelines-dspy]
  • Misunderstanding piece (Miyamura): [eito.substack.com/p/dspy-the-most-misunderstood-agent]
  • MIPROv2 community Q&A: [github.com/stanfordnlp/dspy/issues/1596]
  • Compile hang pattern: [github.com/stanfordnlp/dspy/issues/1970]
  • LangGraph vs DSPy issue: [github.com/stanfordnlp/dspy/issues/1078]

What ships with it: 7 files

45.6 KB alongside SKILL.md

intermediate/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.