Skip to content

Commit 1ce911f

Browse files
committed
cleanup
1 parent 881a65b commit 1ce911f

4 files changed

Lines changed: 65 additions & 67 deletions

File tree

langfuse/_client/client.py

Lines changed: 51 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,18 @@
1010
from datetime import datetime
1111
from hashlib import sha256
1212
from time import time_ns
13-
from typing import Any, Dict, List, Literal, Optional, Union, cast, overload
13+
from typing import (
14+
Any,
15+
Dict,
16+
List,
17+
Literal,
18+
Optional,
19+
Union,
20+
Type,
21+
cast,
22+
overload,
23+
get_args,
24+
)
1425

1526
import backoff
1627
import httpx
@@ -39,6 +50,7 @@
3950
from langfuse._client.constants import (
4051
ObservationTypeLiteral,
4152
ObservationTypeLiteralNoEvent,
53+
ObservationTypeGenerationLike,
4254
)
4355
from langfuse._client.resource_manager import LangfuseResourceManager
4456
from langfuse._client.span import (
@@ -656,10 +668,14 @@ def _create_observation_from_otel_span(
656668
LangfuseGuardrail,
657669
]:
658670
"""Create the appropriate observation type from an OTEL span."""
659-
if as_type == "generation":
660-
return LangfuseGeneration(
671+
if as_type in get_args(ObservationTypeGenerationLike):
672+
observation_class = self._get_span_class(as_type)
673+
# Type ignore to prevent overloads of internal _get_span_class function,
674+
# issue is that LangfuseEvent could be returned
675+
return observation_class( # type: ignore[return-value]
661676
otel_span=otel_span,
662677
langfuse_client=self,
678+
environment=self._environment,
663679
input=input,
664680
output=output,
665681
metadata=metadata,
@@ -673,21 +689,12 @@ def _create_observation_from_otel_span(
673689
cost_details=cost_details,
674690
prompt=prompt,
675691
)
676-
elif as_type == "span":
677-
return LangfuseSpan(
678-
otel_span=otel_span,
679-
langfuse_client=self,
680-
environment=self._environment,
681-
input=input,
682-
output=output,
683-
metadata=metadata,
684-
version=version,
685-
level=level,
686-
status_message=status_message,
687-
)
688692
else:
689-
# For all other observation types (agent, tool, etc.), create a span and set the type
690-
span = LangfuseSpan(
693+
# For other types (e.g. span, guardrail), create appropriate class without generation properties
694+
observation_class = self._get_span_class(as_type)
695+
# Type ignore to prevent overloads of internal _get_span_class function,
696+
# issue is that LangfuseEvent could be returned
697+
return observation_class( # type: ignore[return-value]
691698
otel_span=otel_span,
692699
langfuse_client=self,
693700
environment=self._environment,
@@ -698,10 +705,9 @@ def _create_observation_from_otel_span(
698705
level=level,
699706
status_message=status_message,
700707
)
701-
# Set the observation type on the span
702-
span._observation_type = as_type
703-
span._otel_span.set_attribute("langfuse.observation.type", as_type)
704-
return span
708+
# span._observation_type = as_type
709+
# span._otel_span.set_attribute("langfuse.observation.type", as_type)
710+
# return span
705711

706712
def start_generation(
707713
self,
@@ -1075,8 +1081,8 @@ def start_as_current_observation(
10751081
status_message: Optional status message for the observation
10761082
end_on_exit (default: True): Whether to end the span automatically when leaving the context manager. If False, the span must be manually ended to avoid memory leaks.
10771083
1078-
# TODO: also add the generation like types here!
1079-
The following parameters are only available when as_type="generation":
1084+
The following parameters are available when as_type is: "generation", "agent",
1085+
"tool", "chain", "retriever", "evaluator" or "embedding".
10801086
completion_start_time: When the model started generating the response
10811087
model: Name/identifier of the AI model used (e.g., "gpt-4")
10821088
model_parameters: Parameters used for the model (e.g., temperature, max_tokens)
@@ -1285,7 +1291,18 @@ def start_as_current_observation(
12851291
def _get_span_class(
12861292
self,
12871293
as_type: ObservationTypeLiteral,
1288-
) -> type:
1294+
) -> Union[
1295+
Type[LangfuseAgent],
1296+
Type[LangfuseTool],
1297+
Type[LangfuseChain],
1298+
Type[LangfuseRetriever],
1299+
Type[LangfuseEvaluator],
1300+
Type[LangfuseEmbedding],
1301+
Type[LangfuseGuardrail],
1302+
Type[LangfuseGeneration],
1303+
Type[LangfuseEvent],
1304+
Type[LangfuseSpan],
1305+
]:
12891306
"""Get the appropriate span class based on as_type."""
12901307
normalized_type = as_type.lower()
12911308

@@ -1400,7 +1417,15 @@ def _start_as_current_otel_span_with_processed_media(
14001417
"status_message": status_message,
14011418
}
14021419

1403-
if span_class == LangfuseGeneration:
1420+
if span_class in [
1421+
LangfuseGeneration,
1422+
LangfuseAgent,
1423+
LangfuseTool,
1424+
LangfuseChain,
1425+
LangfuseRetriever,
1426+
LangfuseEvaluator,
1427+
LangfuseEmbedding,
1428+
]:
14041429
common_args.update(
14051430
{
14061431
"completion_start_time": completion_start_time,
@@ -1411,19 +1436,7 @@ def _start_as_current_otel_span_with_processed_media(
14111436
"prompt": prompt,
14121437
}
14131438
)
1414-
# TODO: for some, create generation-like classes with those props.
1415-
elif span_class in [
1416-
LangfuseSpan,
1417-
LangfuseAgent,
1418-
LangfuseTool,
1419-
LangfuseChain,
1420-
LangfuseRetriever,
1421-
LangfuseEvaluator,
1422-
LangfuseEmbedding,
1423-
LangfuseGuardrail,
1424-
]:
1425-
# set their type internally in the class
1426-
pass
1439+
# For span and guardrail types, no generation properties needed
14271440

14281441
yield span_class(**common_args)
14291442

langfuse/_client/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
LANGFUSE_TRACER_NAME = "langfuse-sdk"
1010

1111

12-
"""Note: this type is used with .__args__ in some cases and therefore must remain flat"""
12+
"""Note: this type is used with .__args__ / get_args in some cases and therefore must remain flat"""
1313
ObservationTypeGenerationLike: TypeAlias = Literal[
1414
"generation",
1515
"agent",

langfuse/_client/observe.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,9 @@ def observe(
109109
name (Optional[str]): Custom name for the created trace or span. If not provided, the function name is used.
110110
as_type (Optional[Literal]): Set the observation type. Supported values:
111111
"generation", "span", "agent", "tool", "chain", "retriever", "embedding", "evaluator", "guardrail".
112-
When set to "generation", creates a specialized LLM generation span with model metrics support.
113-
Other types create spans with the specified type for graph visualization and filtering in the Langfuse UI.
112+
Observation types are highlighted in the Langfuse UI for filtering and visualization.
113+
The types "generation", "agent", "tool", "chain", "retriever", "embedding", "evaluator" create a span which
114+
allows to set additional attributes such as model metrics..
114115
115116
Returns:
116117
Callable: A wrapped version of the original function that automatically creates and manages Langfuse spans.
@@ -136,13 +137,6 @@ async def generate_answer(query):
136137
return response.choices[0].message.content
137138
```
138139
139-
For automatic graph instrumentation with agent workflows:
140-
```python
141-
@observe(as_type="agent")
142-
def planning_agent():
143-
return create_plan()
144-
```
145-
146140
For trace context propagation between functions:
147141
```python
148142
@observe()
@@ -369,7 +363,6 @@ def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
369363
# Set public key in execution context for nested decorated functions
370364
with _set_current_public_key(public_key):
371365
langfuse_client = get_client(public_key=public_key)
372-
373366
context_manager: Optional[
374367
Union[
375368
_AgnosticContextManager[LangfuseGeneration],

langfuse/_client/span.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ def __init__(
116116
LangfuseOtelSpanAttributes.OBSERVATION_TYPE, as_type
117117
)
118118
self._langfuse_client = langfuse_client
119-
120119
self._observation_type = as_type
121120

122121
self.trace_id = self._langfuse_client._get_otel_trace_id(otel_span)
@@ -606,15 +605,7 @@ def update(
606605
level=level,
607606
status_message=status_message,
608607
observation_type=cast(
609-
Literal[
610-
"generation",
611-
"agent",
612-
"tool",
613-
"chain",
614-
"retriever",
615-
"evaluator",
616-
"embedding",
617-
],
608+
ObservationTypeGenerationLike,
618609
self._observation_type,
619610
),
620611
completion_start_time=completion_start_time,
@@ -1072,7 +1063,8 @@ class LangfuseSpan(LangfuseObservationWrapper):
10721063
This class represents a general-purpose span that can be used to trace
10731064
any operation in your application. It extends the base LangfuseObservationWrapper
10741065
with specific methods for creating child spans, generations, and updating
1075-
span-specific attributes.
1066+
span-specific attributes. If possible, use a more specific type for
1067+
better observability and insights.
10761068
"""
10771069

10781070
def __init__(
@@ -1602,7 +1594,7 @@ def update(
16021594

16031595

16041596
class LangfuseAgent(LangfuseObservationWrapper):
1605-
"""Specialized span for agent observations in agentic workflows."""
1597+
"""Agent observation for reasoning blocks that act on tools using LLM guidance."""
16061598

16071599
def __init__(self, **kwargs: Any) -> None:
16081600
"""Initialize a new LangfuseAgent span."""
@@ -1611,7 +1603,7 @@ def __init__(self, **kwargs: Any) -> None:
16111603

16121604

16131605
class LangfuseTool(LangfuseObservationWrapper):
1614-
"""Specialized span for tool observations in agentic workflows."""
1606+
"""Tool observation representing external tool calls, e.g., calling a weather API."""
16151607

16161608
def __init__(self, **kwargs: Any) -> None:
16171609
"""Initialize a new LangfuseTool span."""
@@ -1620,7 +1612,7 @@ def __init__(self, **kwargs: Any) -> None:
16201612

16211613

16221614
class LangfuseChain(LangfuseObservationWrapper):
1623-
"""Specialized span for chain observations in agentic workflows."""
1615+
"""Chain observation for connecting LLM application steps, e.g. passing context from retriever to LLM."""
16241616

16251617
def __init__(self, **kwargs: Any) -> None:
16261618
"""Initialize a new LangfuseChain span."""
@@ -1629,7 +1621,7 @@ def __init__(self, **kwargs: Any) -> None:
16291621

16301622

16311623
class LangfuseRetriever(LangfuseObservationWrapper):
1632-
"""Specialized span for retriever observations in agentic workflows."""
1624+
"""Retriever observation for data retrieval steps, e.g. vector store or database queries."""
16331625

16341626
def __init__(self, **kwargs: Any) -> None:
16351627
"""Initialize a new LangfuseRetriever span."""
@@ -1638,7 +1630,7 @@ def __init__(self, **kwargs: Any) -> None:
16381630

16391631

16401632
class LangfuseEmbedding(LangfuseObservationWrapper):
1641-
"""Specialized span for embedding observations in agentic workflows."""
1633+
"""Embedding observation for LLM embedding calls, typically used before retrieval."""
16421634

16431635
def __init__(self, **kwargs: Any) -> None:
16441636
"""Initialize a new LangfuseEmbedding span."""
@@ -1647,7 +1639,7 @@ def __init__(self, **kwargs: Any) -> None:
16471639

16481640

16491641
class LangfuseEvaluator(LangfuseObservationWrapper):
1650-
"""Specialized span for evaluator observations in agentic workflows."""
1642+
"""Evaluator observation for assessing relevance, correctness, or helpfulness of LLM outputs."""
16511643

16521644
def __init__(self, **kwargs: Any) -> None:
16531645
"""Initialize a new LangfuseEvaluator span."""
@@ -1656,7 +1648,7 @@ def __init__(self, **kwargs: Any) -> None:
16561648

16571649

16581650
class LangfuseGuardrail(LangfuseObservationWrapper):
1659-
"""Specialized span for guardrail observations in agentic workflows."""
1651+
"""Guardrail observation for protection e.g. against jailbreaks or offensive content."""
16601652

16611653
def __init__(self, **kwargs: Any) -> None:
16621654
"""Initialize a new LangfuseGuardrail span."""

0 commit comments

Comments
 (0)