The instinct with any LLM task is to write one big prompt: "read all of this, figure out the answer, and write it up." It often almost works — the output is fluent and confident — which is exactly what makes it dangerous. Under the hood the model is doing extraction, reasoning, and writing simultaneously, and attention is finite, so it drops a detail, miscounts, picks the wrong priority, or silently skips a whole sub-task. Worse, you get back one opaque paragraph with no seam to pull apart. I built an interactive demo that runs the same task both ways, and the gap is hard to unsee.
The task that breaks the mega-prompt
The demo takes five messy customer reviews and asks for one quantified executive insight: note the positives, name the number-one complaint, quantify it, and recommend a fix. The single prompt returns something plausible — "customers are happy, the main complaint seems to be slow shipping" — and it is wrong. App crashes appear in two of five reviews; shipping in one. It picked the wrong top issue, never quantified anything, and gave you no way to see where it slipped.
The idea: a pipeline of single-purpose prompts
Prompt chaining decomposes the task into a sequence of small prompts where each step's output is the next step's input. The canonical shape is extract → transform → summarize:
const rows = await extract(rawInput); // step 1: parse, don't think
const tally = await transform(rows); // step 2: reason over structure
const answer = await summarize(tally); // step 3: present, don't compute
It is the Unix-pipe philosophy applied to LLM calls — small tools, composed.
Extract: parse, don't think
The first link does only extraction. Turn messy text into a clean, machine-readable shape and do nothing else — no analysis, no prose. A narrow prompt like this is something even a small model gets right almost every time:
async function extract(rawReviews) {
return llm(`For EACH review, emit one line:
+ positives · - negative theme in {app,battery,shipping,price,comfort,sound}
Reviews:\n${rawReviews}`); // e.g. "R1 +overall · -app ..."
}
The hard parsing now happens exactly once, and every step downstream operates on tidy rows instead of re-parsing raw text.
Transform: reason over the structure
The middle link does the actual reasoning — aggregate, count, rank — but over step 1's clean rows, never the raw input:
async function transform(rows) {
return llm(`From these tagged rows, tally NEGATIVE mentions per theme,
sort descending, and list POSITIVE themes separately.
Rows:\n${rows}`);
}
This is dramatically more reliable than reasoning inside a mega-prompt, because the model is not also fighting to parse messy text at the same time.
Summarize: present, don't compute
The last link only writes, and only from what the pipeline already computed:
async function summarize(tally) {
return llm(`Using ONLY this tally, write one paragraph:
overall sentiment, the #1 complaint WITH its count,
and a concrete recommendation.\n\nTally:\n${tally}`);
}
Separating "decide the answer" from "phrase the answer" is what stops fluent prose from quietly inventing a different top issue or forgetting a number.
The payoff: gates and error isolation
Chaining them is just the three calls in order — but because every intermediate result is a visible checkpoint, you can gate between steps, and when the answer is wrong the failure is localized instead of buried:
async function run(rawReviews) {
const rows = await extract(rawReviews);
assert(rows.includes("-"), "extract produced no tagged rows"); // gate
const tally = await transform(rows);
assert(/\d/.test(tally), "transform produced no counts"); // gate
const answer = await summarize(tally);
return { rows, tally, answer }; // keep intermediates → debuggable!
}
If the final answer is off, you open rows, then tally, then answer, and see exactly which step failed — "ah, extract missed review 4, so the count was off." A single mega-prompt has zero seams, so a bug anywhere looks the same: a bad paragraph.
When to chain — and when not to
This is not free. More calls mean more latency and token cost, and an error in an early step propagates downstream (garbage in, garbage out — so gate aggressively). Chain when the task has genuinely distinct phases and reliability or debuggability matter. For a simple single-shot task, one good prompt is faster and cheaper — building a pipeline for a one-liner is its own kind of over-engineering. Reliability compounds in your favour: one broad prompt has to nail every sub-task at once, while each narrow step has a far higher success rate on its single job.
Pick a task, flip between the single prompt and the chain, and step through the pipeline to watch state flow stage to stage:
https://dev48v.infy.uk/prompt/day35-prompt-chaining.html
Top comments (0)