Home / Articles

From prompt tweaking to feedback loops: DSPy, GEPA and Claude Code

Learn how DSPy, MIPRO, STORM, GEPA, Claude Code and MCP shift AI work from rewriting prompts to building measurable programs with executable feedback loops.

Publisher: REACTAPP.TOP10 min read2213 words

This article is published in English.

Sources: From Stanford’s DSPy to Anthropic’s Claude Code: AI Engineering Beyond Prompt Engineering

For years the default fix for a weak LLM result was simple: tweak the prompt and try again. With agentic systems, the prompt often isn't the layer that needs work.

Picture a production bug that only appears after a config change. Hand it to two different AI setups. The first gets the stack trace plus a carefully worded instruction and returns a patch. The second can open the repository, read the project's rules, reproduce the failure, change code, run the tests, see what broke and go around again.

The model matters in both cases. What the second setup has, and the first doesn't, is an executable feedback loop.

Once that loop exists, prompt wording becomes one knob among many. You can also tune how the task is split up, what gets retrieved, which tools are available, the examples, verification, retry rules, how execution is sandboxed, and the evaluator that decides whether the work is actually right.

That's the thread running from Stanford's research on DSPy, MIPRO, STORM and GEPA to Anthropic's production work on Claude Code and the Model Context Protocol. These aren't one architecture. The shared idea sits underneath: AI engineering is shifting from polishing a single prompt to building systems that act, measure the outcome and improve the program wrapped around the model.

The prompt is now one parameter

A one-shot app has very few controls:

Task → Prompt → Model → Result

For contained tasks that's fine. It gets brittle once the job needs several stages, outside information, real side effects, checking, or recovery from a bad decision halfway through.

A system built for production looks more like this:

 Task
  ↓
Program / Planner
  ↓
Context + Retrieval
  ↓
Tools + Environment
  ↓
Execution Trace
  ↓
Evaluator
  ↓
Retry, Repair, or Optimize
  ↓
Result

Now a poor result has many possible causes. The model might not be strong enough. Retrieval might have pulled the wrong context. The planner may have split the work badly. A tool could have returned stale data. The verifier might have waved through an invalid answer. Or the instructions really do need fixing.

So prompt engineering doesn't go away. It turns into one part of a broader debugging and optimization problem.

DSPy: make the program explicit

DSPy's first big idea was to stop treating an LM pipeline as a pile of hand-tuned prompt strings. The original paper models LM applications as computational graphs of declarative modules and adds a compiler that optimizes those modules against a metric. The current docs say it more plainly: define structured signatures and modules, supply examples and a scoring function, and compile the program instead of hand-tuning every prompt.

A small DSPy program looks like this:

import dspy

class Diagnose(dspy.Signature):
    """Identify the most likely root cause from an issue and repository evidence."""
    issue: str = dspy.InputField()
    evidence: str = dspy.InputField()
    diagnosis: str = dspy.OutputField()

program = dspy.ChainOfThought(Diagnose)

optimizer = dspy.GEPA(
    metric=score_diagnosis,
    auto="medium",
)

optimized = optimizer.compile(
    program,
    trainset=historical_incidents,
)

The syntax isn't the point. What matters is that four things normally tangled together in one prompt are now separate: what the task must produce, how it gets executed, which examples guide it, and how success is scored.

That changes the engineer's job. Rather than burning the whole iteration budget debating whether "be concise" should become "reason carefully before answering", you get to ask a better question: which behavior should improve, and how will you measure it?

Without a meaningful metric, automatic optimization just makes the system better at the wrong goal.

MIPRO: tuning many stages is a search problem

Things get harder when the program has several modules. Take a bug-fix flow with diagnosis, patch generation and review, where the final test run fails. Which module caused it? Which instruction should change? Is one of the few-shot examples misleading? Would a better diagnosis step make patch generation worse?

That's a credit assignment problem, and it's what MIPRO targets. The MIPRO paper goes beyond editing a single prompt. It tunes the written instructions and the few-shot examples of every module together, combining instruction proposals that are aware of both the program and the data, evaluation on mini-batches, and a surrogate model that steers the search toward promising combinations.

In outline:

Bootstrap useful demonstrations
          ↓
Propose task-grounded instructions
          ↓
Search instruction + demo combinations
          ↓
Evaluate the whole program

With Llama-3-8B, the optimizer beat its baselines on five of seven multi-stage programs, with the best case gaining up to 13% on the reported accuracy metric.

That's a narrower claim than "automatic prompts beat humans". The bigger takeaway is structural: once instructions and demonstrations are parameters of a multi-stage program, improving it becomes a search over the system instead of a writing exercise on one string.

STORM: structure comes before optimization

No optimizer can save a badly shaped workflow. Stanford's STORM is a good example, since its focus is how the pipeline is laid out, not which prompt wins.

A single model doing all the research and the long-form writing in one go is the naive version; STORM pulls the preparation phase out into its own steps. It finds different perspectives on the topic, uses them to drive questioning grounded in sources, organizes what it gathers into an outline, and only then writes.

Against an outline-driven retrieval baseline, the paper reports a 25 percentage point absolute gain in organization and a 10 point gain in breadth. The STORM repository is equally clear about the limits: generated articles aren't ready to publish and often need heavy editing.

The lesson that carries over isn't "add more agents". It's that decomposition gives you distinct places to control context, evidence, failure handling and evaluation. Before optimizing a workflow, make sure its stages line up with the ways it actually fails.

GEPA: learn from what actually happened

A single score can tell you a run was mediocre. It usually can't tell you why. A real execution leaves far richer evidence behind:

input
  ↓
retrieval choice
  ↓
reasoning
  ↓
tool call
  ↓
