Workflow Patterns
Five composable patterns — chaining, routing, parallelization, orchestrator-workers, evaluator-optimizer — that cover most of what production agent systems actually do.
▶ Watch this reelWhat you'll learn
- Prompt chaining & routing
- Parallelization
- Orchestrator-workers
- Evaluator-optimizer
Remember this
- Chaining decomposes hard tasks into testable steps with validation between; routing specializes via classification with a shared output contract
- Parallelization: sectioning for throughput, voting for fuzzy-judgment reliability — with a designed merge and completeness checks
- Orchestrator-workers for tasks that can't be pre-split; evaluator-optimizer for checkable quality — with actionable critiques and honest exits
Chaining & routing
- Chain: extract → analyze → format; validate BETWEEN steps.
- Router: classify → specialized handler; shared output contract.
- Conditional logic in prose = smell; in code = architecture.
Parallelization
- Sectioning: split → gather → concat; assert completeness at merge.
- Voting: N runs → aggregate; for fuzzy judgments; design aggregator + tie policy.
- Formal criteria → mechanical verification, not votes.
Orchestrator-workers
- Dynamic decomposition when slices aren't knowable upfront.
- Compress worker returns; budget rounds/workers/cost.
- Prefer static sectioning when the split is knowable.
Evaluator-optimizer
- Generate → critique → refine; mechanical checks first.
- Actionable critiques; per-dimension evaluators; honest exits with history.
Code: Evaluator-optimizer, implemented
async def refine_until_pass(spec: str, checks: list[callable],
max_rounds: int = 3) -> Draft:
draft = await llm(GEN_PROMPT, spec=spec)
history = []
for round in range(max_rounds):
# mechanical checks first — free and honest
failures = [c(draft) for c in checks if not c(draft)]
if not failures:
return draft
# model judge for the non-mechanical criteria
critique = await llm(CRITIQUE_PROMPT, draft=draft,
failures=failures)
history.append({"round": round, "critique": critique})
draft = await llm(REFINE_PROMPT, spec=spec, draft=draft,
feedback=critique) # fix ONLY the gaps
# budget out → escalate with full history
await escalate_to_human(draft, history)
return draft # labeled 'unrefined' — never silently final