Skip to Content
SDK Reference.NETInstrumentation: Semantic Kernel

Veriproof.Sdk.Instrumentation.SemanticKernel

Who can use this
Available to
DeveloperAdministrator
Not available to
Governance EngineerCompliance OfficerBusiness OwnerAuditor

This instrumentation library is for .NET developers building on Microsoft Semantic Kernel. If you are a Governance Engineer, Compliance Officer, Business Owner, or Auditor, your team’s developers set this up — start with the Training Academy track for your role.

Automatically captures spans for every Semantic Kernel function invocation, prompt render, and tool call using the Kernel’s built-in filter pipeline. No manual Activity creation required.

Compatibility: .NET 10+, Semantic Kernel 1.x


Installation

dotnet add package Veriproof.Sdk.Core dotnet add package Veriproof.Sdk.Instrumentation.SemanticKernel

Setup

Register the filter and VeriProof tracing in Program.cs:

using OpenTelemetry.Trace; using Veriproof.Sdk; using Veriproof.Sdk.Instrumentation.SemanticKernel; using Microsoft.SemanticKernel; var builder = WebApplication.CreateBuilder(args); // 1. Register the VeriProof Semantic Kernel filter in DI builder.Services.AddVeriproofSemanticKernelAdapter(options => { options.GenAiSystem = "semantic-kernel"; options.CaptureRenderedPrompt = false; // opt-in: forward prompt text to VeriProof options.CaptureFunctionResult = false; // opt-in: forward function output options.CaptureToolDescription = true; }); // 2. Configure VeriProof OTel exporter — include the SK activity source builder.Services.AddOpenTelemetry() .WithTraces(traces => traces .AddVeriproofSemanticKernelInstrumentation() // adds the SK activity source .AddVeriproofTracing(options => { options.ApiKey = builder.Configuration["VeriproofApiKey"]!; options.ApplicationId = builder.Configuration["VeriproofApplicationId"]!; }) ); // 3. Build the Semantic Kernel with VeriProof filter injected automatically via DI builder.Services.AddKernel(); builder.Services.AddSingleton<IChatCompletionService>(...);

Alternatively, attach the filter directly to a Kernel instance (useful when not using DI):

using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; var filter = new VeriproofKernelFilter( Options.Create(new SemanticKernelAdapterOptions { GenAiSystem = "semantic-kernel", CaptureRenderedPrompt = false, CaptureFunctionResult = false, }), NullLogger<VeriproofKernelFilter>.Instance); var kernel = Kernel.CreateBuilder() .AddOpenAIChatCompletion("gpt-4.1", apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY")!) .Build(); kernel.AttachVeriproofFilter(filter);

SemanticKernelAdapterOptions

OptionTypeDefaultDescription
TenantIdstring?nullOverride per-filter tenant if multi-tenant
ApplicationIdstring?nullOverride per-filter application ID
GenAiSystemstring"semantic-kernel"gen_ai.system attribute on all spans
CaptureRenderedPromptboolfalseInclude gen_ai.system_instructions / input messages (requires EnableContentCapture in exporter options)
CaptureFunctionResultboolfalseInclude gen_ai.output.messages
CaptureToolDescriptionbooltrueInclude tool description in span attributes
MaxContentLengthint2048Truncation limit for captured content

What gets captured

For each Semantic Kernel function invocation, VeriproofKernelFilter creates a child span containing:

AttributeSource
gen_ai.systemSemanticKernelAdapterOptions.GenAiSystem
gen_ai.operation.nameKernel operation type (e.g. chat.completions)
gen_ai.request.modelModel ID from the execution settings
gen_ai.usage.input_tokensFrom the FunctionResult metadata
gen_ai.usage.output_tokensFrom the FunctionResult metadata
gen_ai.tool.nameFunction plugin + function name
gen_ai.tool.descriptionWhen CaptureToolDescription = true
gen_ai.system_instructionsWhen CaptureRenderedPrompt = true

Adding governance attributes

The filter creates spans automatically, but you can enrich them with additional governance metadata by accessing the Activity directly:

using System.Diagnostics; using Veriproof.Sdk.Annotations; using Veriproof.Sdk.Annotations.Models; // In your kernel invocation wrapper: using var sessionActivity = activitySource.StartActivity("ai.session"); sessionActivity? .SetSessionIntent(SessionIntent.advisory) .SetTransactionId($"support:{ticketId}") .SetDataSensitivity(DataSensitivity.Internal); // Invoke the kernel — all SK spans appear as children of sessionActivity var result = await kernel.InvokeAsync(plugin["AnalyseTicket"], new KernelArguments { ["ticket"] = ticketBody }); sessionActivity? .SetSessionOutcome(SessionOutcome.success) .SetGovernanceDecision( DecisionContext.Simple("Categorise support ticket", result.GetValue<string>()!));

Full example

See the Semantic Kernel example for a complete runnable application.


Next steps

Last updated on