n4nAI

Semantic Kernel planner tutorial: sequential vs stepwise

Compare Semantic Kernel's Sequential and Stepwise planners across capabilities, latency, ergonomics, and failure modes with code examples and a decision matrix.

n4n Team6 min read1,399 words

Audio narration

Coming soon — every post will get a voice note here.

Semantic Kernel’s planner abstraction lets you hand a goal to an LLM and get back an executable plan. The framework ships two planners out of the box: the Sequential Planner and the Stepwise Planner. They solve the same problem — decomposing a user request into function calls — but their execution models, failure modes, and token economics differ enough that picking the wrong one costs you latency, money, or correctness. This post breaks down the trade-offs so you can choose without guesswork.

How each planner works

Sequential Planner: one-shot plan generation

The Sequential Planner asks the model to produce a complete plan — an ordered list of function calls with arguments — in a single completion. It renders the available functions into the prompt, includes the user’s goal, and expects a JSON array of steps. The planner then executes that array linearly, passing each step’s output to the next.

from semantic_kernel.planners import SequentialPlanner
from semantic_kernel.planners.sequential_planner import SequentialPlannerConfig

planner = SequentialPlanner(kernel, SequentialPlannerConfig())
plan = await planner.create_plan("Email the Q3 forecast to the CFO")
result = await plan.invoke()

The model sees every function signature up front. If you register 30 skills, the prompt grows accordingly. The plan is static: once generated, the planner does not revisit the model unless you invoke it again with a new goal.

Stepwise Planner: iterative reasoning loop

The Stepwise Planner treats planning as a loop. On each iteration, it sends the current state (goal, available functions, prior step results) to the model and asks for the next action. The model can call a function, request more information, or declare the goal complete. The planner executes the single step, updates state, and repeats.

from semantic_kernel.planners import StepwisePlanner
from semantic_kernel.planners.stepwise_planner import StepwisePlannerConfig

planner = StepwisePlanner(kernel, StepwisePlannerConfig(max_iterations=10))
result = await planner.execute("Email the Q3 forecast to the CFO")

This is effectively a ReAct loop inside the planner. The model only sees the functions relevant to the current step (though the full catalog is still in the system prompt), and it can adapt based on intermediate results.

Capabilities and expressiveness

Dimension Sequential Planner Stepwise Planner
Branching / conditionals Not supported. Plan is a flat list. Supported. Model can decide next step based on prior output.
Loops / retry logic Not supported. Supported. Model can re-try a failed call with adjusted args.
Dynamic function discovery No — all functions in prompt at plan time. Partial — model can request functions not initially considered.
Human-in-the-loop Awkward. Must re-plan from scratch. Natural. Pause after any step, inject input, resume.
Parallel execution Manual. You’d need to post-process the plan. Not native. Steps are inherently serial.
Max plan length Limited by context window (single completion). Limited by max_iterations and cumulative context.

The Sequential Planner is a straight-line script. The Stepwise Planner is a state machine. If your workflow needs “if the forecast fails, fall back to last quarter’s data,” Stepwise handles it natively. Sequential requires you to encode that logic into a single function or accept a brittle plan.

Latency and token economics

Sequential Planner: one big completion

  • Latency: One model round-trip for planning, then N function executions. Total planning latency = single completion time.
  • Tokens: Prompt includes all function schemas + goal. Completion includes the full plan. For 20 functions with complex schemas, the prompt alone can exceed 4k tokens.
  • Cost: Predictable. One planning call per goal. No surprise iterations.

Stepwise Planner: many small completions

  • Latency: One model round-trip per step. A 5-step plan = 5 planning completions + 5 function executions. Planning latency scales linearly with steps.
  • Tokens: Each iteration sends accumulated state (goal + history + schemas). Context grows with each step. Long-running plans can hit context limits.
  • Cost: Variable. A simple goal might take 2 steps; a complex one might hit max_iterations (default 10). You pay for every reasoning step.

Rule of thumb: If your typical plan is 1–3 steps, Stepwise adds negligible overhead. If plans regularly exceed 5 steps, Sequential’s single completion wins on latency and often on cost.

Failure modes and debugging

Sequential Planner failures

  1. Hallucinated function calls: The model invents a function that doesn’t exist. The planner validates against the kernel at execution time and throws.
  2. Argument type mismatches: The plan looks valid but arguments don’t match the function signature. Caught at execution, not plan time.
  3. Stale plans: If a function’s behavior changes (e.g., API version bump), the plan breaks silently until execution.
  4. No recovery: A failed step stops the entire plan. No built-in retry or fallback.

Debugging means inspecting the generated JSON plan. You can log plan.generated_plan and replay it manually.

Stepwise Planner failures

  1. Infinite loops: The model keeps requesting the same action. Controlled by max_iterations, but you still pay for the loops.
  2. Context explosion: Long histories push earlier steps out of context. The model “forgets” the original goal or prior results.
  3. Oscillation: Model alternates between two actions (e.g., “search” then “refine search” repeatedly).
  4. Premature completion: Model declares success before the goal is actually met.

