Semantic Kernel (Python) tracing
Send Semantic Kernel's native Python agent, tool and model spans to Future AGI with the maintained traceAI adapter and explicit content controls.
Trace Python Semantic Kernel agents, tool calls and model usage in Future AGI. traceAI-semantic-kernel enables Semantic Kernel’s native OpenTelemetry diagnostics and maps its spans without adding a second tracing layer.
Prerequisites
- Python 3.10–3.13.
- Future AGI API credentials.
- Your own OpenAI API key and a Chat Completions model with tool-calling support for the example below.
Use OpenAIChatCompletion or Azure OpenAI’s AzureChatCompletion. This guide covers Python, not Java Semantic Kernel, .NET or Microsoft Agent Framework.
Warning
AzureAIInferenceChatCompletion is not supported. Its separate Azure SDK spans are outside this adapter’s content and privacy controls. Do not enable SEMANTICKERNEL_EXPERIMENTAL_GENAI_* flags as a workaround: Azure SDK content recording can remain enabled despite sensitive=False, FI_HIDE_INPUTS or FI_HIDE_OUTPUTS. For an Azure OpenAI deployment, use AzureChatCompletion; it is not a replacement for an Azure AI Inference endpoint.
Install
python -m pip install "traceAI-semantic-kernel==0.1.2" "fi-instrumentation-otel==1.2.3" "semantic-kernel==1.45.0"
The adapter requires semantic-kernel>=1.38.0,<2. Keep the example’s version pin when starting out: Semantic Kernel’s GenAI diagnostics are experimental and upgrades can change span names or attributes. With uv pip install, add --prerelease=allow for Semantic Kernel’s azure-ai-agents dependency.
Configure credentials
Set these in the terminal where you will run the application. Replace the model placeholder with a Chat Completions model available to your OpenAI account.
export FI_API_KEY="YOUR_FUTURE_AGI_API_KEY"
export FI_SECRET_KEY="YOUR_FUTURE_AGI_SECRET_KEY"
export OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
export OPENAI_CHAT_MODEL_ID="YOUR_CHAT_COMPLETIONS_MODEL"
Run an agent
Save this as semantic_kernel_app.py. The hotel tool returns sample policy data; the agent calls your OpenAI model to answer the question.
import asyncio
import os
from fi_instrumentation import register, using_session
from fi_instrumentation.fi_types import ProjectType
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.functions import kernel_function
from traceai_semantic_kernel import SemanticKernelInstrumentor
class HotelPlugin:
@kernel_function(description="Get the hotel's checkout time.")
def get_checkout_time(self) -> str:
return "Checkout is at 11:00 AM."
async def main():
trace_provider = register(
project_type=ProjectType.OBSERVE,
project_name="semantic-kernel-demo",
)
try:
SemanticKernelInstrumentor().instrument(
tracer_provider=trace_provider,
sensitive=False,
)
agent = ChatCompletionAgent(
name="HotelAssistant",
instructions="Use the hotel tool to answer questions about checkout.",
service=OpenAIChatCompletion(
ai_model_id=os.environ["OPENAI_CHAT_MODEL_ID"],
api_key=os.environ["OPENAI_API_KEY"],
),
plugins={"Hotel": HotelPlugin()},
)
with using_session("hotel-conversation"):
response = await agent.get_response("What time is checkout?")
print(response.message.content)
finally:
trace_provider.force_flush()
trace_provider.shutdown()
if __name__ == "__main__":
asyncio.run(main())
python semantic_kernel_app.py
Call instrument() once during application startup with the provider returned by register(). It enables the shared diagnostics in process; no SEMANTICKERNEL_* environment flags are needed. With fi-instrumentation-otel==1.2.3, adding a processor to that provider preserves its exporter and the Semantic Kernel mapping processor; you do not need to reinstrument. The first add_span_processor() on a directly constructed TracerProvider still replaces its default processor chain, so use register() as shown.
Do not also enable traceAI-openai, traceAI-litellm or another client instrumentor for the same model calls: that creates duplicate model spans and token totals.
View the trace
Open Observe in Future AGI, select semantic-kernel-demo, and open the latest trace. When the agent calls the hotel tool, its tree includes:
invoke_agent HotelAssistant AGENT
└─ AutoFunctionInvocationLoop CHAIN
├─ chat <your model> LLM
├─ execute_tool Hotel-get_checkout_time TOOL
└─ chat <your model> LLM
Model spans contain the model, provider and input/output token counts reported by Semantic Kernel, including streaming usage. A model-requested function is TOOL; a function you invoke directly with kernel.invoke or kernel.invoke_prompt is CHAIN. The adapter does not add retrieval spans, cost, cache-token or reasoning-token counts.
Use using_session() to group turns under your application’s conversation identifier; Semantic Kernel does not supply a session ID to this integration. For subsequent turns, also pass thread=response.thread to agent.get_response() to retain the agent’s chat history. A function invoked inside your own auto-function-invocation filter or streaming consumer can be classified as TOOL rather than CHAIN.
Content and privacy
By default, sensitive=False removes prompt/completion messages, agent messages, tool arguments and tool results from Semantic Kernel-scoped spans. Tool names, descriptions and definitions, agent metadata, model names, token counts and IDs remain. Keep sensitive text out of those metadata fields. Exception stack traces are removed; exception messages are removed and the error status retains the exception type.
To capture content, change the existing startup call to sensitive=True and restart the application. This stores messages, tool arguments/results and exception messages in Future AGI. Calling instrument() again on an already instrumented process does not change its settings.
FI_HIDE_INPUTS=true and FI_HIDE_OUTPUTS=true still remove the respective input or output span fields when sensitive=True; set them before instrument(). Only TraceConfig.hide_inputs and TraceConfig.hide_outputs are applied by this adapter, not other TraceConfig settings such as PII redaction or error-detail hiding. These switches do not remove sensitive text from exception messages when sensitive=True.
Warning
These controls cover Semantic Kernel-scoped spans, not independently emitted provider spans, custom attributes or Python logs. With sensitive=True, model messages also flow through Semantic Kernel’s INFO logging. Input/output hiding filters the spans, not those log records; configure your logging handlers accordingly.
Troubleshooting
- No spans arrive. Check your Future AGI credentials and pass the provider returned by
register()toinstrument(). Check startup warnings for an incompatible Semantic Kernel diagnostics module or a non-SDK tracer provider. - Token counts are doubled. Remove client-level instrumentation for the same Semantic Kernel calls.
- Prompt or completion fields are empty. Content capture is off by default. Review content and privacy before changing the startup call to
sensitive=True; also checkFI_HIDE_INPUTSandFI_HIDE_OUTPUTS. - A short script exits before export. Keep
force_flush()andshutdown()in thefinallyblock, after the awaited agent call completes.
Questions & Discussion