Skip to content

Planning Fundamentals

Overview

Planning is the process of breaking down complex goals into manageable sub-goals and determining the sequence of actions needed to achieve them.

Without planning, agents become reactive (responding to immediate situations). With planning, agents become goal-directed (working systematically toward objectives).


The Planning Problem

Without Planning

User: "Write a comprehensive report on AI trends"

Agent (reactive):
→ Generates random paragraphs about AI
→ No structure, no coherence
→ Misses key points
→ Quality: Poor

With Planning

User: "Write a comprehensive report on AI trends"

Agent (planned):
1. Define report structure
 - Introduction (1 page)
 - Current trends (3 pages)
 - Impact analysis (2 pages)
 - Future predictions (1 page)
 - Conclusion (1 page)

2. Research each section
3. Write each section
4. Integrate into coherent report
5. Review and edit

Quality: Excellent

Core Concepts

Goal Hierarchy

Breaking one large goal into smaller sub-goals:

Top-Level Goal: "Analyze market for Product X"
 │
 - Sub-Goal 1: "Research competitive landscape"
 - Find competitors
 - Analyze their products
 - Compare features
 │
 - Sub-Goal 2: "Analyze customer needs"
 - Survey existing customers
 - Analyze feedback
 - Identify gaps
 │
 - Sub-Goal 3: "Assess financial viability"
 - Estimate development cost
 - Project revenue
 - Calculate ROI

Ordering & Dependencies

Some tasks must happen in order, others can be parallel:

Sequential (one then another):
 Research → Analysis → Report
 [Can't analyze before researching]

Parallel (simultaneously):
 - Competitive Analysis
 - Customer Research
 - Market Research
 [All can happen at same time]

Hybrid:
 Research (parallel) → Analysis (sequential) → Report

Planning Strategies

Strategy 1: Hierarchical Planning (Top-Down)

Break large goal into progressively smaller sub-goals.

class HierarchicalPlanner:
 def plan(self, goal: str) -> List[str]:
 """Break goal into hierarchical sub-goals"""

 # Level 1: Main phases
 phases = self.llm.decompose_into_phases(goal)
 # ["Research phase", "Analysis phase", "Report phase"]

 # Level 2: Sub-tasks per phase
 all_tasks = []
 for phase in phases:
 subtasks = self.llm.decompose_into_tasks(phase)
 all_tasks.extend(subtasks)

 # Level 3: Specific actions
 all_actions = []
 for task in all_tasks:
 actions = self.llm.decompose_into_actions(task)
 all_actions.extend(actions)

 return all_actions

# Example execution
planner = HierarchicalPlanner()

plan = planner.plan("Write comprehensive market analysis report")
# Output:
# 1. Research
# 2. Research
# 3. Research
# 4. Analysis
# 5. Analysis
# 6. Report
# 7. Report
#... etc

Pros:

  • Systematic and organized
  • Easy to understand
  • Good for structured tasks

Cons:

  • May miss dependencies
  • Rigid structure
  • Doesn't handle surprises well

Strategy 2: Dependency-Based Planning

Identify dependencies between tasks, then order them:

class DependencyPlanner:
 def plan(self, goal: str) -> List[str]:
 """Plan by identifying dependencies"""

 # Get all tasks
 tasks = self.llm.list_tasks(goal)
 # ["research", "analysis", "writing", "editing"]

 # Identify dependencies
 dependencies = {}
 for task in tasks:
 deps = self.llm.identify_dependencies(task)
 dependencies[task] = deps

 # Topological sort (order by dependencies)
 ordered_tasks = self.topological_sort(dependencies)

 return ordered_tasks

 def topological_sort(self, dependencies):
 """Order tasks respecting dependencies"""
 result = []
 visited = set()

 def visit(node):
 if node in visited:
 return
 visited.add(node)

 for dep in dependencies.get(node, []):
 visit(dep)

 result.append(node)

 for task in dependencies:
 visit(task)

 return result

# Example
planner = DependencyPlanner()
plan = planner.plan("Launch new product")
# Automatically handles:
# - Design must come before manufacturing
# - Marketing must come before launch
# - But testing can happen in parallel

Strategy 3: Constraint-Based Planning

Plan while respecting constraints (time, budget, resources):

class ConstraintPlanner:
 def plan(self, goal: str, constraints: dict) -> List[str]:
 """Plan respecting constraints"""

 max_time_hours = constraints.get('time', float('inf'))
 max_budget = constraints.get('budget', float('inf'))
 available_resources = constraints.get('resources', [])

 # Generate candidate tasks
 all_tasks = self.llm.list_all_tasks(goal)

 # Estimate time and cost for each
 task_metrics = {}
 for task in all_tasks:
 task_metrics[task] = {
 'time': self.estimate_time(task),
 'cost': self.estimate_cost(task),
 'resources_needed': self.identify_resources(task)
 }

 # Select tasks that fit constraints
 selected_tasks = []
 total_time = 0
 total_cost = 0

 for task in sorted(task_metrics.keys(), 
 key=lambda t: task_metrics[t]['cost']):
 metrics = task_metrics[task]

 # Check if fits
 if (total_time + metrics['time'] <= max_time_hours and
 total_cost + metrics['cost'] <= max_budget and
 self.resources_available(metrics['resources_needed'])):

 selected_tasks.append(task)
 total_time += metrics['time']
 total_cost += metrics['cost']

 return selected_tasks

# Usage
planner = ConstraintPlanner()

plan = planner.plan(
 goal="Analyze market",
 constraints={
 'time': 10, # Max 10 hours
 'budget': 5000, # Max $5000
 'resources': ['researcher', 'analyst']
 }
)
# Automatically selects high-value tasks that fit constraints

Planning Techniques

Technique 1: Goal Regression (Backward Planning)

Start from desired goal, work backward to current state:

class BackwardPlanner:
 def plan(self, current_state: dict, goal_state: dict) -> List[str]:
 """Plan backward from goal to current state"""

 plan = []
 state = goal_state

 while state != current_state:
 # What action brings us closer?
 action = self.find_regressive_action(state, current_state)

 if not action:
 # Can't reach goal
 return None

 plan.insert(0, action) # Add to front of plan
 state = self.apply_inverse(state, action)

 return plan

# Example
backward_plan = BackwardPlanner()

current = {"location": "home", "time": "9:00am"}
goal = {"location": "meeting", "time": "10:00am"}

plan = backward_plan.plan(current, goal)
# Backward reasoning:
# To be at meeting at 10:00am:
# → Need to leave office at 9:50am
# → Need to be at office by 9:40am
# → Need to leave home by 9:15am (with buffer)
# → Need to prepare by 9:00am

Technique 2: Abstraction

Plan at high level first, then fill in details:

class AbstractionPlanner:
 def plan(self, goal: str) -> dict:
 """Plan using abstraction levels"""

 # Level 1: Abstract plan (high-level milestones)
 abstract_plan = [
 "Prepare",
 "Execute",
 "Finalize"
]

 # Level 2: Concrete plan (specific tasks)
 concrete_plan = {}
 for phase in abstract_plan:
 concrete_plan[phase] = self.llm.expand_phase(phase, goal)

 # Level 3: Action plan (specific actions)
 action_plan = {}
 for phase, tasks in concrete_plan.items():
 action_plan[phase] = []
 for task in tasks:
 actions = self.llm.expand_task(task)
 action_plan[phase].extend(actions)

 return action_plan

# Example
planner = AbstractionPlanner()
plan = planner.plan("Organize company event")

# Result:
# Prepare:
# - Reserve venue
# - Send invitations
# - Plan agenda
# Execute:
# - Set up venue
# - Greet attendees
# - Run agenda
# Finalize:
# - Cleanup
# - Send thank-you notes

-

Planning in Production

Complete Planning System

class ProductionPlanner:
 def __init__(self):
 self.llm = LLM()
 self.memory = MemorySystem()
 self.validator = PlanValidator()

 def plan(self, goal: str, context: dict = None) -> dict:
 """Generate complete plan"""

 # Step 1: Understand goal
 goal_analysis = self.analyze_goal(goal)
 # {constraints, scope, dependencies, resources_needed}

 # Step 2: Generate plan options
 plan_options = self.generate_plan_options(goal, goal_analysis)
 # [option1, option2, option3]

 # Step 3: Evaluate options
 ranked_options = self.rank_options(plan_options)

 # Step 4: Validate best option
 best_plan = ranked_options[0]
 is_valid = self.validator.validate(best_plan)

 if not is_valid:
 # Try next option or replan
 best_plan = self.handle_invalid_plan(ranked_options)

 # Step 5: Store for learning
 self.memory.store_plan(goal, best_plan)

 return {
 'goal': goal,
 'plan': best_plan['steps'],
 'estimated_time': best_plan['time'],
 'estimated_cost': best_plan['cost'],
 'confidence': best_plan['confidence'],
 'dependencies': best_plan['dependencies']
 }

 def analyze_goal(self, goal: str) -> dict:
 """Analyze goal to understand scope"""

 analysis = self.llm.analyze(f"""
 Analyze this goal and identify:
 1. Key constraints (time, budget, resources)
 2. Scope (what's included/excluded)
 3. Dependencies (prerequisites)
 4. Success criteria (how to know it's done)

 Goal: {goal}
 """)

 return self.parse_analysis(analysis)

 def generate_plan_options(self, goal: str, analysis: dict):
 """Generate multiple plan options"""

 options = []

 # Option 1: Fast (minimal steps)
 fast_plan = self.llm.plan(f"""
 Create a fast plan for: {goal}
 Focus on: Most critical steps only
 Time: Minimize
 Quality: Acceptable minimum
 """)
 options.append({'name': 'fast', 'plan': fast_plan})

 # Option 2: Quality (comprehensive)
 quality_plan = self.llm.plan(f"""
 Create a quality plan for: {goal}
 Focus on: Comprehensive approach
 Time: Allow sufficient time
 Quality: Excellent
 """)
 options.append({'name': 'quality', 'plan': quality_plan})

 # Option 3: Balanced (middle ground)
 balanced_plan = self.llm.plan(f"""
 Create a balanced plan for: {goal}
 Focus on: Efficient and good quality
 Time: Reasonable
 Quality: Good
 """)
 options.append({'name': 'balanced', 'plan': balanced_plan})

 return options

 def rank_options(self, options: List) -> List:
 """Rank options by usefulness"""

 ranked = []
 for option in options:
 score = self.score_plan(option['plan'])
 ranked.append({
 'name': option['name'],
 'plan': option['plan'],
 'score': score
 })

 return sorted(ranked, key=lambda x: x['score'], reverse=True)

 def score_plan(self, plan: dict) -> float:
 """Score a plan's quality"""

 score = 0
 score += plan['expected_quality'] * 0.4 # Quality weight
 score += (1 / plan['estimated_time']) * 0.3 # Speed bonus
 score += (1 / plan['estimated_cost']) * 0.3 # Cost efficiency

 return score

Planning Warnings

Warning 1: Over-Planning

# WRONG
plan = detailed_planner.plan("Write email")
# Output
# Result

# RIGHT
plan = simple_planner.plan("Write email")
# Output
# Result

Lesson: Plan depth should match task complexity.

Warning 2: Rigid Plans

# WRONG
if not task_complete:
 force_complete(task) # Even if approach isn't working

# RIGHT
if not task_complete:
 if retry_count < 3:
 try_different_approach()
 else:
 replan()

Lesson: Plans are guides, not contracts.

Warning 3: Missing Dependencies

# WRONG
tasks = ["Design", "Code", "Test"] # No ordering
launch_all_parallel() # Crashes: can't code before design

# RIGHT
tasks = {
 "Design": [],
 "Code": ["Design"],
 "Test": ["Code"]
}
execute_respecting_dependencies(tasks)

Lesson: Always identify task dependencies.


Best Practices

1. Validate Before Executing

# Good
plan = planner.plan(goal)
if validator.is_feasible(plan):
 executor.execute(plan)
else:
 planner.replan()

# Bad
plan = planner.plan(goal)
executor.execute(plan) # Hope for best

2. Monitor Execution

# Good
for step in plan:
 result = execute_step(step)
 if not result.success:
 replanning_trigger = True
 break

# Bad
for step in plan:
 execute_step(step) # Blind execution

3. Keep Plans Flexible

# Good
def execute_plan(plan):
 for step in plan:
 result = execute(step)

 if result.failed and is_recoverable(result):
 alternative = find_alternative(step)
 execute(alternative)

# Bad
def execute_plan(plan):
 for step in plan:
 execute(step) # Always same way

Key Takeaways

  1. Planning separates agents from chatbots - Systematic thinking
  2. Multiple strategies exist - Hierarchical, dependency-based, constraint-based
  3. Plan depth matches task complexity - Don't over-engineer simple tasks
  4. Plans are guides, not mandates - Adapt when needed
  5. Validation critical - Check feasibility before execution
  6. Monitor execution - Detect issues early
  7. Learn from plans - Improve planning over time

-

Next Steps

-

Last Updated: August 9, 2026