Skip to content

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:

  1. Planning Phase - The LLM creates a detailed, step-by-step plan
  2. Execution Phase - Each step is executed in order using available tools
  3. 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

typescript
import { createPlanExecuteAgent } from '@agentforge/patterns';
import { ChatOpenAI } from '@langchain/openai';
import { webScraper, calculator, fileWriter } from '@agentforge/tools';

const agent = createPlanExecuteAgent({
  model: new ChatOpenAI({ model: 'gpt-4' }),
  tools: [webScraper, calculator, fileWriter],
  maxExecutionSteps: 20
});

const result = await agent.invoke({
  messages: [{
    role: 'user',
    content: '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.messages[result.messages.length - 1].content);

Configuration Options

Core Options

typescript
interface PlanExecuteConfig {
  // Required
  model: BaseChatModel;           // The language model
  tools: StructuredTool[];      // Available tools

  // Optional
  maxExecutionSteps?: number;   // Max steps to execute (default: 25)
  maxPlanningIterations?: number;  // Max re-planning attempts (default: 3)
  returnIntermediateSteps?: boolean;  // Include execution steps
  enableReplanning?: boolean;   // Allow plan adjustments (default: true)
}

Advanced Configuration

typescript
const agent = createPlanExecuteAgent({
  model: new ChatOpenAI({ model: 'gpt-4' }),
  tools: [webScraper, calculator, fileWriter],

  // Execution limits
  maxExecutionSteps: 30,
  maxPlanningIterations: 5,
  
  // Enable re-planning based on results
  enableReplanning: true,
  
  // Return detailed execution trace
  returnIntermediateSteps: true,
  
  // Custom planning prompt
  planningPrompt: `Create a detailed, step-by-step plan.
  
Each step should:
- Be specific and actionable
- Specify which tool to use
- Include expected outcomes
- Consider dependencies`
});

How It Works

1. Planning Phase

The agent creates a structured plan:

typescript
// Example plan generated by the agent
{
  steps: [
    {
      id: 1,
      description: "Search for '2026 programming language popularity'",
      tool: "web-search",
      expectedOutcome: "List of top programming languages"
    },
    {
      id: 2,
      description: "Extract statistics for top 5 languages",
      tool: "calculator",
      expectedOutcome: "Numerical comparison data"
    },
    {
      id: 3,
      description: "Write summary report to file",
      tool: "file-write",
      expectedOutcome: "Report saved successfully"
    }
  ]
}

2. Execution Phase

Each step is executed sequentially:

typescript
for (const step of plan.steps) {
  const result = await executeTool(step.tool, step.params);
  
  // Check if re-planning is needed
  if (result.requiresReplanning) {
    plan = await replan(plan, result);
  }
}

3. Re-planning

If a step fails or produces unexpected results:

typescript
const agent = createPlanExecuteAgent({
  model,
  tools,
  enableReplanning: true,
  
  // Custom re-planning strategy
  replanningStrategy: async (plan, executionResult, error) => {
    if (error) {
      // Remove failed step and add alternative
      return adjustPlan(plan, executionResult);
    }
    return plan;
  }
});

Customization

Custom Planning Prompt

typescript
const agent = createPlanExecuteAgent({
  model,
  tools,
  planningPrompt: `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.`
});

Custom Execution Strategy

typescript
import { createPlanExecuteAgent, ExecutionStrategy } from '@agentforge/patterns';

const parallelStrategy: ExecutionStrategy = {
  async execute(plan, tools) {
    // Group independent steps
    const groups = groupIndependentSteps(plan.steps);
    
    // Execute each group in parallel
    for (const group of groups) {
      await Promise.all(
        group.map(step => executeTool(step.tool, step.params))
      );
    }
  }
};

const agent = createPlanExecuteAgent({
  model,
  tools,
  executionStrategy: parallelStrategy
});

Streaming

Monitor planning and execution in real-time:

typescript
const stream = await agent.stream({
  messages: [{ role: 'user', content: 'Complex research task' }]
});

for await (const chunk of stream) {
  if (chunk.planning) {
    console.log('Planning:', chunk.planning.currentStep);
  }
  if (chunk.execution) {
    console.log('Executing step:', chunk.execution.stepId);
    console.log('Result:', chunk.execution.result);
  }
}

Best Practices

1. Provide Clear Task Descriptions

The quality of the plan depends on task clarity:

typescript
// ❌ Vague
const result = await agent.invoke({
  messages: [{ role: 'user', content: 'Do some research' }]
});

// ✅ Clear and specific
const result = await agent.invoke({
  messages: [{
    role: 'user',
    content: `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

typescript
const agent = createPlanExecuteAgent({
  model,
  tools,
  maxExecutionSteps: 25,  // Prevent runaway execution
  maxPlanningIterations: 3  // Limit re-planning attempts
});

3. Enable Re-planning for Robustness

typescript
const agent = createPlanExecuteAgent({
  model,
  tools,
  enableReplanning: true,  // Adapt to unexpected results
  replanningThreshold: 0.7  // Re-plan if confidence < 70%
});

4. Use Checkpoints for Long Tasks

typescript
import { withCheckpointing } from '@agentforge/core';

const agent = withCheckpointing(
  createPlanExecuteAgent({ llm, tools }),
  {
    checkpointEvery: 5,  // Save state every 5 steps
    storage: 'redis'
  }
);

Common Patterns

Research & Report Generation

typescript
import { webScraper, htmlParser, fileWriter } from '@agentforge/tools';

const researchAgent = createPlanExecuteAgent({
  model: new ChatOpenAI({ model: 'gpt-4' }),
  tools: [webScraper, htmlParser, fileWriter],
  maxExecutionSteps: 30,
  planningPrompt: `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`
});

Data Pipeline

typescript
import { fileReader, jsonParser, csvParser } from '@agentforge/tools';

const pipelineAgent = createPlanExecuteAgent({
  model: new ChatOpenAI({ model: 'gpt-4' }),
  tools: [fileReader, jsonParser, csvParser],
  planningPrompt: `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`
});

Multi-Source Analysis

typescript
import { apiCall, webScrape, calculator, chartGenerate } from '@agentforge/tools';

const analysisAgent = createPlanExecuteAgent({
  model: new ChatOpenAI({ model: 'gpt-4' }),
  tools: [apiCall, webScrape, calculator, chartGenerate],
  enableReplanning: true,
  planningPrompt: `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`
});

Debugging

Inspect the Plan

typescript
const result = await agent.invoke(input, {
  returnIntermediateSteps: true
});

console.log('Generated Plan:');
result.plan.steps.forEach((step, i) => {
  console.log(`${i + 1}. ${step.description}`);
  console.log(`   Tool: ${step.tool}`);
  console.log(`   Expected: ${step.expectedOutcome}`);
});

Track Execution Progress

typescript
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

typescript
import { visualizePlanExecution } from '@agentforge/core';

const result = await agent.invoke(input, {
  returnIntermediateSteps: true
});

// Generate Gantt chart or flowchart
const diagram = visualizePlanExecution(result);
console.log(diagram);

Performance Optimization

1. Parallel Execution

Execute independent steps in parallel:

typescript
const agent = createPlanExecuteAgent({
  model,
  tools,
  executionMode: 'parallel',  // Execute independent steps concurrently
  maxParallelSteps: 3
});

2. Plan Caching

Cache plans for similar tasks:

typescript
import { withPlanCache } from '@agentforge/patterns';

const agent = withPlanCache(
  createPlanExecuteAgent({ llm, tools }),
  {
    ttl: 3600,
    similarityThreshold: 0.8
  }
);

3. Incremental Execution

Resume from checkpoints:

typescript
const agent = createPlanExecuteAgent({
  model,
  tools,
  resumeFromCheckpoint: true,
  checkpointStorage: 'redis'
});

// Resume interrupted execution
const result = await agent.invoke(input, {
  checkpointId: 'previous-run-id'
});

Comparison with ReAct

FeaturePlan-ExecuteReAct
PlanningUpfront, structuredDynamic, iterative
ExecutionSequentialFlexible
Best forComplex, multi-stepGeneral purpose
PredictabilityHighMedium
AdaptabilityMedium (with re-planning)High
Token usageHigher (planning overhead)Lower

Next Steps

Further Reading

Released under the MIT License.