From b1aa0463695d5793db3881b11519a0e82b1193fb Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Tue, 4 Feb 2025 09:54:30 -0800 Subject: [PATCH 1/2] Update agent tracing span name and attributes --- .../utils/telemetry/agent_diagnostics/decorators.py | 13 ++++++++++++- .../agent_diagnostics/gen_ai_attributes.py | 12 ++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 python/semantic_kernel/utils/telemetry/agent_diagnostics/gen_ai_attributes.py diff --git a/python/semantic_kernel/utils/telemetry/agent_diagnostics/decorators.py b/python/semantic_kernel/utils/telemetry/agent_diagnostics/decorators.py index 91e5f28197f4..5eef5a53bf85 100644 --- a/python/semantic_kernel/utils/telemetry/agent_diagnostics/decorators.py +++ b/python/semantic_kernel/utils/telemetry/agent_diagnostics/decorators.py @@ -7,6 +7,7 @@ from opentelemetry.trace import get_tracer from semantic_kernel.utils.experimental_decorator import experimental_function +from semantic_kernel.utils.telemetry.agent_diagnostics import gen_ai_attributes if TYPE_CHECKING: from semantic_kernel.agents.agent import Agent @@ -19,12 +20,22 @@ @experimental_function def trace_agent_invocation(invoke_func: Callable) -> Callable: """Decorator to trace agent invocation.""" + OPERATION_NAME = "invoke_agent" @functools.wraps(invoke_func) async def wrapper_decorator(*args: Any, **kwargs: Any) -> AsyncIterable: agent: "Agent" = args[0] - with tracer.start_as_current_span(agent.name): + with tracer.start_as_current_span(f"{OPERATION_NAME} {agent.name}") as span: + span.set_attributes({ + gen_ai_attributes.OPERATION: OPERATION_NAME, + gen_ai_attributes.AGENT_ID: agent.id, + gen_ai_attributes.AGENT_NAME: agent.name, + }) + + if agent.description: + span.set_attribute(gen_ai_attributes.AGENT_DESCRIPTION, agent.description) + async for response in invoke_func(*args, **kwargs): yield response diff --git a/python/semantic_kernel/utils/telemetry/agent_diagnostics/gen_ai_attributes.py b/python/semantic_kernel/utils/telemetry/agent_diagnostics/gen_ai_attributes.py new file mode 100644 index 000000000000..09062516c9ed --- /dev/null +++ b/python/semantic_kernel/utils/telemetry/agent_diagnostics/gen_ai_attributes.py @@ -0,0 +1,12 @@ +# Copyright (c) Microsoft. All rights reserved. + +# Constants for tracing agent activities with semantic conventions. +# Ideally, we should use the attributes from the semcov package. +# However, many of the attributes are not yet available in the package, +# so we define them here for now. + +# Activity tags +OPERATION = "gen_ai.operation.name" +AGENT_ID = "gen_ai.agent.id" +AGENT_NAME = "gen_ai.agent.name" +AGENT_DESCRIPTION = "gen_ai.agent.description" From 4b3efb7e0fd9e06b7c8004398319bb78fdca6484 Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Tue, 4 Feb 2025 10:02:01 -0800 Subject: [PATCH 2/2] Fix unit tests --- .../agent_diagnostics/test_trace_chat_completion_agent.py | 4 ++-- .../agent_diagnostics/test_trace_open_ai_assistant_agent.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/tests/unit/utils/agent_diagnostics/test_trace_chat_completion_agent.py b/python/tests/unit/utils/agent_diagnostics/test_trace_chat_completion_agent.py index 3c1df16efa14..f222e51227a3 100644 --- a/python/tests/unit/utils/agent_diagnostics/test_trace_chat_completion_agent.py +++ b/python/tests/unit/utils/agent_diagnostics/test_trace_chat_completion_agent.py @@ -18,7 +18,7 @@ async def test_chat_completion_agent_invoke(mock_tracer, chat_history): async for _ in chat_completion_agent.invoke(chat_history): pass # Assert - mock_tracer.start_as_current_span.assert_called_once_with(chat_completion_agent.name) + mock_tracer.start_as_current_span.assert_called_once_with(f"invoke_agent {chat_completion_agent.name}") @patch("semantic_kernel.utils.telemetry.agent_diagnostics.decorators.tracer") @@ -30,4 +30,4 @@ async def test_chat_completion_agent_invoke_stream(mock_tracer, chat_history): async for _ in chat_completion_agent.invoke_stream(chat_history): pass # Assert - mock_tracer.start_as_current_span.assert_called_once_with(chat_completion_agent.name) + mock_tracer.start_as_current_span.assert_called_once_with(f"invoke_agent {chat_completion_agent.name}") diff --git a/python/tests/unit/utils/agent_diagnostics/test_trace_open_ai_assistant_agent.py b/python/tests/unit/utils/agent_diagnostics/test_trace_open_ai_assistant_agent.py index d4a7ae6134ef..4883b9c2a55c 100644 --- a/python/tests/unit/utils/agent_diagnostics/test_trace_open_ai_assistant_agent.py +++ b/python/tests/unit/utils/agent_diagnostics/test_trace_open_ai_assistant_agent.py @@ -18,7 +18,7 @@ async def test_open_ai_assistant_agent_invoke(mock_tracer, chat_history, openai_ async for _ in open_ai_assistant_agent.invoke(chat_history): pass # Assert - mock_tracer.start_as_current_span.assert_called_once_with(open_ai_assistant_agent.name) + mock_tracer.start_as_current_span.assert_called_once_with(f"invoke_agent {open_ai_assistant_agent.name}") @patch("semantic_kernel.utils.telemetry.agent_diagnostics.decorators.tracer") @@ -30,4 +30,4 @@ async def test_open_ai_assistant_agent_invoke_stream(mock_tracer, chat_history, async for _ in open_ai_assistant_agent.invoke_stream(chat_history): pass # Assert - mock_tracer.start_as_current_span.assert_called_once_with(open_ai_assistant_agent.name) + mock_tracer.start_as_current_span.assert_called_once_with(f"invoke_agent {open_ai_assistant_agent.name}")