tool result
  ↓
constraint failure
  ↓
final output

GEPA, short for Genetic-Pareto and published in July 2025, uses that signal. It samples execution trajectories, reflects on them in natural language, proposes prompt edits, scores the candidates, and keeps a Pareto frontier so complementary strategies aren't thrown away.

Comparison in the paper Reported result
Against GRPO, six tasks about 6% better on average
Rollouts needed vs GRPO up to 35x fewer
Against MIPROv2 more than 10% better
AIME-2025 accuracy +12%

One boundary matters a lot in production. GEPA optimizes over trajectories you've already observed. It is not permission to let a live agent rewrite itself after every user request. Before any optimized candidate goes live, it should be versioned, scored on cases it never trained on, kept within a fixed optimization budget, and pass an explicit promotion step against a curated eval set. That's the line between useful self-improvement and uncontrolled self-modification.

Claude Code: the loop inside a real environment

DSPy attacks the problem from the program optimization side. Claude Code comes at it from the runtime side. In Anthropic's framing it's an agent that lives in your repo: it picks up the project's own instructions, changes files, executes shell commands and test suites, and keeps adjusting based on the results. Its advanced patterns material talks about splitting work across subagents, running hooks between steps, and plugging in company-internal services over MCP.

The architecture isn't "chat with a smarter coder". It's closer to this:

Repository + Project Rules + Task
              ↓
            Model
       ↙      ↓      ↘
     Read    Edit   Execute
       ↘      ↓      ↙
      Tests / Runtime Evidence
              ↓
         Next Decision

That runtime evidence changes what the model can do. A failing test is better feedback than "please reconsider". A compiler error beats a model grading its own patch. Whether a diff stays within bounds can be checked mechanically instead of asking another model if the change feels appropriately scoped.

Anthropic's internal productivity numbers are interesting but easy to over-read. Its 2026 analysis reports roughly eight times more lines of code per engineer per day by Q2 2026 compared with earlier periods, and it warns explicitly that lines of code overstate real productivity. That window also covers big changes to both the models and Claude Code, so the figure doesn't show that orchestration alone produced the gain. The clearer signal is that modern coding systems keep turning model output into actions, observations and then another decision.

MCP connects tools; it doesn't orchestrate

MCP often gets lumped in with agents, tool use and orchestration as if those were the same thing. They aren't. The MCP architecture is a client-server spec: an AI app connects to servers and finds out what tools, resources and prompts they expose, then calls them in a uniform way. The host coordinates the clients and stays responsible for permissions, context management, security policy and how the LLM is plugged in.

So MCP covers one layer of a bigger stack:

Model                  capability envelope
Program / graph         task decomposition
Context / state         what the model can see
Tools / MCP             what the system can access or do
Runtime / harness       where actions execute
Evaluator               what counts as success
Optimizer               how the program improves
Observability           why a run succeeded or failed

No single framework owns all of it, which is exactly why thinking in systems pays off.

Optimize the bug-fix loop, not the prompt

Back to the bug from the start. Instead of one instruction saying "find the problem and fix it", spell out the workflow:

  Issue + Repository
        ↓
    Diagnosis
        ↓
      Patch
        ↓
Tests + Lint + Runtime Checks
        ↓
    Diff Review
        ↓
  Accept or Revise

Every stage now produces evidence. The runtime logs which files were read, which commands ran, the patches that failed, test output and the final diff.

Deterministic checks cover what can be proven mechanically: the required tests pass, lint stays clean, forbidden files aren't touched, and the patch stays in its allowed scope. Model judgment is saved for questions that really are semantic, like whether the diagnosis explains the probable root cause.

Over time, past cases become an evaluation set. MIPRO can search instructions and demonstrations across the diagnosis and repair modules. GEPA can take failed trajectories and written evaluator feedback and propose better program text. But optimization belongs behind a release boundary:

Production traces
      ↓
Curated evaluation set
      ↓
Offline optimizer
      ↓
Candidate program
      ↓
Held-out validation
      ↓
Controlled promotion

This is where research and production finally meet. The agent runtime produces actions and traces. The evaluator turns traces into evidence. The optimizer suggests a better program. The deployment process decides whether it's safe to ship.

What this means for AI engineers

Prompts haven't become irrelevant. You just have more useful places to step in. When a workflow underperforms, don't start with the wording by reflex. Work out which layer failed:

  • Could the base model handle the task at all?
  • Did retrieval surface the right context?
  • Was the task split at sensible boundaries?
  • Did the tools return evidence you can trust?
  • Was execution isolated and observable?
  • Does the evaluator measure the behavior you actually care about?
  • Is the optimizer improving held-out quality, or just fitting the dev set?

Looking at the whole system also exposes trade-offs the hype tends to skip. Wrapping a weak model in a graph doesn't make it a frontier model. A bad metric optimizes the wrong behavior. More tools mean more failure paths and a bigger security surface. Every optimization run spends tokens and eval time. Worst of all, an agent that edits itself with no version history and no untouched test cases can drift into being flakier, all while looking more independent on paper.

So the takeaway isn't that the model stopped mattering. Model quality sets the ceiling on capability. System design decides how much of that capability turns into reliable work.

That's the real link between the Stanford research and Anthropic's tooling. With DSPy the program stops hiding inside prompt strings. MIPRO lets you search over instructions and examples across stages. STORM is a reminder that the shape of the workflow comes first. GEPA mines full execution traces for improvements. Claude Code puts the model inside a working engineering harness, and MCP standardizes one of the boundaries to outside capabilities. Different projects at different layers, all pointing the same way.

Next time an AI system fails, "what prompt should I try next?" shouldn't be the only question. Ask which part of the system broke, and what evidence would let you fix it.