Multi-Step Planning vs Reactive Loops
Should your agent plan the whole task upfront or figure it out step by step? A multi-step planning agent and a reactive loop fail in opposite ways. This guide helps you choose and combine them.
# Reactive loop: decide the next action fresh each step.
def reactive_loop(state, max_steps=12):
for _ in range(max_steps):
action = model_decide_next(state) # no plan, just "what now?"
if action.name == "finish":
return action.args["answer"]
state = update_state(state, action, run_tool(action))
return force_answer(state)
# Multi-step planning agent: make a plan, then execute it.
def planning_loop(state):
plan = model_make_plan(state) # ordered list of subtasks
for task in plan:
result = execute_subtask(state, task)
state = update_state(state, task, result)
if should_replan(state, plan): # reality diverged from plan
plan = model_make_plan(state)
return synthesize_answer(state)Should your agent plan the entire task before it acts, or just react one step at a time? It's the question every agent builder hits around their third project, usually right after a reactive loop wandered off task or a rigid plan shattered on the first surprise. The honest answer is that a multi-step planning agent and a reactive loop each win in situations where the other loses badly — and knowing which you're in is most of the skill.
This guide gives you a way to decide, code for both, and a hybrid that captures most of the upside of each.
Quick-Start (Copy This Right Now)
Here's the core of each style side by side, so you can feel the difference immediately.
[object Object],
,[object Object], ,[object Object],(,[object Object],):
,[object Object], _ ,[object Object], ,[object Object],(max_steps):
action = model_decide_next(state) ,[object Object],
,[object Object], action.name == ,[object Object],:
,[object Object], action.args[,[object Object],]
state = update_state(state, action, run_tool(action))
,[object Object], force_answer(state)
,[object Object],
,[object Object], ,[object Object],(,[object Object],):
plan = model_make_plan(state) ,[object Object],
,[object Object], task ,[object Object], plan:
result = execute_subtask(state, task)
state = update_state(state, task, result)
,[object Object], should_replan(state, plan): ,[object Object],
plan = model_make_plan(state)
,[object Object], synthesize_answer(state)What this does: The reactive loop asks "what's the best next action?" every step with no lookahead, while the multi-step planning agent commits to an ordered plan first and executes it, re-planning only when reality diverges — two fundamentally different control philosophies in a dozen lines.
Understanding the Variables
The choice hinges on three properties of your task.
Predictability is the first. If you can roughly know the steps in advance — "fetch data, clean it, analyze, report" — planning pays off, because a plan keeps the agent on a coherent arc instead of rediscovering the path each step. If the next step genuinely depends on what the last one returned in ways you can't foresee, reactive wins, because any plan you make will be obsolete by step two.
Interdependence is the second. Reactive loops excel when steps are loosely coupled and order barely matters. Planning excels when steps have strict dependencies and doing them out of order wastes work or breaks things.
Cost of a wrong turn is the third. Reactive agents can drift — chase a tangent, lose the thread of the original goal — because nothing holds the overall shape. A plan is a commitment that resists drift. When staying on task matters and drift is expensive, planning's rigidity becomes a feature.
There's a fourth factor people forget: the cost of planning itself. Making a plan is a model call, sometimes an expensive one if you ask for detail. For short tasks, that upfront call can cost more than the reactive loop would have spent total. A multi-step planning agent only earns its planning overhead when the task is long enough that the plan saves more steps than it costs to produce. On a three-step task, planning is pure tax; on a fifteen-step task with dependencies, it's a bargain. Estimate task length before you reach for planning.
The subtler cost is re-planning. Every time reality diverges from the plan, you pay for another planning call. A task that surprises the agent constantly will re-plan so often that you get all the cost of planning and all the chaos of reacting, with none of the benefit of either. If your task is that unpredictable, skip planning entirely and go reactive — you were never going to have a stable plan anyway.
⚡ Pro tip: Before adding planning, count how many steps your reactive loop currently averages. If it's under five, planning will very likely cost more than it saves. Planning's benefits — coherence, dependency handling, drift resistance — only compound over long horizons. On short tasks, a plan is a solution to a problem you don't have.
⚡ Pro tip: The classic failure of a multi-step planning agent is a beautiful plan that's wrong, executed faithfully to a wrong conclusion. The classic failure of a reactive loop is drift — competent individual steps that collectively wander off the goal. Name which failure would hurt you more, and you've largely made your choice.
Step-by-Step: Building a Hybrid That Beats Both
The best real-world agents are rarely pure. They plan at a coarse level and react within each phase. Here's how to build that.
Start with a lightweight plan — phases, not detailed steps. A good plan for a research agent is "gather sources, extract claims, cross-check, synthesize," not a rigid twelve-step script. Coarse plans give direction without brittleness.
[object Object], ,[object Object],(,[object Object],):
phases = model_make_plan(state) ,[object Object],
,[object Object], phase ,[object Object], phases:
state = react_within_phase(state, phase, max_steps=,[object Object],)
,[object Object], phase_failed(state):
phases = model_replan(state, remaining=phases)
,[object Object], synthesize_answer(state)
,[object Object], ,[object Object],(,[object Object],):
,[object Object], _ ,[object Object], ,[object Object],(max_steps):
action = model_decide_next(state, goal=phase) ,[object Object],
,[object Object], action.name == ,[object Object],:
,[object Object], state
state = update_state(state, action, run_tool(action))
,[object Object], stateWhat this does: It plans coarse phases up front for direction, then runs a scoped reactive loop inside each phase so the agent adapts to what it finds — combining the on-task discipline of planning with the flexibility of reacting.
The scoping is the trick. Inside
react_within_phaseOne decision you'll face: how much detail to put in each phase. The temptation is to specify heavily so execution is predictable, but heavy phases recreate the brittleness of a rigid plan. Keep each phase to a single clear objective and a success condition — "sources gathered" means at least three relevant documents in hand — and let the reactive loop inside decide how to get there. A phase you can state in one sentence with an obvious done-check is the right grain. If you can't state a phase without listing its steps, it's really a plan in disguise, and you've lost the flexibility that made the hybrid worth building.
⚡ Pro tip: Make phases explicit checkpoints for re-planning. After each phase, ask whether the remaining plan still makes sense given what you learned. Re-planning between phases is cheap and keeps the plan honest; re-planning mid-phase is chaotic. Phase boundaries are the right seam.
Pro-Level Variations
For a customer-onboarding agent with regulatory steps that must happen in order, lean heavily toward planning — the dependencies are real and the cost of skipping a step is a compliance violation.
For an exploratory data-analysis agent where each finding suggests the next question, lean reactive — no upfront plan survives contact with the data, and forcing one just wastes a planning call.
For a devops incident responder, use the hybrid: plan coarse phases (diagnose, isolate, mitigate, verify) but react hard within each, because the specifics of any incident are unknowable in advance while the overall shape is stable.
A pattern worth stealing from the strongest hybrid agents: let the plan carry the "why" and let the reactive loop handle the "how." The plan phase for a research agent might say "establish whether the outage was network-related — this matters because it determines who we page." That rationale travels into the reactive loop as context, so even as the agent improvises its specific searches, it never loses sight of what the phase is for. Plans that carry intent, not just steps, keep reactive execution aligned without micromanaging it.
There's also an underrated middle option: plan-as-you-go, where the agent maintains a running plan it revises every step rather than committing upfront or planning not at all. It's more expensive than either pure style but shines on tasks that are structured yet unpredictable — the agent always has a current best plan, and always updates it with what it just learned. Reserve this for high-value tasks where the extra planning calls are justified by the stakes.
Troubleshooting Common Issues
If your planning agent produces good plans but executes them into wrong answers, your re-planning trigger is too weak — it's not noticing when reality has diverged. Tighten
should_replanIf your reactive loop keeps drifting off the original goal, inject the goal into every step's context and add a periodic "does my recent work still serve the original question?" check. Reactive agents forget the destination; remind them.
If your hybrid re-plans constantly, your phases are too fine-grained. Coarsen them. Phases should be stable enough that you re-plan a handful of times per run, not every phase.
⚡ Pro tip: When debugging a planning agent, log the plan at creation and every plan revision. Most planning failures are visible in the plan itself — a missing phase, a wrong assumption baked in at step zero — long before they show up in the final answer. The plan is your best debugging artifact; a reactive loop gives you nothing comparable to inspect, which is another quiet argument for at least coarse planning on complex tasks.
⚠️ Common mistake: Choosing planning because it feels more "intelligent" and impressive. A detailed upfront plan looks sophisticated in a demo and often performs worse in production than a plain reactive loop, because real tasks surprise the plan constantly and each surprise forces an expensive re-plan. Match the control style to the task's actual predictability, not to which one looks smarter.
Your Turn
Classify your task on the three axes — predictability, interdependence, cost of a wrong turn — and start with the pure style that fits, then reach for the hybrid if you're straddling. Keep plans coarse, scope your reactive loops, and re-plan at phase boundaries.
The plan-generation prompts and the "still on track?" checks are worth saving once tuned, because you'll reuse them across every planning agent you build. A prompt library like PromptABCD lets you version your planning prompts, re-plan triggers, and phase-scoping wording in one place, so your next multi-step planning agent starts from a proven skeleton.
Continue Reading
Save the prompts from this post
PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.
