跳转至

Prompt Chaining: Split One Big Task Into Smaller Steps

The travel assistant starts with one prompt:

Plan a relaxed Hangzhou day trip. I like tea, local food, and easy walking.

The model may write a route in one shot. But if you need it to extract preferences, draft an itinerary, and format the final answer, those jobs blur together inside one prompt. The model may miss a constraint or change content while formatting.

Prompt Chaining does not make the model more autonomous. It does the opposite: when the steps are known, Python owns the path.

One Sentence

Prompt Chaining turns one large prompt into fixed smaller steps, so each step has one job and intermediate outputs can be inspected.

What Breaks Without It

Problem What it looks like Risk
One prompt contains every instruction Output looks complete You cannot tell which part failed
Extraction and writing are mixed The answer reads well Budget or walking constraints may disappear
Final answer is generated directly Fewer calls UI, tests, and reviewers cannot inspect intermediate work

What This Pattern Changes

Who Owns
Python Step order, passing outputs forward, trace
Model One small task per step
Parser / checker Optional validation at step boundaries

The next step is chosen by code, not by the model.

Walk Through One Trace

Step Input Output Why split it
1 Extract preferences User request tea, local food, easy walking Capture constraints first
2 Draft itinerary Preferences West Lake, Tea Museum, Hefang Street Focus on route
3 Format answer Draft Concise final itinerary Focus on presentation

Flow

flowchart LR
  I["User request"] --> A["Step 1: Extract preferences"]
  A --> B["Step 2: Draft itinerary"]
  B --> C["Step 3: Format answer"]
  C --> O["Final itinerary"]

Code Walk

Define fixed steps:

steps = [
    PromptStep(name="extract_preferences", user_prompt="Extract travel preferences from: {input}"),
    PromptStep(name="draft_itinerary", user_prompt="Draft an itinerary from these preferences:\n{input}"),
    PromptStep(name="format_final", user_prompt="Format this itinerary as a concise final answer:\n{input}"),
]

Run them in order:

out = run_prompt_chain(model, initial_input=task, steps=steps, tracer=tracer)

Full example:

from __future__ import annotations

from pathlib import Path

from agent_patterns_lab.patterns.workflow_chaining import PromptStep, run_prompt_chain
from agent_patterns_lab.runtime import MockLLM, Tracer


def main() -> None:
    tracer = Tracer()
    model = MockLLM(
        [
            "Preferences: tea, local food, easy walking. Constraint: relaxed one-day trip.",
            "Draft: Morning West Lake, afternoon Tea Museum, evening Hefang Street.",
            "Final itinerary: West Lake -> China National Tea Museum -> Hefang Street.",
        ]
    )

    steps = [
        PromptStep(name="extract_preferences", user_prompt="Extract travel preferences from: {input}"),
        PromptStep(name="draft_itinerary", user_prompt="Draft an itinerary from these preferences:\n{input}"),
        PromptStep(name="format_final", user_prompt="Format this itinerary as a concise final answer:\n{input}"),
    ]

    out = run_prompt_chain(
        model,
        initial_input="Plan a relaxed one-day Hangzhou trip. I like tea, local food, and easy walking.",
        steps=steps,
        tracer=tracer,
    )
    print(out)

    trace_path = tracer.export_jsonl(Path(".traces") / "11_prompt_chaining.jsonl")
    print(f"[trace] {trace_path}")


if __name__ == "__main__":
    main()

Run:

UV_CACHE_DIR=.uv_cache PYTHONPATH=src uv run --no-sync python examples/11_prompt_chaining.py

Nearby Patterns

Pattern Who decides next Use when
Chatbot No next step One answer is enough
Prompt Chaining Python fixes the order Steps are known
Routing Code/model picks a branch Inputs need different flows
ReAct Model chooses from observations Tool results change the next step

When To Use It

  • You can write the steps before the run starts.
  • You want intermediate artifacts.
  • Each step has a clear input and output.
  • A fixed workflow is cheaper and easier to test than an open loop.

When Not To Use It

  • The next step depends on a fresh tool result.
  • One model call is enough.
  • Step boundaries are vague.
  • Latency is tight and extra calls are not worth it.

Costs And Common Failures

Failure Symptom Fix
Over-splitting Tiny task becomes many calls Merge steps without independent value
Error propagation Bad extraction poisons later steps Validate at step boundaries
Interface drift Step output changes shape Use structured output
Thin trace Only final answer is logged Record every step input/output

If the steps are fixed, use Prompt Chaining.

If inputs need different paths, read Routing. If tool observations change the path, read ReAct.

References