Plan-Execute Pattern
The Plan-Execute pattern separates planning from execution. The agent first creates a comprehensive plan, then executes each step systematically. This pattern is ideal for complex, multi-step tasks that benefit from upfront planning.
Overview
Plan-Execute agents work in two distinct phases:
- Planning Phase - The LLM creates a detailed, step-by-step plan
- Execution Phase - Each step is executed in order using available tools
- Re-planning (optional) - Adjust the plan based on execution results
This pattern is inspired by classical AI planning systems and the Plan-and-Solve paper.
When to Use Plan-Execute
✅ Good for:
- Complex multi-step tasks
- Tasks requiring sequential execution
- When you need predictable execution order
- Tasks that benefit from upfront planning
- Long-running workflows
❌ Not ideal for:
- Simple, single-step tasks (use ReAct instead)
- Highly exploratory tasks (use ReAct instead)
- When flexibility is more important than structure (use ReAct instead)
- Real-time interactive applications (use ReAct instead)
Pattern Comparison
Not sure which pattern to use? See the Agent Patterns Overview for a detailed comparison of all patterns.
Basic Usage
import { createPlanExecuteAgent } from '@agentforge/patterns';
import { ChatOpenAI } from '@langchain/openai';
import { webScraper, calculator, fileWriter } from '@agentforge/tools';
const agent = createPlanExecuteAgent({
planner: {
model: new ChatOpenAI({ model: 'gpt-4' }),
maxSteps: 5
},
executor: {
tools: [webScraper, calculator, fileWriter],
parallel: false
},
maxIterations: 20
});
const result = await agent.invoke({
input: 'Research the top 5 programming languages in 2026, compare their popularity, and create a summary report.'
});
console.log('Plan:', result.plan);
console.log('Result:', result.response);Configuration Options
Core Options
interface PlanExecuteConfig {
// Required
planner: {
model: BaseChatModel; // Language model for planning
systemPrompt?: string; // Custom planning prompt
maxSteps?: number; // Max steps in a plan (default: 7)
includeToolDescriptions?: boolean; // Include tool info in planning
};
executor: {
tools: Tool[]; // Available tools for execution
model?: BaseChatModel; // Optional model for sub-tasks
parallel?: boolean; // Enable parallel execution
stepTimeout?: number; // Timeout per step (ms)
};
// Optional
replanner?: {
model: BaseChatModel; // Model for replanning decisions
replanThreshold?: number; // Confidence threshold (0-1)
systemPrompt?: string; // Custom replanning prompt
};
maxIterations?: number; // Max planning iterations (default: 5)
returnIntermediateSteps?: boolean; // [Not yet implemented] Include execution steps
verbose?: boolean; // [Not yet implemented] Enable verbose logging
checkpointer?: BaseCheckpointSaver; // State persistence
}Advanced Configuration
const agent = createPlanExecuteAgent({
planner: {
model: new ChatOpenAI({ model: 'gpt-4' }),
maxSteps: 5,
// Custom planning prompt
systemPrompt: `Create a detailed, step-by-step plan.
Each step should:
- Be specific and actionable
- Specify which tool to use
- Include expected outcomes
- Consider dependencies`
},
executor: {
tools: [webScraper, calculator, fileWriter],
parallel: false
},
replanner: {
model: new ChatOpenAI({ model: 'gpt-4' }),
replanThreshold: 0.7
},
maxIterations: 30,
// verbose: true // [Not yet implemented] Enable verbose logging for detailed execution trace
});How It Works
1. Planning Phase
The agent creates a structured plan:
// Example plan generated by the agent
{
steps: [
{
id: "step-1",
description: "Search for '2026 programming language popularity'",
tool: "web-search",
args: { query: "2026 programming language popularity" }
},
{
id: "step-2",
description: "Extract statistics for top 5 languages",
tool: "calculator",
args: { operation: "analyze" },
dependencies: ["step-1"]
},
{
id: "step-3",
description: "Write summary report to file",
tool: "file-write",
args: { path: "report.md" },
dependencies: ["step-2"]
}
]
}2. Execution Phase
Each step is executed sequentially:
for (const step of plan.steps) {
const result = await executeTool(step.tool, step.args);
// Check if re-planning is needed based on state
if (state.status === 'replanning' || state.iteration > 0) {
plan = await replan(plan, state.pastSteps);
}
}3. Re-planning
If a step fails or produces unexpected results:
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 10
},
executor: {
tools,
parallel: false
},
replanner: {
model,
replanThreshold: 0.7,
systemPrompt: `Re-evaluate the plan based on execution results.
If errors occurred, adjust the plan to work around them.
If confidence is low, create alternative approaches.`
}
});Customization
Custom Planning Prompt
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 10,
systemPrompt: `You are an expert planner.
Create a comprehensive plan with these requirements:
1. Break down the task into 5-10 clear steps
2. Identify dependencies between steps
3. Specify tools and parameters for each step
4. Include validation checkpoints
5. Plan for error handling
Format your plan as a numbered list with tool specifications.`
},
executor: {
tools,
parallel: false
}
});Custom Execution Strategy
import { createPlanExecuteAgent } from '@agentforge/patterns';
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 10
},
executor: {
tools,
parallel: true, // Enable parallel execution of independent steps
stepTimeout: 30000
}
});Streaming
Monitor planning and execution in real-time:
const stream = await agent.stream({
input: 'Complex research task'
});
for await (const chunk of stream) {
if (chunk.status === 'planning') {
console.log('Planning in progress...');
}
if (chunk.status === 'executing' && chunk.currentStepIndex !== undefined) {
const currentStep = chunk.plan?.steps[chunk.currentStepIndex];
console.log('Executing step:', currentStep?.id);
console.log('Description:', currentStep?.description);
}
if (chunk.pastSteps && chunk.pastSteps.length > 0) {
const lastStep = chunk.pastSteps[chunk.pastSteps.length - 1];
console.log('Completed:', lastStep.step.description);
console.log('Result:', lastStep.result);
}
}Best Practices
1. Provide Clear Task Descriptions
The quality of the plan depends on task clarity:
// ❌ Vague
const result = await agent.invoke({
input: 'Do some research'
});
// ✅ Clear and specific
const result = await agent.invoke({
input: `Research the environmental impact of electric vehicles:
1. Find recent studies (2024-2026)
2. Compare with traditional vehicles
3. Include manufacturing and lifecycle data
4. Create a summary with citations`
});2. Set Appropriate Step Limits
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 10
},
executor: {
tools,
parallel: false
},
maxIterations: 25 // Prevent runaway execution
});3. Enable Re-planning for Robustness
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 10
},
executor: {
tools,
parallel: false
},
replanner: {
model,
replanThreshold: 0.7 // Re-plan if confidence < 70%
}
});4. Use Checkpointer for Long Tasks
import { MemorySaver } from '@langchain/langgraph';
const checkpointer = new MemorySaver();
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 5
},
executor: {
tools,
parallel: false
},
checkpointer // Enable state persistence for resuming
});
// Use with thread_id to resume conversations
const result = await agent.invoke(
{ input: 'Complex task' },
{ configurable: { thread_id: 'task-123' } }
);Common Patterns
Research & Report Generation
import { webScraper, htmlParser, fileWriter } from '@agentforge/tools';
const researchAgent = createPlanExecuteAgent({
planner: {
model: new ChatOpenAI({ model: 'gpt-4' }),
maxSteps: 10,
systemPrompt: `Create a research plan:
1. Identify key topics to research
2. Search multiple sources for each topic
3. Synthesize findings
4. Generate structured report
5. Save to file with citations`
},
executor: {
tools: [webScraper, htmlParser, fileWriter],
parallel: false
},
maxIterations: 30
});Data Pipeline
import { fileReader, jsonParser, csvParser } from '@agentforge/tools';
const pipelineAgent = createPlanExecuteAgent({
planner: {
model: new ChatOpenAI({ model: 'gpt-4' }),
maxSteps: 10,
systemPrompt: `Create a data processing plan:
1. Read source data
2. Validate and clean data
3. Transform to target schema
4. Write to database
5. Verify data integrity`
},
executor: {
tools: [fileReader, jsonParser, csvParser],
parallel: false
}
});Multi-Source Analysis
import { httpGet, calculator, jsonParser } from '@agentforge/tools';
// Note: webScraper and chartGenerate are user-defined tools for this example
const analysisAgent = createPlanExecuteAgent({
planner: {
model: new ChatOpenAI({ model: 'gpt-4' }),
maxSteps: 10,
systemPrompt: `Create an analysis plan:
1. Gather data from all sources
2. Normalize and merge datasets
3. Perform statistical analysis
4. Generate visualizations
5. Create summary report`
},
executor: {
tools: [httpGet, calculator, jsonParser],
parallel: false
},
replanner: {
model: new ChatOpenAI({ model: 'gpt-4' }),
replanThreshold: 0.7
}
});Debugging
Inspect the Plan
const result = await agent.invoke(input);
console.log('Generated Plan:');
result.plan.steps.forEach((step, i) => {
console.log(`${i + 1}. ${step.description}`);
console.log(` Tool: ${step.tool || 'none'}`);
console.log(` Args: ${JSON.stringify(step.args || {})}`);
if (step.dependencies) {
console.log(` Dependencies: ${step.dependencies.join(', ')}`);
}
});Track Execution Progress
const result = await agent.invoke(input, {
callbacks: [{
handleToolStart: (tool, input) => {
console.log(`Starting: ${tool.name}`, input);
},
handleToolEnd: (output) => {
console.log('Completed:', output);
},
handleToolError: (error) => {
console.error('Error:', error);
}
}]
});Visualize Plan Execution
const result = await agent.invoke(input);
// Inspect execution steps
console.log('Execution Steps:');
result.pastSteps.forEach((step, i) => {
console.log(`${i + 1}. ${step.step.description}`);
console.log(` Status: ${step.status}`);
console.log(` Result: ${step.result}`);
});Performance Optimization
1. Parallel Execution
Execute independent steps in parallel:
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 10
},
executor: {
tools,
parallel: true, // Execute independent steps concurrently
stepTimeout: 30000
}
});2. Plan Caching
Cache plans for similar tasks using middleware:
import { withCache, createSharedCache } from '@agentforge/core';
const cache = createSharedCache({ maxSize: 100 });
// Apply caching to the planner node
// Note: This requires accessing the graph nodes directly
// For simpler caching, consider using the production preset
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 5
},
executor: {
tools,
parallel: false
}
});3. Incremental Execution
Resume from checkpoints:
import { MemorySaver } from '@langchain/langgraph';
const checkpointer = new MemorySaver();
const agent = createPlanExecuteAgent({
planner: {
model,
maxSteps: 10
},
executor: {
tools,
parallel: false
},
checkpointer
});
// Resume interrupted execution
const result = await agent.invoke(input, {
configurable: { thread_id: 'task-123' }
});Comparison with ReAct
| Feature | Plan-Execute | ReAct |
|---|---|---|
| Planning | Upfront, structured | Dynamic, iterative |
| Execution | Sequential | Flexible |
| Best for | Complex, multi-step | General purpose |
| Predictability | High | Medium |
| Adaptability | Medium (with re-planning) | High |
| Token usage | Higher (planning overhead) | Lower |
Next Steps
- ReAct Pattern - For flexible, iterative tasks
- Reflection Pattern - For self-improving agents
- Multi-Agent Pattern - For collaborative planning
- API Reference - Complete API documentation
Further Reading
- Plan-and-Solve Paper - Research paper
- LangGraph Planning - LangGraph tutorial
- Examples - Working code examples