Debugging requires logging each iteration’s prompt, completion, and function result. The StepwisePlanner exposes an on_step callback for this.

async def log_step(step: PlanStep, result: FunctionResult):
    print(f"Step {step.index}: {step.function_name} -> {result}")

planner = StepwisePlanner(kernel, config, on_step=log_step)

Ergonomics and developer experience

Sequential Planner: declarative, testable

  • Plan as artifact: The plan is a serializable object. You can store it, version it, replay it in tests, or ship it to a separate execution environment.
  • Deterministic execution: Given the same plan, execution is deterministic (modulo function side effects).
  • Easier offline testing: Generate plans against a mock kernel, assert on structure, then execute against real functions.
# Test plan structure without hitting the model
plan = await planner.create_plan("Get user 123's orders")
assert len(plan.steps) == 2
assert plan.steps[0].name == "get_user"
assert plan.steps[1].name == "get_orders"

Stepwise Planner: interactive, opaque

  • No plan artifact: The plan exists only as execution trace. You can’t easily serialize “what the model decided to do” without recording the full session.
  • Harder to test: You need integration tests that run the full loop. Unit-testing a single step requires mocking the model’s reasoning.
  • Better for exploration: When the path to the goal is genuinely unknown (e.g., “debug this production issue”), Stepwise’s adaptability shines.

Ecosystem and extensibility

Both planners accept a PromptTemplateConfig to customize the system prompt. This is where you inject domain knowledge, few-shot examples, or constraints.

Sequential Planner customization

from semantic_kernel.prompt_template import PromptTemplateConfig

config = SequentialPlannerConfig(
    prompt_template_config=PromptTemplateConfig(
        template="""
        You are a financial analyst. Available functions:
        {{$functions}}
        
        Goal: {{$goal}}
        
        Return a JSON array of steps. Prefer `get_cached_data` over `fetch_live_data`.
        """
    )
)

Stepwise Planner customization

config = StepwisePlannerConfig(
    max_iterations=15,
    prompt_template_config=PromptTemplateConfig(
        template="""
        You are a financial analyst. Available functions:
        {{$functions}}
        
        Goal: {{$goal}}
        History: {{$history}}
        
        Decide the NEXT action. If data is stale, use `refresh_cache` first.
        """
    )
)

The Stepwise Planner’s prompt template receives {{$history}} — a serialized transcript of prior steps. This is your lever for steering long-running plans.

Both planners integrate with Semantic Kernel’s filter pipeline. You can intercept function calls for logging, auth, or caching without modifying the planner.

Limits and guardrails

Limit Sequential Stepwise
Max functions in prompt ~20–30 before quality degrades Same, but less critical per iteration
Context window pressure Single large prompt Accumulates across iterations
Hard timeout Model completion timeout max_iterations × completion timeout
Rate limit exposure 1 planning call N planning calls (burstier)
Parallelism None (planner is single-threaded) None

If you register 50+ functions, both planners suffer. The fix is function selection — use a vector index or keyword filter to pass only relevant functions to the planner. Semantic Kernel doesn’t do this automatically; you build it.

Which to choose

Choose Sequential Planner when:

  • Plans are short and predictable (1–4 steps, same pattern every time).
  • You need auditability — compliance, replay, or offline plan review.
  • Latency budget is tight — one planning call beats five.
  • Functions are pure-ish — no complex conditional logic needed mid-plan.
  • You’re building a traditional API — request in, plan out, execute, respond.

Typical use cases: “Summarize this document,” “Translate and save,” “Lookup user and send notification.”

Choose Stepwise Planner when:

  • The path is genuinely unknown — exploratory tasks, debugging, research.
  • You need conditional logic — “if X fails, try Y; if Y succeeds, do Z.”
  • Human-in-the-loop is required — approval gates, clarification prompts.
  • Functions have side effects that inform next steps — e.g., provisioning infrastructure, then configuring it.
  • You can tolerate variable latency/cost — background jobs, async workflows.

Typical use cases: “Investigate why the payment failed,” “Set up a new tenant end-to-end,” “Debug the failing CI pipeline.”

Hybrid approach (what we do at n4n.ai)

Run the Sequential Planner first with a “draft” prompt that encourages conservative plans. If the plan fails validation or execution, fall back to Stepwise with a more permissive prompt and a higher iteration budget. This captures the common case fast while retaining adaptability for edge cases.

async def execute_with_fallback(goal: str):
    # Try sequential first
    seq_plan = await sequential_planner.create_plan(goal)
    try:
        return await seq_plan.invoke()
    except PlanExecutionError as e:
        # Log and fall back
        logger.warning(f"Sequential plan failed: {e}, trying stepwise")
        return await stepwise_planner.execute(goal)

This pattern keeps p95 latency low while handling the long tail of complex requests.


Bottom line: Sequential Planner is a compiler — one shot, static output, predictable. Stepwise Planner is an interpreter — iterative, adaptive, open-ended. Match the planner to the nature of the goal, not the complexity of your function catalog.

Tagssemantic-kernelplannersequential-plannercomparison

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All semantic kernel planners & agents posts →