Skip to content

Commit 744ddb6

Browse files
committed
address pr comments
1 parent ae6bf62 commit 744ddb6

File tree

3 files changed

+30
-14
lines changed

3 files changed

+30
-14
lines changed

instrumentation-genai/opentelemetry-instrumentation-langchain/src/opentelemetry/instrumentation/langchain/callback_handler.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
from langchain_core.messages import BaseMessage # type: ignore
2323
from langchain_core.outputs import LLMResult # type: ignore
2424

25-
from opentelemetry.instrumentation.langchain.span_manager import _SpanManager
25+
from opentelemetry.instrumentation.langchain.span_manager import (
26+
_OPERATION_INVOKE_AGENT,
27+
_SpanManager,
28+
)
2629
from opentelemetry.semconv._incubating.attributes import (
2730
gen_ai_attributes as GenAI,
2831
)
@@ -260,7 +263,7 @@ def on_chain_start(
260263
# If this is an agent chain, set agent-specific attributes
261264
if metadata and "agent_name" in metadata:
262265
span.set_attribute(GenAI.GEN_AI_AGENT_NAME, metadata["agent_name"])
263-
span.set_attribute(GenAI.GEN_AI_OPERATION_NAME, "invoke_agent")
266+
span.set_attribute(GenAI.GEN_AI_OPERATION_NAME, _OPERATION_INVOKE_AGENT)
264267

265268
def on_chain_end(
266269
self,

instrumentation-genai/opentelemetry-instrumentation-langchain/src/opentelemetry/instrumentation/langchain/span_manager.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
from opentelemetry.trace import Span, SpanKind, Tracer, set_span_in_context
2626
from opentelemetry.trace.status import Status, StatusCode
2727

28-
__all__ = ["_SpanManager"]
28+
__all__ = ["_SpanManager", "_OPERATION_INVOKE_AGENT"]
29+
30+
# Operation name constants
31+
_OPERATION_INVOKE_AGENT = "invoke_agent"
2932

3033

3134
@dataclass
@@ -98,9 +101,9 @@ def create_agent_span(
98101
agent_name: Optional[str] = None,
99102
) -> Span:
100103
"""Create a span for agent invocation."""
101-
span_name = (
102-
f"invoke_agent {agent_name}" if agent_name else "invoke_agent"
103-
)
104+
# Use "unknown" as default if agent_name is not provided
105+
effective_agent_name = agent_name or "unknown"
106+
span_name = f"{_OPERATION_INVOKE_AGENT} {effective_agent_name}"
104107
span = self._create_span(
105108
run_id=run_id,
106109
parent_run_id=parent_run_id,
@@ -109,10 +112,9 @@ def create_agent_span(
109112
)
110113
span.set_attribute(
111114
GenAI.GEN_AI_OPERATION_NAME,
112-
"invoke_agent",
115+
_OPERATION_INVOKE_AGENT,
113116
)
114-
if agent_name:
115-
span.set_attribute(GenAI.GEN_AI_AGENT_NAME, agent_name)
117+
span.set_attribute(GenAI.GEN_AI_AGENT_NAME, effective_agent_name)
116118

117119
return span
118120

@@ -122,15 +124,19 @@ def create_chain_span(
122124
parent_run_id: Optional[UUID],
123125
chain_name: str,
124126
) -> Span:
125-
"""Create a span for chain execution."""
127+
"""Create a span for chain execution.
128+
129+
Chains are internal operations by default and don't have gen_ai.operation.name.
130+
However, if the chain represents an agent (determined by metadata in the callback),
131+
the operation name and agent name attributes will be set separately by the
132+
callback handler to make it an agent span.
133+
"""
126134
span = self._create_span(
127135
run_id=run_id,
128136
parent_run_id=parent_run_id,
129137
span_name=f"chain {chain_name}",
130138
kind=SpanKind.INTERNAL,
131139
)
132-
# Chains are internal operations, not direct GenAI operations
133-
# We can track them but they don't have a gen_ai.operation.name
134140
return span
135141

136142
def end_span(self, run_id: UUID) -> None:

instrumentation-genai/opentelemetry-instrumentation-langchain/tests/test_agent_spans.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,17 @@ def callback_handler(tracer_provider):
2222

2323

2424
def test_agent_chain_span(callback_handler, span_exporter):
25-
"""Test that agent chains create proper invoke_agent spans."""
25+
"""Test that agent chains create proper invoke_agent spans.
26+
27+
Note: Agent chains are created via create_chain_span() but are enhanced
28+
with agent-specific attributes (gen_ai.agent.name and gen_ai.operation.name)
29+
when metadata contains 'agent_name'. This is different from regular chains
30+
which remain as internal operations without gen_ai.operation.name.
31+
"""
2632
run_id = uuid4()
2733
parent_run_id = uuid4()
2834

29-
# Start a chain that represents an agent
35+
# Start a chain that represents an agent (note: metadata includes agent_name)
3036
callback_handler.on_chain_start(
3137
serialized={
3238
"name": "TestAgent",
@@ -52,6 +58,7 @@ def test_agent_chain_span(callback_handler, span_exporter):
5258
span = spans[0]
5359
assert span.name == "chain TestAgent"
5460
assert span.kind == SpanKind.INTERNAL
61+
# Agent chains have these attributes set via callback_handler when metadata contains agent_name
5562
assert span.attributes.get(GenAI.GEN_AI_AGENT_NAME) == "TestAgent"
5663
assert span.attributes.get(GenAI.GEN_AI_OPERATION_NAME) == "invoke_agent"
5764

0 commit comments

Comments
 (0)