The Workflow Agent
A single ReAct loop handles most one-shot tasks, but harder problems sometimes need structure that decides work before the next tool result arrives. A workflow agent means an agent system where your harness controls a workflow: a graph of model calls, deterministic code steps, tool calls, and specialist loops. This shape helps when sub-tasks that run in parallel can share results, when a plan can be written before tools run, or when routing should follow a rule instead of the last observation.
The harness can scope a workflow around a model call, a deterministic step, a specialist loop, or a group of parallel branches. At each boundary, it decides what context crosses, what can branch, and which results feed the next pipeline stage. Fan-out and fixed routing make that control visible without replacing the ReAct loop from the previous page.
Two key patterns that differ in when the model decides
ReAct (Reason + Act)
At each step the model reads the latest observation before it picks an action
and runs a tool, then sizes up whatever came back and chooses again. The agent
reacts to whatever the previous tool call returned, so the path
through the tools takes shape as it runs. That makes ReAct strong when the
path depends on intermediate results and weak when many steps could have
run at once.
Paper: Yao et al., 2022.
ReWOO (Reason Without Observation)
The model writes the full plan upfront in one LLM call before any tool runs at
all. A deterministic executor then runs every tool that the plan named, often in
parallel, and a second LLM call reads what came back to synthesize the results.
Because the plan never sees a tool result, the model "reasons without observation."
That makes ReWOO strong when the steps are independent and weak when later steps
need to react to earlier ones.
Paper: Xu et al., 2023.
When a single loop beats splitting into agents
Without independent workstreams, the coordination overhead of multi-agent composition buys nothing, and one plain loop stays faster and easier to debug.
That tax is fixed regardless of the task, so the question becomes whether the work returns enough to cover it. A linear job that one prompt already handles will never recoup the extra calls and the routing logic that they require. The split begins to earn its keep only once the task itself carries the kind of structure that a single loop has no choice but to flatten down into one timeline. Any one of the conditions below makes the trade pay off.
- Specialization matters. Different workstreams need different system prompts, tools, or models. One agent forced into both roles degrades both.
- Parallelism is possible. Two workers run concurrently, where one agent could only run them in sequence. Three independent searches finish in the time of the slowest.
- Context bloat is real. A single agent doing everything accumulates 10000-token context. Specialists stay focused on their slice.
- Failure isolation helps. A crashed worker does not kill the whole task. The orchestrator retries, skips, or routes around it.
Applied · PipelineRun the full plan-execute-synthesize pipeline?
Running a ReWOO pipeline against the NVIDIA glossary
The cell below runs a ReWOO pipeline against the NVIDIA glossary, using
helpers.webSearch (the ranked glossary search you met in Module 1c) for every retrieval the plan calls for. The glossary explorer shows the full index this searches and lets you run any query the planner might emit:
Promise.all is JavaScript's helper for starting several promises and waiting
until all of them finish. Here it is just the concurrency mechanism: it does not call
the model and it does not decide which searches to run.
- Planner. One schema-bound LLM call emits a JSON list of 3-5 search queries.
- Executor. Plain JavaScript. Every query runs concurrently via
Promise.all, with no LLM calls at this stage. - Synthesizer. A second LLM call reads every result and writes the brief, citing each search by index.
Two LLM calls total, plus N parallel glossary searches. Edit the research goal and watch the planner's query list change.
Routing a ticket to one specialist with a fixed enum
Routing is a different shape of multi-agent in which a triage agent classifies the input and hands it to one specialist. Because the classifier must emit one of a fixed enum of categories, the output needs a tight contract. A fixed enum is a closed list of allowed labels; if the model returns anything else, the router should reject the route or retry under stricter instructions instead of guessing. Each specialist downstream owns a narrow system prompt and does not need to see the triage agent's reasoning.
Fanning one shared input out to specialists at once
The ReWOO pipeline was parallel by construction, since every query it planned ran concurrently against the glossary. A more common parallel pattern fans one shared input out to several specialists that each carry their own system prompt and all run at once. In the trace, total wall time tracks the slowest specialist while the others overlap inside that window, the Gantt chart shows each specialist's duration, and all specialists share one web-search result so cost stays bounded.
Deep · FactoryFactor repeated specialists into one declaration?
Declaring specialists from a factory instead of hand-writing each
Each of the four exercises above built a small agent by hand from the same few pieces of boilerplate that production code should never have to retype for every new specialist. Those pieces are a role label, a system prompt, a tool list, and an invocation. The factory pattern parameterises those four moving parts, so you declare specialists instead of writing them:
- Role. A short label, used for logs and routing.
- System prompt. The behaviour contract: what it does, what it refuses, and how it phrases its replies.
- Tools. The JSON-Schema-described functions it can call, if any.
- Invoke contract. A consistent shape (
specialist.run(input)) that returns the final reply.
CrewAI,
LangChain, and
LangGraph
all expose this same factory under names that vary by framework, whether
Agent or create_agent or a role/goal dataclass.
The cell below builds two specialists from the same four parameters, an
arithmetic tutor and a translator that both run on one input with their replies
rendered side by side.
Before you continue
- The ReWOO planner above emits a JSON list of queries. What is the failure mode if a later query needs a fact from an earlier query's result? Which of the two patterns from the top of this page do you switch to?
- The triage router has a fixed enum of categories. What should the router do if the model emits a category that is not in the enum? Is the JSON schema enough by itself, or do you also need application-side validation?
- The factory exercise parameterises four things (role, system prompt, tools, invoke). What would you add as a fifth parameter to prevent a specialist from drifting into another specialist's domain when the input is ambiguous?
References
- Xu et al., ReWOO: Decoupling Reasoning from Observations (2023). The planner / worker / solver decomposition this module's Workflow Agent implements.
- Wang et al., Plan-and-Solve Prompting (2023). The simpler ancestor: a single LLM call writes a plan, the same LLM executes step-by-step. ReWOO splits planner from executor.
- Madaan et al., Self-Refine: Iterative Refinement with Self-Feedback (2023). The pattern behind iterative multi-pass research: an agent critiques its own output and re-runs until a quality threshold is met.
- LangGraph. The production framework that formalises the workflow / state-machine pattern this module sketches by hand.
Comprehensive list at Going Further · References.
Try it · the triage router, live
Ask a support question and the artifact classifies it into one category with a single model call before it routes that ticket to the matching specialist's system prompt and streams the answer back in that voice. It runs the same classify-then-specialist pattern shown above. The categories here are a customer-support set rather than the IT help-desk enum. Its four values are billing, technical, account, and other. Only the category list changes when the domain changes, while the routing mechanism underneath stays identical.