Agent Planning and Task Decomposition
Every agent in this series so far has reasoned about its next real step one iteration at a time — genuinely reactive, deciding step 2 only after seeing step 1's result. This part covers a different, real technique: explicit, upfront planning before any real execution begins.
The real, genuine limit of pure step-by-step reasoning
Part 15's orchestrator, reasoning purely reactively: decides to call
account_setup_agent, THEN decides what's next — genuinely fine
for a simple, real task, but for a complex, real multi-step goal,
purely reactive reasoning can miss real, important dependencies
that only become obvious when the FULL task is considered upfrontAdding a real, explicit planning step
def create_plan(goal: str, available_tools: list[str]) -> list[str]:
response = client.messages.create(
model="claude-sonnet-5", max_tokens=1024,
system=(
f"Break this real goal into an ordered list of specific, "
f"concrete steps, using only these available real tools: "
f"{available_tools}. Output ONLY a numbered list."
),
messages=[{"role": "user", "content": goal}],
)
return parse_numbered_list(response.content[0].text)plan = create_plan(
"Onboard new GreenDesk customer Northwind Studios, 35-person team, Pro plan",
available_tools=["create_workspace", "assign_default_permissions", "generate_welcome_content", "schedule_kickoff_call"],
)Real, expected plan:
1. Create a GreenDesk workspace for Northwind Studios
2. Assign default permissions appropriate for a 35-person team
3. Generate personalized welcome content for the Pro plan
4. Schedule a kickoff callThis real, explicit plan is generated ONCE, upfront, seeing the entire real goal at once — genuinely different from part 15's orchestrator deciding one real step at a time with only partial visibility into what's still ahead.
An upfront plan lets a real, human reviewer see the AGENT'S FULL intended approach before any real execution happens — directly extending the confirmation pattern from the LLM & Advanced AI series' own guardrails coverage to the planning stage itself, not just individual destructive actions. Reviewing a 4-step plan is genuinely easier than reviewing each step's real justification after the fact.
Executing a real, pre-built plan, with real, per-step verification
def execute_plan(plan: list[str], tool_functions: dict) -> list[dict]:
results = []
for step in plan:
step_response = client.messages.create(
model="claude-sonnet-5", max_tokens=1024,
system=f"Execute this specific real step: {step}",
tools=tools, messages=[{"role": "user", "content": step}],
)
tool_call = next((b for b in step_response.content if b.type == "tool_use"), None)
if tool_call:
result = tool_functions[tool_call.name](**tool_call.input)
results.append({"step": step, "result": result})
# a real, genuine checkpoint — did this step actually
# succeed before moving to the next, potentially dependent one?
if not verify_step_success(result):
return results + [{"step": step, "result": "FAILED — halting remaining plan"}]
return resultsThis real, per-step verification directly connects to part 18's error-recovery coverage — a real, upfront plan doesn't eliminate the need for genuine, per-step error handling; it just makes the overall real structure more predictable and reviewable.
When upfront planning genuinely beats reactive reasoning
Genuinely worth planning upfront: a real, complex task with several
KNOWN, dependent steps (onboarding, this series' own example) —
seeing the whole real task at once helps the model correctly
sequence dependent steps
Genuinely NOT worth planning upfront: a real, open-ended task like
part 11's research agent, where the right NEXT step genuinely
depends on what a prior real search actually returned — reactive,
step-by-step reasoning is the more natural, correct fitForcing an explicit, upfront plan onto a genuinely open-ended, exploratory task like web research, where the correct next step structurally can't be known until a prior real step's actual result is seen. Planning helps most for tasks with real, knowable structure upfront — it adds real, unnecessary rigidity to genuinely adaptive, exploratory tasks.
FAQ
Can a plan be revised mid-execution if a step's result changes what's needed?
Not automatically in the version above — execute_plan halts on a failed step rather than replanning around it. A more capable version would call create_plan again with the failure context included, effectively blending upfront planning with the reactive approach part 15 uses, rather than treating them as mutually exclusive.
Is task decomposition the same thing as planning?
Closely related but not identical — decomposition is breaking a goal into sub-tasks; planning additionally orders and sequences those sub-tasks, including handling dependencies between them. create_plan here does both in one step, which is normal for a task simple enough not to need them separated.
How is verifying a step's success (verify_step_success) different from just checking the tool didn't error?
A tool call can return successfully while still not accomplishing the intended goal — create_workspace might return a 200 status for a workspace with the wrong settings. Real step verification checks the outcome matches what the step intended, not just that the call completed without an exception.
Next: error recovery and self-correction in agents — the real, practical handling every project in this series has deferred until now.