Lesson 4.1: Planning and breaking a goal into steps
Learn how agents plan: plan first or step by step, how to write a plan with dependencies and checks, find the critical path, run steps in parallel and replan.
By the end of this lesson you will be able to explain the difference between planning everything first and deciding one step at a time, write a plan as structured steps with dependencies and checks, validate a plan in code before running it, find the critical path that sets how fast a job can finish, decide which steps can run in parallel, and say when a plan should be revised. You will take a six-step job that needs 85 seconds one step after another and show that it can finish in 60 seconds when independent steps run together, with the critical path running through steps B, D, E and F. You should have read Lessons 1.2, 3.1 and 3.4, which cover the loop, the job description and a first working agent. A little Python helps for the code example. The mathematics is addition and taking the largest of a few numbers.
The agent you built in Module 3 handled a short, nearly fixed task: two lookups and a reply. Real jobs are longer and vaguer. "Prepare the supplier payment summary for October" is not a single action, and no tool does it in one call. The agent has to decide what the parts are, in what order they must happen, which can overlap and how it will know each is done. That is planning, and how an agent plans decides whether a long task is finished well, finished slowly or never finished at all. This module covers three things that make longer work possible: planning, reasoning and memory. This lesson starts with planning.
Two ways to decide what to do
There are two basic styles, and most real agents blend them.
Step by step (reactive). The agent looks at where it is, chooses the next action, does it, looks again. It is the loop of Lesson 1.2 with no explicit plan. It adapts instantly to what each step reveals. Its weakness is that it can wander: with no overall picture it may do steps in an odd order, repeat itself, forget part of the goal or finish early.
Plan first, then execute. The agent first produces a plan, a list of the steps it intends to take, and then carries them out. The plan gives the work a shape. It can be shown to a person for approval before anything happens, checked by code for mistakes, and used as a checklist to measure progress. Its weakness is that the world does not always match the plan: a lookup returns something unexpected and step four no longer makes sense.
The usual answer is to combine them: plan, execute, and revise. The agent writes a plan, works through it, and after each step, or when something surprising happens, asks whether the plan still holds. If not, it replans, rewriting the remaining steps from the current position.
Style · Strength · Weakness · Best forStep by step · Adapts at once, no planning cost · Can wander, forget or stop early · Short tasks, highly uncertain tasks
Plan first · Shape, review, parallelism, progress tracking · Can go stale when facts change · Longer tasks with a knowable structure
Plan and revise · Both, at the price of extra calls · More moving parts · Most long tasks
Predict first: an agent must produce a monthly report that involves eight distinct steps, some of which can be done at the same time. Would you rather it decided step by step, or planned first? Decide before reading on.
Planning first, in most cases. With eight steps and some independence, a plan lets the work run in parallel, lets a person check the approach before an hour of work is done, and prevents the quiet failure in which a step-by-step agent forgets one of the parts. For a two-step task the planning call would cost more than it saves. The rule of thumb: the longer and more structured the task, the more a plan pays.
What a good plan looks like
A plan written as a loose paragraph of intentions is hard to check or run. A useful plan is structured data, with the same fields for every step.
Field · Purpose · Exampleid · A short name other steps can refer to · fetchpayments
description · What the step does, in one sentence · Get all payments made in October
tool or method · What will do it · getpayments tool
dependson · Which steps must finish first · [] or [fetchinvoices]
success check · How to tell the step worked · At least one payment row returned; total matches the ledger
on failure · What to do if it does not · Retry once, then escalate
The dependencies are the heart of it. Some steps need the output of others: you cannot total the payments before fetching them. Others are independent: fetching the invoices and fetching the payments need not wait for each other. Writing the dependencies down turns a list into a graph, and the graph tells you what can overlap.
The success check is the second important field. A step that has no way of being judged complete will be reported complete whenever the model feels done. A check can be a rule that code evaluates (the result has rows, the totals agree) or a question for a model to answer about the output. Either way it makes progress verifiable and catches errors early, when they are cheap to fix, instead of at the end, when they have spread through later steps. This is the remedy from Lesson 1.2 for compounding errors.
Good steps have the right size. A step should be one thing that a single tool call or a short sequence can do and that can be checked. "Prepare the report" is too big, because it hides everything. "Compute the total of the second invoice's third line" is too small, and wastes the plan's attention. A step that is too large can be broken further when its turn comes, which is called hierarchical planning: a short high-level plan, with each step expanded into detail only when the agent reaches it.
The graph and the critical path
Take a concrete job. An accounts agent prepares a payment summary with six steps. Each has an estimated duration, and some depend on others.
Step · What it does · Time (seconds) · NeedsA · Fetch October invoices · 10 · nothing
B · Fetch October payments · 20 · nothing
C · Match invoices to purchase orders · 15 · A
D · Match payments to bank records · 25 · B
E · Find the mismatches · 10 · C and D
F · Write the summary · 5 · E
If the agent does them one after another, the job takes 10 + 20 + 15 + 25 + 10 + 5 = 85 seconds. But A and B do not depend on each other, and neither do C and D. If the harness can run independent steps at the same time, the job's duration is set not by the total of all steps but by the longest chain of dependent steps, called the critical path.
Work out when each step can finish, assuming everything that can run in parallel does. A finishes at 10. B finishes at 20. C needs A, so it starts at 10 and finishes at 25. D needs B, so it starts at 20 and finishes at 45. E needs both C (25) and D (45), so it starts at 45 and finishes at 55. F finishes at 60. The whole job takes 60 seconds, a saving of 25 seconds, or 29 per cent. The critical path is B, then D, then E, then F: 20 + 25 + 10 + 5 = 60. Any delay to one of those steps delays the whole job. A delay of 5 seconds to step A, however, changes nothing, because A has slack: C could start as late as second 20 without holding up D.
This tells the planner where to put effort. Speeding up step C by five seconds saves nothing, since D finishes later. Speeding up D by five saves five seconds in total. Optimise the critical path, and leave the steps with slack alone.
Parallelism has limits
Running steps together saves time but not effort: it costs the same model calls, and the extra requests still need capacity. More important, parallel steps cannot see each other's results, so they must be truly independent, or they may duplicate work or conflict. There is a practical limit on the number of workers too. With n independent steps of t seconds each and w workers, the time is t multiplied by the number of rounds, which is n divided by w rounded up.
Checking a plan before running it
Because a plan is structured data, code can check it. A model can write a plan that sounds sensible and is broken: a step depends on one that does not exist, two steps depend on each other so neither can start, a step has no success check, or a tool is named that the agent does not have. Catching these costs nothing, and running a broken plan can cost a great deal.
A plan validator should check at least:
every step has an id, a description, a tool and a success check;
every dependency refers to a step that exists;
there are no cycles, meaning no step depends, directly or through others, on itself;
every tool named is one the agent actually has;
the plan is not larger than a limit, for example no more than 12 steps;
for write actions, there is an approval step before them.
If the check fails, the validator returns the problems to the model in plain words, exactly as a tool validator does, and the model writes a corrected plan. For higher-stakes work, a person approves the plan before execution: reading eight lines is much easier than reviewing eight actions after the fact.
Replanning
A plan is a hypothesis. Revise it when its assumptions fail. The usual triggers are:
A step fails its check, and retrying will not help.
A result is unexpected: the invoice list is empty, or the amounts differ from what the plan assumed.
New information changes the goal, for instance the user adds a constraint partway through.
A step takes much longer or costs much more than estimated.
A fixed number of steps has passed, as a routine review.
When replanning, keep what is done. The agent gives the model the original goal, the plan, the completed steps with their results and the reason for revision, and asks for a new plan for the remaining work only. Replanning has a cost, one more model call and the risk of unsettling a good plan, so set a limit, such as three revisions, after which the agent escalates. A task that needs constant replanning is often a sign that it was not understood.
Replanning calls add up. A job of n steps costs n calls for the steps, one call to plan and one for each replan. With 8 steps, one plan and two replans, that is 11 calls instead of the 8 that a step-by-step agent would make. In return the agent has a shape, checks and approval. Whether that is worth it depends on the length and stakes of the task, which is exactly the judgement the style table above summarises.
Common planning failures
Over-planning. A twelve-step plan for a two-step job wastes calls and invites errors. Plan in proportion to the task.
Under-specified steps. "Handle the exceptions" cannot be done or checked. Each step needs a clear action and test.
Hidden dependencies. A plan that says two steps are independent when one needs the other's output produces wrong results when run in parallel.
Stale plans. The agent keeps following a plan that the evidence has overtaken. Check after each step.
Hallucinated steps. The plan names tools that do not exist, or assumes data that is not available. Validate against the real tool list.
Never finishing. Plans that expand at each step, with no end condition. Cap the steps and the replans.
No progress record. Without marking steps done, the agent may repeat finished work. Keep the status of each step.
A planner in code
The following program represents a plan as data, validates it, computes the critical path and the earliest finish of each step, orders the steps into rounds that can run in parallel, and shows a simple replan. It uses only the standard library.
python
from graphlib import TopologicalSorter, CycleError
PLAN = {
"A": {"what": "Fetch October invoices", "tool": "getinvoices", "seconds": 10, "needs": [], "check": "rows > 0"},
"B": {"what": "Fetch October payments", "tool": "getpayments", "seconds": 20, "needs": [], "check": "rows > 0"},
"C": {"what": "Match invoices to purchase orders", "tool": "matchorders", "seconds": 15, "needs": ["A"], "check": "all matched or listed"},
"D": {"what": "Match payments to bank records", "tool": "matchbank", "seconds": 25, "needs": ["B"], "check": "all matched or listed"},
"E": {"what": "Find the mismatches", "tool": "compare", "seconds": 10, "needs": ["C", "D"], "check": "list produced"},
"F": {"what": "Write the summary", "tool": "writereport", "seconds": 5, "needs": ["E"], "check": "under 300 words"},
}
AVAILABLETOOLS = {"getinvoices", "getpayments", "matchorders", "matchbank", "compare", "writereport"}
def validateplan(plan, tools, maxsteps=12):
"""Return a list of problems in plain words; an empty list means the plan is acceptable."""
problems = []
if len(plan) > maxsteps:
problems.append(f"The plan has {len(plan)} steps; the limit is {maxsteps}.")
for sid, step in plan.items():
for field in ("what", "tool", "check"):
if not step.get(field):
problems.append(f"Step {sid} has no {field}.")
if step.get("tool") not in tools:
problems.append(f"Step {sid} uses tool '{step.get('tool')}', which does not exist.")
for dep in step.get("needs", []):
if dep not in plan:
problems.append(f"Step {sid} needs '{dep}', which is not in the plan.")
try:
list(TopologicalSorter({s: st["needs"] for s, st in plan.items()}).staticorder())
except CycleError:
problems.append("The steps depend on each other in a circle, so none can start.")
return problems
def schedule(plan):
"""Earliest finish of every step, the total time with parallel running, and the critical path."""
finish, via = {}, {}
for sid in TopologicalSorter({s: st["needs"] for s, st in plan.items()}).staticorder():
needs = plan[sid]["needs"]
start = max((finish[d] for d in needs), default=0)
finish[sid] = start + plan[sid]["seconds"]
via[sid] = max(needs, key=lambda d: finish[d]) if needs else None
last = max(finish, key=finish.get)
path, node = [], last
while node:
path.append(node)
node = via[node]
return finish, finish[last], list(reversed(path))
def rounds(plan):
"""Groups of steps that can run at the same time."""
sorter = TopologicalSorter({s: st["needs"] for s, st in plan.items()})
sorter.prepare()
out = []
while sorter.isactive():
ready = sorted(sorter.getready())
out.append(ready)
sorter.done(ready)
return out
print(validateplan(PLAN, AVAILABLETOOLS))
finish, total, path = schedule(PLAN)
print(finish, "total", total, "critical path", path, "against", sum(s["seconds"] for s in PLAN.values()), "in sequence")
print(rounds(PLAN))
a broken plan: a missing dependency, an unknown tool and a circle
bad = {"X": {"what": "a", "tool": "magic", "seconds": 1, "needs": ["Y"], "check": "ok"},
"Y": {"what": "b", "tool": "compare", "seconds": 1, "needs": ["X"], "check": "ok"},
"Z": {"what": "c", "tool": "compare", "seconds": 1, "needs": ["Q"], "check": ""}}
for problem in validateplan(bad, AVAILABLETOOLS):
print("-", problem)
replanning: keep finished steps, rewrite the rest after step D fails its check
done = {"A", "B", "C"}
remaining = {s: {st, "needs": [d for d in st["needs"] if d not in done]} for s, st in PLAN.items() if s not in done}
remaining["D2"] = {"what": "Match payments by amount and date only", "tool": "matchbank", "seconds": 30, "needs": [], "check": "all matched or listed"}
remaining["E"]["needs"] = ["D2"]
del remaining["D"]
print(validateplan(remaining, AVAILABLETOOLS), schedule(remaining)[1:])
Running it shows the plan accepted, a total of 60 seconds along the path B, D, E, F, four rounds of parallel work, four clear complaints about the broken plan and a replanned remainder that is still valid, finishing in 45 more seconds. Notice that the validation and the scheduling are ordinary code. The model only writes the plan; the harness checks it, orders it and runs it.
Common mistakes
Planning every task. A short fixed task needs no plan. Plan when the work is long or structured.
Plans as loose prose. Use structured steps with ids, tools, dependencies and checks, so code can verify them.
No success checks. A step with no test will be called finished when the model feels done.
Trusting stated independence. Check dependencies, and run in parallel only when steps truly do not need each other.
Optimising the wrong steps. Time is set by the critical path. Steps with slack do not matter.
Never revising. Check after each step, and replan when the evidence changes.
Unlimited replanning. Cap the revisions and escalate. Constant replanning means the task is not understood.
Skipping validation. A plan with a missing dependency or a circle can be caught in milliseconds.
No approval for risky plans. A person can read a plan in a minute; reviewing actions after they happen is harder.
Key takeaways
Agents decide either step by step or by planning first. Most long tasks do best with plan, execute and revise.
A good plan is structured data: each step has an id, a tool, dependencies, a success check and a failure response.
Dependencies turn the plan into a graph. The longest chain, the critical path, sets how fast the job can finish. In the example, 85 seconds in sequence falls to 60 with parallel running, along B, D, E, F.
Speed up the critical path; steps with slack change nothing.
Validate plans in code for missing fields, unknown tools, missing dependencies, circles and size, and let a person approve plans for risky work.
Replan when a check fails, a result surprises you or the goal changes. Keep finished work, cap the revisions and escalate when the cap is hit.
Check yourself
1. Why is a success check on each step valuable?
It makes progress verifiable and catches errors when they are cheap to fix, before they spread through later steps.
2. Steps P (10 s) and Q (15 s) are independent, and R (5 s) needs both. How long does the job take with parallel running, and without?
With parallel running: 15 + 5 = 20 seconds. In sequence: 10 + 15 + 5 = 30 seconds.
3. In question 2, what is the critical path, and does speeding up P by 3 seconds help?
Q then R. Speeding up P does not help because P has slack: Q finishes later.
4. Ten independent steps of 6 seconds each run on 4 workers. How long do they take?
Rounds: 10 ÷ 4 rounded up is 3. Time: 3 × 6 = 18 seconds.
5. Name two things a plan validator should check.
For example that every dependency exists, that there are no circular dependencies, that every tool named is real, and that each step has a success check.
6. What should the agent give the model when it replans?
The goal, the original plan, the completed steps with their results, and the reason for revision, asking for a plan for the remaining work only.
Try this
Set aside seventy-five minutes.
1. Take a job with five to eight steps, such as preparing a monthly report. Write each step with an id, a tool, a time estimate, dependencies and a success check.
2. Draw the graph. Mark which steps are independent.
3. Compute the earliest finish of each step, the total with parallel running, and the critical path. Check the numbers with the code in this lesson by replacing the plan.
4. Identify a step with slack, and a step on the critical path. Decide which one is worth speeding up.
5. Break the plan on purpose in three ways: a missing dependency, a circle and an unknown tool. Check that the validator catches each.
6. Decide the triggers for replanning and the cap on revisions. Write what the agent should do at the cap.
7. Use the simulator to compare running eight of your steps with one, two and four workers.
A good result is a structured plan that passes validation, a critical path with times, a list of steps that can run in parallel and a written replanning rule. The next lesson looks at how an agent thinks within a step: prompting it to reason, act and check its own work.
Tags: Agentic AI Agent planning Task decomposition Critical path AI agents