Beta Telemetry#
AG2 Beta includes a TelemetryMiddleware that emits OpenTelemetry spans for agent turns, LLM calls, tool executions, and human-in-the-loop interactions.
The middleware follows the OpenTelemetry GenAI Semantic Conventions, so traces can be exported to any compatible backend -- Jaeger, Grafana Tempo, Datadog, Honeycomb, Langfuse, and others.
Installation#
Quick Start#
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter
from autogen.beta import Agent
from autogen.beta.config import OpenAIConfig
from autogen.beta.middleware.builtin import TelemetryMiddleware
# 1. Configure OpenTelemetry
resource = Resource.create(attributes={"service.name": "ag2-beta-quickstart"})
tracer_provider = TracerProvider(resource=resource)
tracer_provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(tracer_provider)
# 2. Create agent with telemetry middleware
agent = Agent(
"assistant",
prompt="You are a helpful assistant.",
config=OpenAIConfig(model="gpt-4o-mini"),
middleware=[
TelemetryMiddleware(
tracer_provider=tracer_provider,
agent_name="assistant",
),
],
)
# 3. Run -- spans are emitted automatically
import asyncio
reply = asyncio.run(agent.ask("What is the capital of France?"))
Trace Hierarchy#
Each ask() call produces a root span with child spans for LLM calls, tool executions, and human input:
invoke_agent assistant
|-- chat gpt-4o-mini # LLM API call
|-- execute_tool get_weather # tool execution
|-- chat gpt-4o-mini # LLM call after tool result
+-- await_human_input assistant # human-in-the-loop
Span Types#
Every span includes an ag2.span.type attribute:
ag2.span.type | Operation name | Triggered by |
|---|---|---|
agent | invoke_agent | on_turn -- wraps the full agent turn |
llm | chat | on_llm_call -- each LLM API call |
tool | execute_tool | on_tool_execution -- each tool invocation |
human_input | await_human_input | on_human_input -- human-in-the-loop |
Semantic Attributes#
Spans carry standard OpenTelemetry GenAI attributes:
| Attribute | Span types | Description |
|---|---|---|
gen_ai.operation.name | All | Operation: invoke_agent, chat, execute_tool, await_human_input |
gen_ai.agent.name | agent, human_input | Agent name |
gen_ai.provider.name | agent, llm | LLM provider (e.g. openai, anthropic) -- auto-detected |
gen_ai.request.model | agent, llm | Model name (e.g. gpt-4o-mini) -- auto-detected |
gen_ai.response.model | llm | Resolved model name from response |
gen_ai.response.finish_reasons | llm | Finish reasons (e.g. ["stop"], ["tool_calls"]) |
gen_ai.usage.input_tokens | llm | Prompt token count |
gen_ai.usage.output_tokens | llm | Completion token count |
gen_ai.tool.name | tool | Tool function name |
gen_ai.tool.call.id | tool | Tool call ID |
gen_ai.tool.type | tool | Tool type (always function) |
Content Capture#
By default, message content, tool arguments, and results are included in spans. To disable content capture for privacy-sensitive environments:
TelemetryMiddleware(
tracer_provider=tracer_provider,
agent_name="assistant",
capture_content=False, # omits messages, tool args, and results
)
When content capture is enabled (the default), spans include these additional attributes:
| Attribute | Span type | Content |
|---|---|---|
gen_ai.input.messages | llm | JSON request messages |
gen_ai.output.messages | llm | JSON response messages |
gen_ai.tool.call.arguments | tool | Tool call arguments (JSON) |
gen_ai.tool.call.result | tool | Tool execution result |
ag2.human_input.prompt | human_input | Prompt shown to human |
ag2.human_input.response | human_input | Human's response |
Warning
With capture_content=True, message content, tool arguments, and human input will appear in your tracing backend. Ensure your backend has appropriate access controls.
Configuration#
TelemetryMiddleware accepts:
| Parameter | Type | Default | Description |
|---|---|---|---|
tracer_provider | TracerProvider \| None | Global provider | OpenTelemetry TracerProvider |
capture_content | bool | True | Include message/tool content in spans |
agent_name | str \| None | "unknown" | Agent name for span attributes |
provider_name | str \| None | None | LLM provider name (auto-detected from response if not set) |
model_name | str \| None | None | Model name (auto-detected from response if not set) |
Tool Execution Example#
from autogen.beta import Agent
from autogen.beta.config import OpenAIConfig
from autogen.beta.middleware.builtin import TelemetryMiddleware
from autogen.beta.tools import tool
@tool
def get_weather(city: str) -> str:
"""Get weather information for a city."""
return f"Sunny, 72F in {city}"
agent = Agent(
"weather_agent",
prompt="Use the get_weather tool to answer weather questions.",
config=OpenAIConfig(model="gpt-4o-mini"),
tools=[get_weather],
middleware=[
TelemetryMiddleware(
tracer_provider=tracer_provider,
agent_name="weather_agent",
),
],
)
Backend Integration#
Since TelemetryMiddleware uses standard OpenTelemetry, any OTLP-compatible backend works. See the V1 tracing documentation for setup guides for Grafana Tempo, Jaeger, Langfuse, and other backends. The setup is identical -- only the agent instrumentation method differs.