Skip to content

Commit 2324237

Browse files
fix(langchain): handle optional serialized values gracefully (#1047)
Co-authored-by: Sebastian Thomas <60929398+SebastianThomas1@users.noreply.github.com>
1 parent 37187cc commit 2324237

File tree

2 files changed

+45
-22
lines changed

2 files changed

+45
-22
lines changed

langfuse/callback/langchain.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -149,24 +149,36 @@ def on_llm_new_token(
149149

150150
self.updated_completion_start_time_memo.add(run_id)
151151

152-
def get_langchain_run_name(self, serialized: Dict[str, Any], **kwargs: Any) -> str:
153-
"""Retrieves the 'run_name' for an entity based on Langchain convention, prioritizing the 'name'
154-
key in 'kwargs' or falling back to the 'name' or 'id' in 'serialized'. Defaults to "<unknown>"
155-
if none are available.
152+
def get_langchain_run_name(self, serialized: Optional[Dict[str, Any]], **kwargs: Any) -> str:
153+
"""Retrieve the name of a serialized LangChain runnable.
154+
155+
The prioritization for the determination of the run name is as follows:
156+
- The value assigned to the "name" key in `kwargs`.
157+
- The value assigned to the "name" key in `serialized`.
158+
- The last entry of the value assigned to the "id" key in `serialized`.
159+
- "<unknown>".
156160
157161
Args:
158-
serialized (Dict[str, Any]): A dictionary containing the entity's serialized data.
162+
serialized (Optional[Dict[str, Any]]): A dictionary containing the runnable's serialized data.
159163
**kwargs (Any): Additional keyword arguments, potentially including the 'name' override.
160164
161165
Returns:
162-
str: The determined Langchain run name for the entity.
166+
str: The determined name of the Langchain runnable.
163167
"""
164-
# Check if 'name' is in kwargs and not None, otherwise use default fallback logic
165168
if "name" in kwargs and kwargs["name"] is not None:
166169
return kwargs["name"]
167170

168-
# Fallback to serialized 'name', 'id', or "<unknown>"
169-
return serialized.get("name", serialized.get("id", ["<unknown>"])[-1])
171+
try:
172+
return serialized["name"]
173+
except (KeyError, TypeError):
174+
pass
175+
176+
try:
177+
return serialized["id"][-1]
178+
except (KeyError, TypeError):
179+
pass
180+
181+
return "<unknown>"
170182

171183
def on_retriever_error(
172184
self,
@@ -196,7 +208,7 @@ def on_retriever_error(
196208

197209
def on_chain_start(
198210
self,
199-
serialized: Dict[str, Any],
211+
serialized: Optional[Dict[str, Any]],
200212
inputs: Dict[str, Any],
201213
*,
202214
run_id: UUID,
@@ -289,7 +301,7 @@ def _deregister_langfuse_prompt(self, run_id: Optional[UUID]):
289301

290302
def __generate_trace_and_parent(
291303
self,
292-
serialized: Dict[str, Any],
304+
serialized: Optional[Dict[str, Any]],
293305
inputs: Union[Dict[str, Any], List[str], str, None],
294306
*,
295307
run_id: UUID,
@@ -479,7 +491,7 @@ def on_chain_error(
479491

480492
def on_chat_model_start(
481493
self,
482-
serialized: Dict[str, Any],
494+
serialized: Optional[Dict[str, Any]],
483495
messages: List[List[BaseMessage]],
484496
*,
485497
run_id: UUID,
@@ -508,7 +520,7 @@ def on_chat_model_start(
508520

509521
def on_llm_start(
510522
self,
511-
serialized: Dict[str, Any],
523+
serialized: Optional[Dict[str, Any]],
512524
prompts: List[str],
513525
*,
514526
run_id: UUID,
@@ -535,7 +547,7 @@ def on_llm_start(
535547

536548
def on_tool_start(
537549
self,
538-
serialized: Dict[str, Any],
550+
serialized: Optional[Dict[str, Any]],
539551
input_str: str,
540552
*,
541553
run_id: UUID,
@@ -573,7 +585,7 @@ def on_tool_start(
573585

574586
def on_retriever_start(
575587
self,
576-
serialized: Dict[str, Any],
588+
serialized: Optional[Dict[str, Any]],
577589
query: str,
578590
*,
579591
run_id: UUID,
@@ -698,7 +710,7 @@ def on_tool_error(
698710

699711
def __on_llm_action(
700712
self,
701-
serialized: Dict[str, Any],
713+
serialized: Optional[Dict[str, Any]],
702714
run_id: UUID,
703715
prompts: List[str],
704716
parent_run_id: Optional[UUID] = None,

langfuse/extract_model.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
def _extract_model_name(
13-
serialized: Dict[str, Any],
13+
serialized: Optional[Dict[str, Any]],
1414
**kwargs: Any,
1515
):
1616
"""Extracts the model name from the serialized or kwargs object. This is used to get the model names for Langfuse."""
@@ -106,13 +106,18 @@ def _extract_model_name(
106106

107107

108108
def _extract_model_from_repr_by_pattern(
109-
id: str, serialized: dict, pattern: str, default: Optional[str] = None
109+
id: str, serialized: Optional[Dict[str, Any]], pattern: str, default: Optional[str] = None
110110
):
111+
if serialized is None:
112+
return None
113+
111114
if serialized.get("id")[-1] == id:
112115
if serialized.get("repr"):
113116
extracted = _extract_model_with_regex(pattern, serialized.get("repr"))
114117
return extracted if extracted else default if default else None
115118

119+
return None
120+
116121

117122
def _extract_model_with_regex(pattern: str, text: str):
118123
match = re.search(rf"{pattern}='(.*?)'", text)
@@ -123,21 +128,27 @@ def _extract_model_with_regex(pattern: str, text: str):
123128

124129
def _extract_model_by_path_for_id(
125130
id: str,
126-
serialized: dict,
131+
serialized: Optional[Dict[str, Any]],
127132
kwargs: dict,
128133
keys: List[str],
129-
select_from: str = Literal["serialized", "kwargs"],
134+
select_from: Literal["serialized", "kwargs"],
130135
):
136+
if serialized is None and select_from == "serialized":
137+
return None
138+
131139
if serialized.get("id")[-1] == id:
132140
return _extract_model_by_path(serialized, kwargs, keys, select_from)
133141

134142

135143
def _extract_model_by_path(
136-
serialized: dict,
144+
serialized: Optional[Dict[str, Any]],
137145
kwargs: dict,
138146
keys: List[str],
139-
select_from: str = Literal["serialized", "kwargs"],
147+
select_from: Literal["serialized", "kwargs"],
140148
):
149+
if serialized is None and select_from == "serialized":
150+
return None
151+
141152
current_obj = kwargs if select_from == "kwargs" else serialized
142153

143154
for key in keys:

0 commit comments

Comments
 (0)