Implementation:Microsoft Semantic kernel KernelProcessStep
| Knowledge Sources | |
|---|---|
| Domains | Process_Orchestration, Event_Driven_Architecture |
| Last Updated | 2026-02-11 19:00 GMT |
Overview
Pattern for defining discrete units of work as process steps by deriving from KernelProcessStep and decorating methods with [KernelFunction].
Description
KernelProcessStep is the abstract base class that all process steps must derive from in Semantic Kernel's process orchestration framework. A step class inherits from KernelProcessStep (or KernelProcessStep<TState> for stateful steps), then declares one or more public methods annotated with the [KernelFunction] attribute. These methods become the executable entry points that the process runtime invokes when events are routed to the step.
Each step method can accept a KernelProcessStepContext parameter, which the runtime injects automatically. This context provides the EmitEventAsync method used to send events to downstream steps in the process graph. Steps may also accept additional parameters whose values are supplied by incoming event data or by the kernel's dependency injection container.
Usage
Derive from KernelProcessStep whenever you need to create a new step that can participate in a Semantic Kernel process workflow. Use KernelProcessStep<TState> when your step needs to maintain state across invocations.
Code Reference
Source Location
- Repository: semantic-kernel
- File:
dotnet/src/Experimental/Process.Abstractions/KernelProcessStep.cs:L10-17
Base Class Signature
public class KernelProcessStep
{
public virtual ValueTask ActivateAsync(KernelProcessStepState state)
{
return default;
}
}
public class KernelProcessStep<TState> : KernelProcessStep where TState : class, new()
{
public virtual ValueTask ActivateAsync(KernelProcessStepState<TState> state)
{
return default;
}
}
Import
using Microsoft.SemanticKernel;
Step Definition Pattern
Minimal Step
The simplest possible step derives from KernelProcessStep and declares a single [KernelFunction] method. The KernelProcessStepContext parameter is injected by the runtime and provides event emission capabilities.
public sealed class StartStep : KernelProcessStep
{
[KernelFunction]
public async ValueTask ExecuteAsync(KernelProcessStepContext context)
{
Console.WriteLine("Step 1 - Start");
}
}
Step with Event Emission
Steps communicate with downstream steps by emitting events through the context. The KernelProcessEvent carries an Id that the process runtime uses to route the event, and an optional Data payload.
public sealed class ValidationStep : KernelProcessStep
{
[KernelFunction]
public async ValueTask ValidateAsync(KernelProcessStepContext context, string input)
{
bool isValid = !string.IsNullOrWhiteSpace(input);
if (isValid)
{
await context.EmitEventAsync(
new KernelProcessEvent { Id = "ValidationPassed", Data = input });
}
else
{
await context.EmitEventAsync(
new KernelProcessEvent { Id = "ValidationFailed", Data = "Input was empty" });
}
}
}
Stateful Step
When a step needs to maintain state across invocations, derive from KernelProcessStep<TState>. Override ActivateAsync to capture the state reference, then use it within your kernel functions.
public sealed class ChatBotResponseStep : KernelProcessStep<ChatBotState>
{
internal ChatBotState? _state;
public override ValueTask ActivateAsync(KernelProcessStepState<ChatBotState> state)
{
_state = state.State;
return ValueTask.CompletedTask;
}
[KernelFunction("GetChatResponse")]
public async Task GetChatResponseAsync(
KernelProcessStepContext context,
string userMessage,
Kernel _kernel)
{
_state!.ChatMessages.Add(new(AuthorRole.User, userMessage));
IChatCompletionService chatService =
_kernel.Services.GetRequiredService<IChatCompletionService>();
ChatMessageContent response =
await chatService.GetChatMessageContentAsync(_state.ChatMessages);
_state.ChatMessages.Add(response);
await context.EmitEventAsync(
new KernelProcessEvent
{
Id = "AssistantResponseGenerated",
Data = response
});
}
}
public sealed class ChatBotState
{
internal ChatHistory ChatMessages { get; } = [];
}
Step with Named Functions
When a step exposes multiple kernel functions, each function is identified by name. This allows the process routing to target specific entry points on the step.
public sealed class CompleteNewCustomerFormStep : KernelProcessStep
{
public static class ProcessStepFunctions
{
public const string NewAccountWelcome = nameof(NewAccountWelcome);
public const string NewAccountProcessUserInfo = nameof(NewAccountProcessUserInfo);
}
[KernelFunction(ProcessStepFunctions.NewAccountWelcome)]
public async Task NewAccountWelcomeAsync(KernelProcessStepContext context)
{
await context.EmitEventAsync(
new KernelProcessEvent
{
Id = "NewCustomerFormWelcomeMessageComplete",
Data = "Welcome! Please provide your details."
});
}
[KernelFunction(ProcessStepFunctions.NewAccountProcessUserInfo)]
public async Task NewAccountProcessUserInfoAsync(
KernelProcessStepContext context,
string userMessage)
{
// Process user info and emit appropriate events
await context.EmitEventAsync(
new KernelProcessEvent
{
Id = "NewCustomerFormCompleted",
Data = userMessage
});
}
}
Key Components
| Component | Type | Description |
|---|---|---|
| KernelProcessStep | Base class | Base class for all stateless process steps. Derive from this to create a new step. |
| KernelProcessStep<TState> | Base class | Generic base class for stateful process steps. The TState parameter defines the shape of persisted state. |
| [KernelFunction] | Attribute | Marks a public method as an executable entry point for the process runtime. A step can have one or more kernel functions. |
| KernelProcessStepContext | Runtime object | Injected into step methods by the runtime. Provides EmitEventAsync for sending events to downstream steps. |
| ActivateAsync | Virtual method | Called when the step is initialized. Override this in stateful steps to capture the state reference. |
| KernelProcessEvent | Data class | Represents an event emitted by a step. Contains an Id (for routing) and optional Data payload. |