Mastering AI Agents: The Planner-Executor-Memory Pattern
1. Concept Introduction
At the heart of many sophisticated AI agents lies a simple yet powerful pattern: Planner-Executor-Memory. This architecture provides a structured way for an agent to reason, act, and learn.
For the Beginner: Imagine you’re building a piece of IKEA furniture. You first look at the instructions and make a high-level plan: “First, I’ll assemble the frame, then I’ll attach the doors, and finally, I’ll insert the shelves.” This is the Planner phase. Next, you pick up the screwdriver and start putting the pieces together, following your plan step-by-step. This is the Executor phase. As you work, you might jot down notes (“allen key #5 is the important one”) or simply remember which parts you’ve already used. This is your Memory.
For the Practitioner: The Planner-Executor-Memory pattern is a cognitive architecture for autonomous agents.
- Planner: A component (often a Large Language Model) that decomposes a high-level goal into a sequence of concrete, actionable steps. The output is a “plan,” which can be a simple list of tasks, a complex graph, or a formal planning language representation.
- Executor: A component that takes the plan and executes each step. This often involves invoking tools (e.g., calling an API, running a shell command, accessing a database), interacting with an environment, or generating a specific output. The executor’s role is to translate the “what” of the plan into the “how” of execution.
- Memory: A persistent or semi-persistent store that the agent uses to maintain state, record observations, and learn from its actions. This can range from a simple list of completed tasks to a sophisticated vector database for retrieval-augmented generation (RAG).
2. Historical & Theoretical Context
The idea of separating planning from execution is a cornerstone of classical Artificial Intelligence. Early AI systems like STRIPS (Stanford Research Institute Problem Solver), developed in the late 1960s, were based on this principle. STRIPS used a formal language to describe states, goals, and actions, and a planner to find a sequence of actions to achieve a goal.
The Planner-Executor model connects directly to the principles of means-ends analysis, a problem-solving technique where you work backward from the goal to identify the “means” (actions) to achieve it. In modern agents, LLMs have supercharged the planning component, allowing for more flexible and common-sense reasoning than was possible with classical planners.
3. Algorithms & Math
The core loop is straightforward and can be expressed in pseudocode:
function AgentLoop(goal):
memory = InitializeMemory()
plan = Planner(goal, memory)
while not plan.is_complete():
step = plan.get_next_step()
result = Executor(step)
memory.update(step, result)
if needs_replan(result):
plan = Planner(goal, memory) // Re-plan based on new info
return memory.get_final_result()
The needs_replan condition is critical. An agent that blindly follows a plan is brittle. The ability to re-plan based on unexpected outcomes or errors is what makes this architecture robust.
4. Design Patterns & Architectures
The Planner-Executor-Memory pattern is a high-level architectural pattern that can be implemented in various ways:
- Event-Driven Architecture: The executor can publish events (e.g.,
step_completed,error_occurred), and the planner can subscribe to these events to trigger re-planning. - State Machine: The agent’s state can be modeled as a state machine, where each step in the plan is a state transition.
- Blackboard System: The memory can be implemented as a “blackboard” where different components (planner, executor, sensors) can read and write information, allowing for more decoupled and opportunistic collaboration.
This pattern is the foundation of many agent frameworks. For example, in LangGraph, the planner might be one node in a graph, and the executor might be another, with the memory passed along the edges as the state object.
5. Practical Application
Here’s a simplified Python example of the pattern.
import json
def simple_planner(goal):
"""A mock planner that returns a fixed plan."""
print(f"Planner: Received goal - '{goal}'")
return [
{"tool": "search", "query": "latest AI agent research"},
{"tool": "write_file", "filename": "summary.txt", "content": "placeholder"}
]
def simple_executor(step):
"""A mock executor that simulates tool calls."""
print(f"Executor: Executing step - {step['tool']}")
if step["tool"] == "search":
# In a real agent, this would call a search API
return "Found a paper on 'Planner-Executor-Memory Pattern'."
elif step["tool"] == "write_file":
# In a real agent, this would write to the filesystem
return f"Successfully wrote to {step['filename']}"
def agent(goal):
"""The main agent loop."""
memory = {"goal": goal, "steps_taken": [], "observations": []}
plan = simple_planner(goal)
for step in plan:
result = simple_executor(step)
memory["steps_taken"].append(step)
memory["observations"].append(result)
# A simple re-planning trigger
if "error" in result.lower():
print("Re-planning might be needed here.")
# new_plan = simple_planner(goal) # Re-plan
print("
--- Agent Finished ---")
print(json.dumps(memory, indent=2))
# Run the agent
agent("Summarize the latest research on AI agents.")
In a framework like CrewAI, you define agents with goals and backstories (which informs the planner) and assign them tasks. The framework then orchestrates the execution of these tasks, managing the memory of what has been done.
6. Comparisons & Tradeoffs
Planner-Executor vs. Reactive Agents:
- Planner-Executor: Proactive, goal-oriented, can perform complex multi-step tasks. However, can be slow to react to sudden changes and the planning phase can be computationally expensive.
- Reactive Agents: Simple, fast, and robust to dynamic environments. They operate on a simple “if this, then that” logic. However, they lack foresight and cannot perform tasks that require long-term planning.
The choice depends on the problem. A self-driving car needs a reactive component to brake suddenly, but a research agent needs a planner to break down a complex query.
7. Latest Developments & Research
Recent research focuses on making the Planner-Executor loop more robust and efficient:
- Self-Correction: Papers like “Chain-of-Thought” and “Self-Refine” explore how LLMs can critique and improve their own plans and outputs, effectively creating a tighter loop between planning and execution.
- Tool-Use: Research on tool-formers and function-calling in LLMs is improving the executor’s ability to interact with the world reliably.
- Hierarchical Planning: For very complex tasks, agents are being developed with hierarchical planners that create high-level plans which are then broken down into sub-plans by more specialized agents.
8. Cross-Disciplinary Insight
This pattern has strong parallels with Daniel Kahneman’s “Thinking, Fast and Slow” in cognitive psychology.
- System 2 (Slow Thinking): This is our conscious, deliberate, and analytical mode of thought. It’s what we use to solve complex problems, make plans, and reason through logic. This is the Planner.
- System 1 (Fast Thinking): This is our automatic, intuitive, and effortless mode of thought. It’s how we react to immediate stimuli. This is the Executor, carrying out the well-defined steps of the plan.
A well-functioning agent, like a well-functioning human, needs both: the ability to plan deliberately and the ability to execute efficiently.
9. Daily Challenge / Thought Exercise
Your 30-Minute Challenge:
Modify the Python code example above to include a simple form of re-planning.
- Add a
stepto the plan that is designed to fail (e.g.,{"tool": "read_file", "filename": "non_existent_file.txt"}). - In the
simple_executor, detect this “failure” and return an error message. - In the main
agentloop, if an error is detected, call thesimple_planneragain to generate a new plan. For simplicity, the new plan can be a hard-coded “recovery” plan (e.g.,[{"tool": "search", "query": "how to handle file not found errors"}]).
This will give you a hands-on feel for how an agent can adapt when its initial plan goes wrong.
10. References & Further Reading
- STRIPS Paper (Classic): Fikes, R. E., & Nilsson, N. J. (1971). STRIPS: A New Approach to the Application of Theorem Proving to Problem Solving. Artificial Intelligence, 2(3-4), 189-208.
- LangGraph (Modern Framework): https://github.com/langchain-ai/langgraph - Explore the code to see how graphs can represent complex agent flows.
- “Self-Refine” Paper: Madaan, A., et al. (2023). Self-Refine: Iterative Refinement with Self-Feedback. arXiv preprint arXiv:2303.17651.