DEV Community

Tang Weigang
Tang Weigang

Posted on

Before adopting DSPy, prove the LM program has a contract

Before adopting DSPy, prove the LM program has a contract

DSPy is easy to undersell. If you describe it as "a nicer way to write prompts", you will probably test the wrong thing.

The better first test is this: can your language-model workflow be expressed as a small program with declared inputs, declared outputs, measurable examples, and an optimizer that is allowed to change prompts without changing the business boundary?

That is the point where DSPy starts to make sense.

The upstream README positions DSPy as a framework for programming, rather than prompting, foundation models. The current Doramagic project pack for stanfordnlp/dspy also points at the same starting command: pip install dspy. The package metadata I checked today declares name="dspy", version 3.3.0b1, and Python >=3.10,<3.15. The GitHub API snapshot showed the repository was still active, with a push on 2026-07-05 and recent pull requests around empty evaluation sets, document formatting, and GEPA trace attribution.

That activity is useful, but it is not the adoption proof. The proof is whether your own task can survive three separations.

1. Separate the task contract from the prompt

In DSPy terms, the first artifact worth reading is not a clever prompt. It is the Signature.

A Signature says what goes in and what must come out. A Module wraps that contract into something callable. An Adapter turns the contract into the provider-facing prompt format and parses the model response back into fields.

That gives you a practical review question:

Can the team name the output fields before anyone starts tuning wording?

If the answer is no, DSPy will not rescue the workflow. You are still negotiating the task itself. The first pass should be a tiny contract: input text, retrieved context if needed, answer, citations, confidence, or whatever fields the product actually needs. Do not start with agents, tools, or multi-stage pipelines.

2. Separate compilation from runtime correctness

DSPy optimizers can improve prompts or weights for a module. That is powerful, but it changes the failure mode.

The dangerous version is: "the optimizer found a better prompt, ship it."

The safer version is: "the optimizer produced a candidate, now compare it against a fixed devset, inspect traces, and keep a rollback path."

Recent upstream activity makes this boundary visible. One recent PR raised a descriptive ValueError for an empty devset instead of falling into a division error. Another fixed GEPA trace attribution by predictor identity. Those are not marketing details; they point at the real operating surface. Optimization needs examples, traces, and attribution. Without those, you are just moving prompt text around with less visibility.

My first acceptance test would be boring on purpose:

  • install in a fresh Python 3.10+ environment;
  • configure one cheap model;
  • define one Signature and one Module;
  • run a tiny fixed devset;
  • print the compiled program and the history/traces;
  • save the before/after result so a human can compare behavior, not just score.

If that feels too heavy, DSPy is probably not the right first abstraction for the task.

3. Separate retrieval quality from answer quality

DSPy is often pulled into RAG work, but RAG failures rarely start in the final answer. They start earlier: chunking, retrieval, metadata, document formatting, or a missing negative example.

So I would not evaluate DSPy by asking "does it answer a question?"

I would evaluate:

  • Did the module receive the right retrieved records?
  • Can the retrieved records be inspected before generation?
  • Does the output contract force citations or evidence fields?
  • Does the devset include a case where retrieval should fail?
  • Can the optimizer improve the answer without hiding a retrieval regression?

The Doramagic manual for DSPy breaks the project into Signatures, Modules, Adapters, LM clients, optimization/compilation, tools, streaming, retrieval, and utilities. That is a good adoption map because it stops the team from treating the final answer as the only object under test.

Where DSPy fits

DSPy is strongest when the team already has a repeatable LM task and wants to make the prompt layer programmable, inspectable, and optimizable.

It is a weaker fit when the team is still discovering the product behavior, has no examples, or cannot say what a correct output looks like. In that case, start with plain code, a small eval file, and manual traces. Add DSPy after the contract is stable enough to optimize.

The practical rule I would use:

Use DSPy when changing the prompt should be treated like compiling a program. Skip it when changing the prompt is still product design.

Sources checked: Doramagic DSPy project/manual pages, Doramagic PROJECT_PACK, upstream README, upstream pyproject.toml, GitHub API repository and release snapshots.

Tags: DSPy, LLM, RAG, prompt-optimization, agent-engineering, evaluation, Python, open-source, AI-engineering, observability, retrieval, GEPA

Top comments (0)