Problem
When planning and execution are interleaved in one loop, untrusted tool outputs can influence which action is selected next. That makes the control flow itself attackable: a malicious intermediate result can redirect the agent into unsafe tools or unauthorized operations.
Solution
Split reasoning into two phases:
- Plan phase – LLM generates a fixed sequence of tool calls before it sees any untrusted data.
- Execution phase – Controller runs that exact sequence. Tool outputs may shape parameters, but cannot change which tools run.
This separates strategic decisions from data-dependent execution. The planner commits to a bounded action graph up front, and the executor enforces that graph deterministically, which preserves flexibility on arguments while protecting control-flow integrity.
Benefits: Planning before execution improves task completion rates by 40-70% and reduces hallucinations by ~60% (Parisien et al., 2024).
plan = LLM.make_plan(prompt) # frozen list of calls
for call in plan:
result = tools.run(call)
stash(result) # outputs isolated from planner
How to use it
Great for email-and-calendar bots, SQL assistants, code-review helpers—any task where the action set is known but parameters vary.
Trade-offs
- Pros: Strong control-flow integrity; moderate flexibility.
- Cons: Content of outputs can still be poisoned (e.g., bad email body).
References
- Beurer-Kellner et al. (2025), §3.1 (2) Plan-Then-Execute.
- Parisien et al. (2024), "Deliberation Before Action: Language Models with Tool Use" – planning improves tool use accuracy from 72% to 94%.
- Boris Cherny (Anthropic): "Plan mode... you kind of have to understand the limits and where you get in the loop. Plan mode can 2-3x success rates pretty easily if you align on the plan first."
- Boris Cherny: "The boundary changes with every model... newer models are more intelligent so the boundary of what you need plan mode for got pushed out."
- AI & I Podcast: How to Use Claude Code Like the People Who Built It