Parallelization assumes you know the split when you write the code: six criteria, six calls. Plenty of real tasks are not like that. "Update every call site affected by this API change" has a shape that depends on the codebase, and you cannot enumerate the subtasks in advance.
Orchestrator-workers moves the decomposition to run time. A central model looks at the task, decides what the subtasks are, dispatches them, and synthesises the results.
┌─────────────┐
task ──────► │ orchestrator│ ── decides the split at run time
└──────┬──────┘
┌─────────┼─────────┐
worker worker worker ── each gets one scoped subtask
└─────────┼─────────┘
┌──────▼──────┐
│ synthesise │
└─────────────┘In code, the shape is three calls with a fan-out in the middle:
// 1. the orchestrator decides the split, returning structure rather than prose
const { object: plan } = await generateObject({
model,
schema: z.object({
subtasks: z.array(z.object({ file: z.string(), instruction: z.string() })),
}),
prompt: `Break this into independent subtasks: ${task}`,
})
// 2. workers run concurrently, each with a clean context holding only its piece
const results = await Promise.all(
plan.subtasks.map((s) => runWorker(s.instruction, s.file))
)
// 3. synthesis, which sees results and not the workers' intermediate noise
return synthesise(task, results)Note what the orchestrator never sees: how each worker got there. It receives outcomes, which is what keeps its own context small enough to reason about the whole job.
What it buys
- The split adapts. Three files or thirty, the same code handles it.
- Workers get clean context. Each sees one subtask, not the whole job, which is usually why quality improves rather than just latency.
- The orchestrator keeps the overview without holding every worker's intermediate noise. It sees results, not transcripts.
Where it goes wrong
- Bad decomposition is invisible. If the orchestrator splits badly, every worker does good work on the wrong pieces, and the output looks thorough. This is the failure mode to watch, and it argues for logging the plan the orchestrator produced.
- Synthesis is the hard part. Combining conflicting worker output is genuinely difficult, and it is where the pattern is usually underbuilt.
- Cost multiplies. One task becomes N+2 calls. For a task with a knowable split, plain parallelization is cheaper and more predictable.
When to reach for it
Only when the decomposition genuinely cannot be written in advance. If you find yourself able to describe the subtasks while writing the prompt, you want parallelization or prompt chaining, both of which are easier to debug.
Related terms
Parallelization
Parallelization runs several model calls at once and combines the results, either by splitting a task into independent parts or by asking the same question repeatedly and aggregating. It buys latency in one form and reliability in the other.
Read definition →ConceptAgents vs. workflows
A workflow follows a path you designed in advance; an agent decides its own path at run time by calling tools in a loop toward a goal. Knowing which one you actually need is the first context-engineering decision.
Read definition →PatternProvenPrompt chaining
Prompt chaining breaks a task into a fixed sequence of steps, feeding each step’s output into the next. It is the simplest workflow pattern, and it beats one giant prompt whenever a task has natural stages.
Read definition →PatternValidatedEvaluator-optimizer
Evaluator-optimizer pairs a generator with a separate critic that scores its output and sends it back for revision. It works when quality is easier to judge than to produce, which is more often than you would expect.
Read definition →