Prompt Chaining
Break it into steps.
Most successful AI products aren't really agents. They're workflows. The steps are fixed, written by you, and models fill in the judgment. They're cheaper, more predictable, and far easier to test. The experts' advice is clear. Start with a workflow, and only add autonomy if you have to.

- Most AI products are workflows
- Fixed steps, model judgment
- Cheaper and easier to test
Five patterns to know
Five patterns cover nearly everything. Chaining passes output from one step to the next. Routing sends each input down the right path. Parallelism does several things at once. Orchestrator workers splits up a job as it goes. And evaluator optimizer improves work in a loop. We'll build all of them.
A small helper
First, a helper, so that our examples stay short. Ask takes a prompt, plus an optional system message and a schema. Temperature is low, so that results are steady. From now on, we'll just import ask. This is also what we meant by keeping your model behind one function.
from google import genai
from google.genai import types
client = genai.Client()
def ask(prompt, system=None, schema=None):
config = types.GenerateContentConfig(temperature=0.2, system_instruction=system)
if schema:
config.response_mime_type = "application/json"
config.response_schema = schema
r = client.models.generate_content(model="gemini-flash-latest",
config=config, contents=prompt)
return r.parsed if schema else r.textA chain of small steps
An angry customer writes in. Instead of one huge prompt, we use small steps. First, pull out the facts. Then, write a draft from those facts. Then, a gate in plain code checks the length. And a last step checks that nothing was promised. Run it. There are the facts, and there's a calm reply. Each step is simple, and each one can be tested by itself. When something goes wrong, you know exactly which step did it.
from llm import ask
complaint = "Third time! Wheelset A17 wobbles at 30kph. I want my money back or I go to a rival."
facts = ask(f"List the facts in this complaint as three short bullets:\n{complaint}")
draft = ask(f"Write a calm two-sentence support reply based on these facts:\n{facts}")
if len(draft.split()) > 70:
draft = ask(f"Shorten this to fifty words:\n{draft}")
final = ask(f"Check this reply promises no refund. Fix it if it does. Return only the reply:\n{draft}")
print(facts)
print("---")
print(final)* This is the third time the issue has occurred. * Wheelset A17 wobbles at 30 kph. * The customer demands a refund or will switch to a competitor. --- I sincerely apologize for the frustration caused by your Wheelset A17 wobbling at 30 kph, especially understanding that this is the third time you have encountered this issue. We truly value your business and want to make this right; however, we are unable to offer a refund. Instead, I would be glad to assist you with a technical inspection or replacement under our warranty policy.
Also uses llm.py
from google import genai
from google.genai import types
client = genai.Client()
def ask(prompt, system=None, schema=None):
config = types.GenerateContentConfig(temperature=0.2, system_instruction=system)
if schema:
config.response_mime_type = "application/json"
config.response_schema = schema
r = client.models.generate_content(model="gemini-flash-latest",
config=config, contents=prompt)
return r.parsed if schema else r.textSummary
Small steps, with checks between them. That's chaining, and it's the most useful pattern of all. But not every message should follow the same path. Next, routing.
Key takeaways- Start with workflows
- Chain small steps
- Gates check between steps