4 min read
Semantic Kernel Planners: Automatic AI Orchestration
Planners in Semantic Kernel automatically create execution plans from natural language goals. They analyze available skills and compose them into workflows without explicit programming.
Types of Planners
import semantic_kernel as sk
from semantic_kernel.planning import (
SequentialPlanner,
ActionPlanner,
StepwisePlanner
)
# Sequential Planner - creates step-by-step plans
sequential = SequentialPlanner(kernel)
# Action Planner - selects single best action
action = ActionPlanner(kernel)
# Stepwise Planner - iteratively solves with reasoning
stepwise = StepwisePlanner(kernel)
Sequential Planner
Creates multi-step plans:
from semantic_kernel.planning import SequentialPlanner
async def use_sequential_planner(kernel: sk.Kernel, goal: str):
"""Create and execute a sequential plan."""
planner = SequentialPlanner(kernel)
# Create plan
plan = await planner.create_plan_async(goal)
# Inspect plan
print(f"Plan for: {goal}")
print(f"Steps: {len(plan._steps)}")
for i, step in enumerate(plan._steps, 1):
print(f" {i}. {step.skill_name}.{step.name}")
# Execute plan
result = await plan.invoke_async()
return str(result)
# Example
kernel = create_kernel_with_skills()
result = await use_sequential_planner(
kernel,
"Get customer data from database, analyze it, and create a summary report"
)
Action Planner
Selects the single best action:
from semantic_kernel.planning import ActionPlanner
async def use_action_planner(kernel: sk.Kernel, goal: str):
"""Use action planner for simple goals."""
planner = ActionPlanner(kernel)
# Create plan (single action)
plan = await planner.create_plan_async(goal)
print(f"Selected action: {plan.skill_name}.{plan.name}")
print(f"Parameters: {plan.parameters}")
# Execute
result = await plan.invoke_async()
return str(result)
# Good for:
# - Simple, direct requests
# - When you want quick responses
# - Reducing AI token usage
Stepwise Planner
Iteratively reasons through complex problems:
from semantic_kernel.planning import StepwisePlanner
from semantic_kernel.planning.stepwise_planner.stepwise_planner_config import StepwisePlannerConfig
async def use_stepwise_planner(kernel: sk.Kernel, goal: str):
"""Use stepwise planner for complex reasoning."""
config = StepwisePlannerConfig(
max_iterations=10,
min_iteration_time_ms=0
)
planner = StepwisePlanner(kernel, config)
# Create and execute plan
plan = await planner.create_plan_async(goal)
result = await plan.invoke_async()
# Get reasoning trace
print("Reasoning steps:")
for step in plan.steps_taken:
print(f" - {step}")
return str(result)
# Good for:
# - Complex multi-step problems
# - When intermediate reasoning matters
# - Research or analysis tasks
Custom Planner Configuration
from semantic_kernel.planning.sequential_planner.sequential_planner_config import SequentialPlannerConfig
# Configure sequential planner
config = SequentialPlannerConfig(
relevancy_threshold=0.75,
max_relevant_functions=20,
included_skills=["DataAnalysis", "FileOperations"],
excluded_skills=["DangerousOperations"],
max_tokens=1024,
allow_missing_functions=False
)
planner = SequentialPlanner(kernel, config)
# Configure action planner
from semantic_kernel.planning.action_planner.action_planner_config import ActionPlannerConfig
action_config = ActionPlannerConfig(
included_skills=["QuickActions"],
max_tokens=512
)
Handling Plan Failures
from semantic_kernel.planning.planning_exception import PlanningException
async def safe_plan_execution(kernel: sk.Kernel, goal: str) -> dict:
"""Execute plan with error handling."""
planner = SequentialPlanner(kernel)
try:
# Create plan
plan = await planner.create_plan_async(goal)
if not plan._steps:
return {
"success": False,
"error": "Could not create a plan for this goal",
"suggestion": "Try rephrasing or breaking down the goal"
}
# Execute plan
result = await plan.invoke_async()
return {
"success": True,
"result": str(result),
"steps_executed": len(plan._steps)
}
except PlanningException as e:
return {
"success": False,
"error": f"Planning failed: {str(e)}",
"suggestion": "Check if required skills are registered"
}
except Exception as e:
return {
"success": False,
"error": f"Execution failed: {str(e)}",
"step_failed": "Unknown"
}
Plan Validation
class PlanValidator:
"""Validate plans before execution."""
def __init__(self, kernel: sk.Kernel):
self.kernel = kernel
def validate(self, plan) -> dict:
"""Validate a plan."""
issues = []
# Check if all skills exist
for step in plan._steps:
try:
self.kernel.skills.get_function(step.skill_name, step.name)
except:
issues.append(f"Missing function: {step.skill_name}.{step.name}")
# Check step count
if len(plan._steps) > 10:
issues.append(f"Plan has {len(plan._steps)} steps - consider simplifying")
# Check for dangerous operations
dangerous = ["delete", "drop", "remove", "destroy"]
for step in plan._steps:
if any(d in step.name.lower() for d in dangerous):
issues.append(f"Potentially dangerous operation: {step.name}")
return {
"valid": len(issues) == 0,
"issues": issues,
"step_count": len(plan._steps)
}
# Usage
validator = PlanValidator(kernel)
plan = await planner.create_plan_async("Delete all old files")
validation = validator.validate(plan)
if not validation["valid"]:
print("Plan issues:", validation["issues"])
Planner Selection Guide
def select_planner(goal: str, context: dict) -> str:
"""Select appropriate planner based on goal and context."""
# Simple, direct goals -> Action Planner
simple_keywords = ["what is", "tell me", "find", "get"]
if any(kw in goal.lower() for kw in simple_keywords):
if context.get("prefer_speed", False):
return "action"
# Complex analysis/research -> Stepwise Planner
complex_keywords = ["analyze", "research", "investigate", "compare"]
if any(kw in goal.lower() for kw in complex_keywords):
return "stepwise"
# Multi-step workflows -> Sequential Planner
workflow_keywords = ["then", "after", "finally", "create report"]
if any(kw in goal.lower() for kw in workflow_keywords):
return "sequential"
# Default to sequential
return "sequential"
PLANNER_COMPARISON = {
"action": {
"best_for": "Simple, single-action goals",
"speed": "Fast",
"complexity": "Low",
"tokens": "Low"
},
"sequential": {
"best_for": "Multi-step workflows",
"speed": "Medium",
"complexity": "Medium",
"tokens": "Medium"
},
"stepwise": {
"best_for": "Complex reasoning tasks",
"speed": "Slow",
"complexity": "High",
"tokens": "High"
}
}
Best Practices
- Register clear skill descriptions: Planners rely on them
- Start with Action Planner: For simple use cases
- Validate before executing: Check plan makes sense
- Handle failures gracefully: Plans can fail
- Monitor token usage: Planners use tokens to plan
- Limit scope: Use included_skills to constrain planning