Prompt chaining is the simplest and most predictable of the workflow patterns. It decomposes a task into a fixed sequence of LLM calls, where each call processes the output of the previous one. Unlike planning (Chapter 5), where the LLM decides the steps, prompt chaining uses a developer-defined pipeline.
┌────────┐ ┌────────┐ Gate ┌────────┐ ┌────────┐
│ Step 1 │───►│ Step 2 │───►(check)─►│ Step 3 │───►│ Step 4 │
│ (LLM) │ │ (LLM) │ │ │ (LLM) │ │ (LLM) │
└────────┘ └────────┘ │ └────────┘ └────────┘
│
┌────▼────┐
│ Fail │
│ (abort │
│ or fix)│
└─────────┘
The key insight: each step is a simpler task than the whole, and simpler tasks yield higher-quality LLM outputs. You trade latency (multiple sequential calls) for accuracy (each call is easier to get right).
# See code/prompt_chaining.py for the full implementation
def generate_article(llm, topic):
"""Generate an article through a chain of prompts."""
# Step 1: Research and outline
outline = llm.generate(
f"Create a detailed outline for an article about: {topic}\n"
f"Include 4-6 main sections with key points for each."
)
# Step 2: Gate - validate the outline
validation = llm.generate(
f"Review this outline for an article about '{topic}':\n{outline}\n\n"
f"Is it comprehensive, well-structured, and logically ordered? "
f"Answer YES or NO with a brief explanation."
)
if "NO" in validation.upper():
# Refine the outline
outline = llm.generate(
f"Improve this outline based on the feedback:\n"
f"Outline: {outline}\nFeedback: {validation}"
)
# Step 3: Write the article
article = llm.generate(
f"Write a complete article following this outline:\n{outline}\n"
f"Write in a clear, engaging style."
)
# Step 4: Edit and polish
final = llm.generate(
f"Edit this article for clarity, grammar, and flow:\n{article}\n"
f"Fix any issues and return the polished version."
)
return final
A distinguishing feature of prompt chaining is the use of gates — programmatic or LLM-based checks between steps that verify the intermediate output before proceeding:
# See code/prompt_chaining.py for the full implementation
def gate_check(llm, output, criteria):
"""Verify that output meets specified criteria."""
result = llm.generate(
f"Evaluate the following output against these criteria:\n"
f"Criteria: {criteria}\n"
f"Output: {output}\n\n"
f"Does the output meet all criteria? "
f"Respond with PASS or FAIL and explain."
)
return "PASS" in result.upper(), result
Gates can also be programmatic — checking for specific patterns, length constraints, or format requirements without involving the LLM:
def programmatic_gate(output, min_length=100, required_sections=None):
"""Non-LLM gate check."""
if len(output) < min_length:
return False, f"Output too short: {len(output)} < {min_length}"
if required_sections:
for section in required_sections:
if section.lower() not in output.lower():
return False, f"Missing required section: {section}"
return True, "All checks passed"
english_copy = llm.generate(f"Write marketing copy for: {product}")
french_copy = llm.generate(f"Translate to French:\n{english_copy}")
data = llm.generate(f"Extract key data points from:\n{document}")
structured = llm.generate(f"Convert to JSON format:\n{data}")
summary = llm.generate(f"Summarize the key findings:\n{structured}")
outline = llm.generate(f"Create an outline for: {topic}")
validated = llm.generate(f"Check this outline for completeness:\n{outline}")
draft = llm.generate(f"Write based on this outline:\n{validated}")
final = llm.generate(f"Edit for quality:\n{draft}")
analysis = llm.generate(f"Analyze this data:\n{data}")
recommendations = llm.generate(f"Based on this analysis, recommend actions:\n{analysis}")
report = llm.generate(f"Format as a professional report:\n{recommendations}")
Prompt chaining is ideal when:
| Aspect | Prompt Chaining | Planning | Agent Loop |
|---|---|---|---|
| Steps defined by | Developer | LLM | LLM |
| Predictability | High | Medium | Low |
| Flexibility | Low | High | High |
| Complexity | Low | Medium | High |
| Best for | Known workflows | Unknown workflows | Open-ended tasks |
Navigation: