Prompt Chaining

By the Syncfusion DevTutorials team · Last updated

Split one fat node into investigate, then write. The writer starts clean with a typed handoff, never sees the dead ends, and gets the answer right.

Watch an Agent Copy Its Own Dead End

A bug report says: "Login fails after a password reset." One agent gets the job: find the cause, then write a short script that shows the bug.

It tries six ideas. Five are dead ends. Then, in the same conversation, it writes the script. Run it and read the last line.

One fat node: investigate and write together

The script tests one of the dead ends, not the real cause. The agent found the right answer, but by the time it wrote the script, its context held six ideas, and the wrong ones were long and convincing. It copied one.

This is the oldest graph pattern of all: prompt chaining. Split the job into two steps, and let the second step start clean.

TL;DR

  • Prompt chaining splits one job into steps. Each step is a node. Each one passes a handoff to the next.
  • What it buys: context isolation. The next step does not see the last step's dead ends.
  • The handoff should be typed: a small, exact shape like {cause, steps, file}, not a long message.
  • Measure it: the writer's context should be a small fraction of the one-node version.
  • It fails when each step forwards everything. Then it is one node with extra waiting.

A Real-World Example

Lena asks her agent to migrate a page to a new design system and then write release notes. The agent spends an hour on the page. It tries three layouts, breaks the build twice and fixes it.

Then it writes the release notes. They mention a layout it threw away and a bug it already fixed. Every dead end from the hour of work is still in its context.

Lena splits the job. The first agent migrates the page and writes a short handoff: what changed, which files, which tests. A second agent writes the release notes from only that handoff. The notes are now short and right.

What You Will Learn

  • What context isolation is, and why dead ends hurt the next step
  • How to split one fat node into two, with one handoff
  • How to type a handoff so the next node knows exactly what it gets
  • How to measure a node's context
  • When chaining does not help

Context Isolation

Everything a node reads goes into its context: the text the model sees before it answers. A model cannot ignore part of its context. If the dead ends are there, they compete with the right answer.

One fat node carries every dead end. In a chain, the writer gets only the findings, a small fraction of the context.

In a chain, the first node does the messy work. It writes a short result into the state. The second node reads only that result. The dead ends stay behind.

Context: one fat node vs a chain

const size = { report: 800, notes: 3600, findings: 400 };
const tokensFor = (reads) => reads.reduce((sum, f) => sum + size[f], 0);

const fat = tokensFor(["report", "notes"]);
const writer = tokensFor(["findings"]);

console.log("one fat node:  " + fat + " tokens");
console.log("chain writer:  " + writer + " tokens");
console.log("writer is " + Math.round((writer / fat) * 100) + "% of the fat node");

Expected output:

one fat node:  4400 tokens
chain writer:  400 tokens
writer is 9% of the fat node

The writer's context is a small fraction of the original. That is less to pay for, and, more important, nothing wrong to copy.

How the Dead End Gets Copied

A model picks the idea it sees most

const ideas = [
  { idea: "the cache is stale",        lines: 40, right: false },
  { idea: "the clock is in UTC",       lines: 25, right: false },
  { idea: "the reset token is reused", lines: 6,  right: true  },
];

// A rough model: the longest, most-discussed idea wins the writer's attention.
const loudest = (list) => list.slice().sort((a, b) => b.lines - a.lines)[0];

console.log("fat node writes about:   " + loudest(ideas).idea);
const findings = ideas.filter((i) => i.right);
console.log("chain writer writes about: " + loudest(findings).idea);

Expected output:

fat node writes about:   the cache is stale
chain writer writes about: the reset token is reused

This is a cartoon of how models behave, not an exact rule. But the effect is real: a long, confident dead end in the context pulls the answer toward it.

The Handoff

The edge between the two nodes carries a handoff: the one field the first node writes and the second node reads. Its quality decides the chain's quality.

An untyped handoff is a chat message the next node has to guess at. A typed one is a shape it can rely on.

A typed handoff has a fixed shape. In the graph file, you give the field a type in state::

state:
  findings: { type: "{cause, steps, file}", writer: investigate }

Now the writer knows it gets three things: the cause, the steps to show it, and the file. Nothing else.

Check a handoff before passing it on

function checkHandoff(findings) {
  const need = ["cause", "steps", "file"];
  const missing = need.filter((k) => !(k in findings));
  return missing.length ? "rejected, missing: " + missing.join(", ") : "accepted";
}

console.log(checkHandoff({ cause: "token reused", steps: 3, file: "auth/reset.ts" }));
console.log(checkHandoff({ cause: "token reused" }));
console.log(checkHandoff({ text: "I think it's the token, or maybe the cache" }));

Expected output:

accepted
rejected, missing: steps, file
rejected, missing: cause, steps, file

