Implementation:Microsoft Semantic kernel IFunctionInvocationFilter
| Knowledge Sources | |
|---|---|
| Domains | AI_Orchestration, Observability, Middleware |
| Last Updated | 2026-02-11 19:00 GMT |
Overview
Concrete tool for implementing middleware-style interceptors that observe, modify, or short-circuit function invocations and prompt rendering in Microsoft Semantic Kernel.
Description
IFunctionInvocationFilter and IPromptRenderFilter are interfaces that define the contract for observability filters in the Semantic Kernel pipeline. By implementing these interfaces and registering the implementations with the kernel's service collection, developers can intercept every function invocation and every prompt rendering operation.
IFunctionInvocationFilter defines a single method, OnFunctionInvocationAsync, which is called for every function invocation (native plugin functions and prompt functions alike). The method receives a FunctionInvocationContext containing:
- Kernel: The kernel instance.
- Function: The KernelFunction being invoked.
- Arguments: The KernelArguments passed to the function.
- Result: The FunctionResult (available after next is called).
- IsStreaming: Whether the invocation is in streaming mode.
- CancellationToken: For cooperative cancellation.
IPromptRenderFilter defines OnPromptRenderAsync, which is called before a rendered prompt is sent to the AI model. Its PromptRenderContext includes:
- Kernel: The kernel instance.
- Function: The KernelFunction associated with the prompt.
- Arguments: The KernelArguments for the invocation.
- RenderedPrompt: The rendered prompt text (can be read and modified).
- ExecutionSettings: The PromptExecutionSettings in effect.
- Result: Can be set to short-circuit function invocation entirely.
Additionally, IAutoFunctionInvocationFilter targets specifically the automatic function invocations triggered by AI model tool-call requests during the auto-invoke loop.
All filters follow the delegate-based middleware pattern: call next to proceed through the pipeline, or skip it to short-circuit.
Usage
Use IFunctionInvocationFilter for cross-cutting concerns around function execution (logging, timing, error handling, caching). Use IPromptRenderFilter for prompt-level concerns (content filtering, PII redaction, prompt logging). Use IAutoFunctionInvocationFilter for concerns specific to AI-initiated function calls.
Code Reference
Source Location
- Repository: semantic-kernel
- File (IFunctionInvocationFilter):
dotnet/src/SemanticKernel.Abstractions/Filters/Function/IFunctionInvocationFilter.cs:L13-21 - File (IPromptRenderFilter):
dotnet/src/SemanticKernel.Abstractions/Filters/Prompt/IPromptRenderFilter.cs:L13-21 - File (IAutoFunctionInvocationFilter):
dotnet/src/SemanticKernel.Abstractions/Filters/AutoFunctionInvocation/IAutoFunctionInvocationFilter.cs:L13-21
Signature (IFunctionInvocationFilter)
public interface IFunctionInvocationFilter
{
Task OnFunctionInvocationAsync(
FunctionInvocationContext context,
Func<FunctionInvocationContext, Task> next);
}
Signature (IPromptRenderFilter)
public interface IPromptRenderFilter
{
Task OnPromptRenderAsync(
PromptRenderContext context,
Func<PromptRenderContext, Task> next);
}
Signature (IAutoFunctionInvocationFilter)
public interface IAutoFunctionInvocationFilter
{
Task OnAutoFunctionInvocationAsync(
AutoFunctionInvocationContext context,
Func<AutoFunctionInvocationContext, Task> next);
}
Import
using Microsoft.SemanticKernel;
I/O Contract
Inputs (IFunctionInvocationFilter.OnFunctionInvocationAsync)
| Name | Type | Required | Description |
|---|---|---|---|
| context | FunctionInvocationContext |
Yes | Contains the Kernel, Function, Arguments, Result, IsStreaming flag, and CancellationToken for the current invocation. |
| next | Func<FunctionInvocationContext, Task> |
Yes | Delegate to the next filter in the pipeline or the function itself. Must be called to proceed; omit to short-circuit. |
Inputs (IPromptRenderFilter.OnPromptRenderAsync)
| Name | Type | Required | Description |
|---|---|---|---|
| context | PromptRenderContext |
Yes | Contains the Kernel, Function, Arguments, RenderedPrompt, ExecutionSettings, and Result for the current rendering. |
| next | Func<PromptRenderContext, Task> |
Yes | Delegate to the next filter in the pipeline or the rendering operation itself. |
Outputs
| Name | Type | Description |
|---|---|---|
| return | Task |
Both methods return Task (void async). Side effects are applied by modifying the context object or by calling/not calling next. |
Usage Examples
Logging Filter for Function Invocations
using Microsoft.SemanticKernel;
public class LoggingFilter : IFunctionInvocationFilter
{
public async Task OnFunctionInvocationAsync(
FunctionInvocationContext context,
Func<FunctionInvocationContext, Task> next)
{
Console.WriteLine($"Invoking: {context.Function.Name}");
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
// Proceed with the function invocation
await next(context);
stopwatch.Stop();
Console.WriteLine($"Completed: {context.Function.Name} in {stopwatch.ElapsedMilliseconds}ms");
Console.WriteLine($"Result: {context.Result}");
}
}
Prompt Redaction Filter
using Microsoft.SemanticKernel;
public class PiiRedactionFilter : IPromptRenderFilter
{
public async Task OnPromptRenderAsync(
PromptRenderContext context,
Func<PromptRenderContext, Task> next)
{
// Proceed with prompt rendering first
await next(context);
// Redact sensitive patterns from the rendered prompt
if (context.RenderedPrompt is not null)
{
context.RenderedPrompt = RedactPii(context.RenderedPrompt);
}
}
private static string RedactPii(string text)
{
// Replace email patterns, SSNs, etc.
return System.Text.RegularExpressions.Regex.Replace(
text, @"\b[\w.-]+@[\w.-]+\.\w+\b", "[REDACTED_EMAIL]");
}
}
Registering Filters with the Kernel
using Microsoft.SemanticKernel;
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatClient(modelId: "gpt-4o", apiKey: "your-api-key");
kernelBuilder.Plugins.AddFromType<TimeInformation>();
// Register filters via the service collection
kernelBuilder.Services.AddSingleton<IFunctionInvocationFilter, LoggingFilter>();
kernelBuilder.Services.AddSingleton<IPromptRenderFilter, PiiRedactionFilter>();
Kernel kernel = kernelBuilder.Build();
// Filters are now active for all invocations
OpenAIPromptExecutionSettings settings = new()
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
Console.WriteLine(await kernel.InvokePromptAsync("What time is it?", new(settings)));
Short-Circuiting with a Cached Result
using Microsoft.SemanticKernel;
public class CachingFilter : IFunctionInvocationFilter
{
private readonly Dictionary<string, FunctionResult> _cache = new();
public async Task OnFunctionInvocationAsync(
FunctionInvocationContext context,
Func<FunctionInvocationContext, Task> next)
{
var cacheKey = $"{context.Function.Name}:{string.Join(",", context.Arguments)}";
if (_cache.TryGetValue(cacheKey, out var cachedResult))
{
// Short-circuit: return cached result without calling the function
context.Result = cachedResult;
return;
}
// Proceed with function invocation
await next(context);
// Cache the result for future calls
_cache[cacheKey] = context.Result;
}
}