Prompt Chaining in AI Workflows
Not every AI task needs a multi-step agent. Sometimes the best solution is a simple chain: call the LLM once, pass the output as input to the next call, repeat. Prompt chaining gives you predictability, lower cost, and easier debugging compared to open-ended agent loops.
What Is Prompt Chaining?
A prompt chain is a sequence of LLM calls where each call's output becomes (part of) the next call's input. Unlike an agent loop, the structure is fixed at design time — no autonomous tool selection, no dynamic loops.
Use a chain when you know the steps needed in advance. Use an agent when the steps depend on what the LLM discovers during execution.
When to Chain vs Single Prompt
| Prefer chaining when... | Prefer single prompt when... |
|---|---|
| Steps are distinct (research → summarise → format) | The task fits in one context window |
| Each step benefits from full focus on one sub-task | Overhead of multiple calls is not worth it |
| You want to use different models per step | Output quality is already good in one call |
| Quality doesn't meet requirements in one shot | Latency is critical |
A Simple 3-Step Chain
from openclaw import Chain, Step
chain = Chain(
steps=[
Step(name="research",
prompt="Research the following topic and provide key facts: {topic}",
model="gpt-4o"),
Step(name="summarise",
prompt="Summarise this research in 3 bullet points:\n{research}",
model="gpt-4o-mini"),
Step(name="format",
prompt="Format these bullet points as a professional email body:\n{summarise}",
model="gpt-4o-mini"),
]
)
result = chain.run(topic="quantum computing breakthroughs in 2025")
print(result["format"]) # Final formatted outputVariable Passing Between Steps
Each step receives the outputs of all previous steps as template variables using {step_name} syntax. You can also inject external variables at run time:
result = chain.run(
topic="quantum computing",
audience="non-technical executives", # Extra variable injected at any step
)Conditional Branching
Use a ConditionalStep to route to different sub-chains based on intermediate output:
from openclaw import ConditionalStep
chain = Chain(steps=[
Step(name="classify",
prompt="Classify this support ticket as 'billing', 'technical', or 'general': {ticket}",
model="gpt-4o-mini"),
ConditionalStep(
condition_key="classify",
branches={
"billing": billing_chain,
"technical": technical_chain,
"general": general_chain,
},
default=general_chain,
),
])Async Chains for Parallel Steps
Independent steps can run in parallel using an async chain:
from openclaw import AsyncChain, ParallelStep
chain = AsyncChain(steps=[
ParallelStep(name="gather", parallel=[
Step(name="competitors", prompt="List the top 5 competitors of {company}"),
Step(name="financials", prompt="Summarise recent financial news for {company}"),
Step(name="sentiment", prompt="Analyse social media sentiment for {company}"),
]),
Step(name="report",
prompt="Write an executive summary using:\n{competitors}\n{financials}\n{sentiment}"),
])
import asyncio
result = asyncio.run(chain.run(company="OpenAI"))Error Handling and Retry
chain = Chain(
steps=[...],
retry=2, # Retry failed steps up to 2 times
on_error="skip", # skip | raise | substitute
substitute="N/A", # Value to use if skipped
)- Chains are deterministic and predictable — prefer them when you know the steps in advance.
- Use agents for open-ended tasks; use chains for structured pipelines.
- Outputs flow between steps as named template variables
{step_name}. - Use
ConditionalStepfor branching logic without building a full agent. - Parallel steps reduce chain latency when steps are independent.
Error Handling in Chains
A prompt chain is only as reliable as its weakest step. Handle failures gracefully with per-step retry and fallback logic:
from openclaw import Chain, Step
chain = Chain([
Step("extract", "Extract the key facts from: {input}",
retry=3, fallback_output="No facts extracted."),
Step("verify", "Verify these facts are correct: {extract}",
timeout_seconds=30),
Step("format", "Format as bullet points: {verify}"),
])
# Access individual step outcomes
result = chain.run(input=document)
for step_name, step_result in result.steps.items():
if step_result.error:
print(f"{step_name} failed: {step_result.error}")
Chain Observability and Debugging
Prompt chains produce multi-step traces that help you diagnose quality issues in specific steps without re-running the full pipeline:
- Use
chain.run(return_trace=True)to capture all intermediate outputs for debugging - Each step’s input, output, token count, and latency are available in
result.trace - Export traces to OpenTelemetry for visualisation in Jaeger or Datadog
- Log step-level quality scores using a lightweight LLM-as-judge check on each step output