A typed handoff also helps you. If a chain gives a wrong answer, read the handoff. It shows which side broke: the investigator found the wrong cause, or the writer misused the right one.

Build the Chain

Here is the split as a graph file. The investigator writes its long notes and a short findings. The writer reads only findings.

nodes:
  - { id: investigate, kind: agent, reads: [report], writes: [notes, findings], exit: { max_iterations: 8 } }
  - { id: write, kind: agent, reads: [findings], writes: [script], exit: { max_iterations: 4 } }
edges:
  - { from: investigate, to: write }

The notes are still useful: you can read them, and the run log keeps them. They just do not go to the writer.

A Split That Does Nothing

Splitting is not enough by itself. Watch what happens when the writer reads the notes too.

Split, but the writer still reads the notes

Two nodes, two agents, and the same wrong answer. This is the failure the QA Wolf guide warns about: if every node forwards the full state, the chain is one node with extra waiting.

Does this chain isolate anything?

const original = 800 + 3600;
const chains = {
  "writer reads findings":         ["findings"],
  "writer reads findings + notes": ["findings", "notes"],
  "writer reads report + findings": ["report", "findings"],
};
const size = { report: 800, notes: 3600, findings: 400 };

for (const [name, reads] of Object.entries(chains)) {
  const ctx = reads.reduce((s, f) => s + size[f], 0);
  const pct = Math.round((ctx / original) * 100);
  console.log(name + ": " + pct + "% " + (pct <= 25 ? "(isolated)" : "(not isolated)"));
}

Expected output:

writer reads findings: 9% (isolated)
writer reads findings + notes: 91% (not isolated)
writer reads report + findings: 27% (not isolated)

Score the Script

The check in the lab asks one question about the script: does it test the real cause? Here is that check for three designs.

Does the script test the real cause?

const realCause = "the reset token is reused";
const designs = [
  { name: "one fat node",          writerSees: ["the cache is stale", realCause] },
  { name: "leaky split",           writerSees: ["the cache is stale", realCause] },
  { name: "chain with findings",   writerSees: [realCause] },
];

// The writer tests the first idea it sees: the loudest one.
for (const d of designs) {
  const tested = d.writerSees[0];
  console.log(d.name + ": tests \"" + tested + "\" -> " + (tested === realCause ? "right" : "wrong"));
}

Expected output:

one fat node: tests "the cache is stale" -> wrong
leaky split: tests "the cache is stale" -> wrong
chain with findings: tests "the reset token is reused" -> right

When Chaining Does Not Help

Chaining buys clean context. It costs a handoff and some waiting. Skip it when:

  • The first step leaves no dead ends: the output of step 1 is already exactly what step 2 needs.
  • The steps are so coupled that step 2 needs nearly everything step 1 saw. Then you would forward the whole state anyway.
  • The job is a strict sequence one agent already does well. Lesson 1 showed that splitting it loses detail.

In Cursor, each subagent runs with its own context, and subagents in the other tools are separate conversations too. That is context isolation built in. A chain of two subagents, where the main agent passes only a short result between them, is exactly this pattern.

Lab Exercise: Split Into Investigate → Write

Now split the fat node yourself.

Split into investigate → write

Open the graph file. Change it so that:

  1. An investigate node reads report and writes notes and findings.
  2. A write node reads only findings and writes script.
  3. An edge goes from investigate to write.
  4. findings has a typed shape in state:, for example { type: "{cause, steps, file}" }.

Then press Check my graph. Each of the 3 versions has a different tempting dead end. The writer's context must be 25% or less of the one-node version, and the script must test the real cause every time. The check also runs 10 bug reports per version: accuracy must rise to at least 8 of 10 (one fat node gets about 4).

Remove the edge from the old node back to itself. A loop-back belongs inside a node that needs retries, not around the whole chain.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
One fat node"The agent knows which ideas were wrong."Dead ends in context compete with the right answer.The output copies a dead end.
Leaky split"Two nodes means isolation."Only what the next node reads matters.Same context, same mistake, more waiting.
Untyped handoff"A paragraph of findings is enough."A small fixed shape: cause, steps, file.The next node guesses what matters.
Throwing notes away"Only the findings matter."Keep notes in the state for people and logs.Nobody can tell how the cause was found.
Chaining everything"More steps are cleaner."Chain only where context really should reset.Each hop adds waiting and loses detail.

Exercises

Each exercise ends with a value on the last line. Press Check to compare it with the expected answer.

What to Remember

  • Prompt chaining splits a job into nodes so each step starts with clean context.
  • Only what the next node reads matters. A split that forwards everything isolates nothing.
  • Pass one small, typed handoff along the edge.
  • Keep the long notes in the state for people, not for the next node.
  • Skip chaining when the steps need each other's full detail.

Further Reading

Next: Routing. A small router sends a payment change down the cheap path, and you give it a safe fallback.