Skip to content
Back to Blog
1 min read

Semantic Kernel Filters: Intercepting and Modifying AI Operations

I wrote “Semantic Kernel Filters: Intercepting and Modifying AI Operations” to share practical, production-minded guidance on this topic.

Understanding Filter Types

Semantic Kernel supports several filter types: function invocation filters, prompt render filters, and auto function invocation filters. Each intercepts different stages of the AI pipeline.

Implementing a Function Invocation Filter

using Microsoft.SemanticKernel;

public class LoggingFilter : IFunctionInvocationFilter
{
    private readonly ILogger<LoggingFilter> _logger;

    public LoggingFilter(ILogger<LoggingFilter> logger)
    {
        _logger = logger;
    }

    public async Task OnFunctionInvocationAsync(
        FunctionInvocationContext context,
        Func<FunctionInvocationContext, Task> next)
    {
        var startTime = DateTime.UtcNow;

        _logger.LogInformation(
            "Invoking function {PluginName}.{FunctionName}",
            context.Function.PluginName,
            context.Function.Name);

        try
        {
            await next(context);

            var duration = DateTime.UtcNow - startTime;
            _logger.LogInformation(
                "Function {FunctionName} completed in {Duration}ms",
                context.Function.Name,
                duration.TotalMilliseconds);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex,
                "Function {FunctionName} failed",
                context.Function.Name);
            throw;
        }
    }
}

Prompt Render Filter for Modification

public class PromptEnhancementFilter : IPromptRenderFilter
{
    public async Task OnPromptRenderAsync(
        PromptRenderContext context,
        Func<PromptRenderContext, Task> next)
    {
        // Add context before rendering
        if (context.Arguments.TryGetValue("user_context", out var userContext))
        {
            context.Arguments["enhanced_prompt"] =
                $"User Context: {userContext}\n\n{context.Arguments["prompt"]}";
        }

        await next(context);

        // Log the final rendered prompt
        Console.WriteLine($"Rendered prompt: {context.RenderedPrompt}");
    }
}

Registering Filters

var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(deploymentName, endpoint, apiKey);

// Add filters
builder.Services.AddSingleton<IFunctionInvocationFilter, LoggingFilter>();
builder.Services.AddSingleton<IPromptRenderFilter, PromptEnhancementFilter>();

var kernel = builder.Build();

Filters enable clean separation of cross-cutting concerns from your core AI logic, making applications more maintainable and testable.\n\n## Takeaways\n\nAdd a concise, personal takeaway and recommended next steps here.\n

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.