fix: improve LangSmith traces with added details (#7897)
* langsmith-improve * langsmith-improve * [autofix.ci] apply automated fixes * Update langsmith.py * fix lint * [autofix.ci] apply automated fixes * Update langsmith.py * Refactor LangSmithTracer to improve type checking and error handling - Moved RunTree import to the appropriate section for clarity. - Updated end_trace method to check both readiness and existence of run_tree before proceeding. * readd if not self._ready check * solve invalid run types * Update src/backend/base/langflow/services/tracing/langsmith.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update src/backend/base/langflow/services/tracing/langsmith.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update src/backend/base/langflow/services/tracing/langsmith.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
parent
1903f607e8
commit
c05327d773
1 changed files with 60 additions and 27 deletions
|
|
@ -18,6 +18,7 @@ if TYPE_CHECKING:
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from langchain.callbacks.base import BaseCallbackHandler
|
from langchain.callbacks.base import BaseCallbackHandler
|
||||||
|
from langsmith.run_trees import RunTree
|
||||||
|
|
||||||
from langflow.graph.vertex.base import Vertex
|
from langflow.graph.vertex.base import Vertex
|
||||||
from langflow.services.tracing.schema import Log
|
from langflow.services.tracing.schema import Log
|
||||||
|
|
@ -29,28 +30,51 @@ class LangSmithTracer(BaseTracer):
|
||||||
self._ready = self.setup_langsmith()
|
self._ready = self.setup_langsmith()
|
||||||
if not self._ready:
|
if not self._ready:
|
||||||
return
|
return
|
||||||
from langsmith.run_trees import RunTree
|
|
||||||
|
|
||||||
self.trace_name = trace_name
|
self.trace_name = trace_name
|
||||||
self.trace_type = trace_type
|
self.trace_type = trace_type
|
||||||
self.project_name = project_name
|
self.project_name = project_name
|
||||||
self.trace_id = trace_id
|
self.trace_id = trace_id
|
||||||
self._run_tree = RunTree(
|
from langsmith import get_current_run_tree
|
||||||
project_name=self.project_name,
|
from langsmith.run_helpers import trace
|
||||||
name=self.trace_name,
|
|
||||||
run_type=self.trace_type,
|
self._run_tree: RunTree | None = None
|
||||||
id=self.trace_id,
|
|
||||||
)
|
|
||||||
self._run_tree.add_event({"name": "Start", "time": datetime.now(timezone.utc).isoformat()})
|
|
||||||
self._children: dict[str, RunTree] = {}
|
self._children: dict[str, RunTree] = {}
|
||||||
except Exception: # noqa: BLE001
|
self._children_traces: dict[str, trace] = {}
|
||||||
logger.debug("Error setting up LangSmith tracer")
|
self._child_link: dict[str, str] = {}
|
||||||
|
parent = get_current_run_tree()
|
||||||
|
if parent is not None and (parent.id == trace_id or parent.name == trace_name):
|
||||||
|
# duplicate init of LangSmithTracer with same trace_id\\trace_name, using current run tree
|
||||||
|
self._run_tree = parent
|
||||||
|
else:
|
||||||
|
self._trace = trace(
|
||||||
|
project_name=self.project_name,
|
||||||
|
name=self.trace_name,
|
||||||
|
run_type=self.get_run_type(self.trace_type),
|
||||||
|
run_id=self.trace_id if parent is None else None,
|
||||||
|
parent=parent,
|
||||||
|
)
|
||||||
|
self._run_tree = self._trace.__enter__()
|
||||||
|
self._run_tree.add_event({"name": "Start", "time": datetime.now(timezone.utc).isoformat()})
|
||||||
|
self._run_tree.post()
|
||||||
|
except Exception as ex: # noqa: BLE001
|
||||||
|
logger.warning(f"Error setting up LangSmith tracer: {ex}")
|
||||||
self._ready = False
|
self._ready = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ready(self):
|
def ready(self):
|
||||||
return self._ready
|
return self._ready
|
||||||
|
|
||||||
|
def get_run_type(self, run_type: str) -> str:
|
||||||
|
from typing import get_args
|
||||||
|
|
||||||
|
from langsmith import client
|
||||||
|
|
||||||
|
valid_run_types = set(get_args(client.RUN_TYPE_T))
|
||||||
|
if run_type not in valid_run_types:
|
||||||
|
logger.warning("Run type %s is not valid. Using default run type 'chain'.", run_type)
|
||||||
|
return "chain"
|
||||||
|
return run_type
|
||||||
|
|
||||||
def setup_langsmith(self) -> bool:
|
def setup_langsmith(self) -> bool:
|
||||||
if os.getenv("LANGCHAIN_API_KEY") is None:
|
if os.getenv("LANGCHAIN_API_KEY") is None:
|
||||||
return False
|
return False
|
||||||
|
|
@ -66,7 +90,7 @@ class LangSmithTracer(BaseTracer):
|
||||||
|
|
||||||
def add_trace(
|
def add_trace(
|
||||||
self,
|
self,
|
||||||
trace_id: str, # noqa: ARG002
|
trace_id: str,
|
||||||
trace_name: str,
|
trace_name: str,
|
||||||
trace_type: str,
|
trace_type: str,
|
||||||
inputs: dict[str, Any],
|
inputs: dict[str, Any],
|
||||||
|
|
@ -78,15 +102,20 @@ class LangSmithTracer(BaseTracer):
|
||||||
processed_inputs = {}
|
processed_inputs = {}
|
||||||
if inputs:
|
if inputs:
|
||||||
processed_inputs = self._convert_to_langchain_types(inputs)
|
processed_inputs = self._convert_to_langchain_types(inputs)
|
||||||
child = self._run_tree.create_child(
|
|
||||||
|
from langsmith.run_helpers import trace
|
||||||
|
|
||||||
|
child_trace = trace(
|
||||||
name=trace_name,
|
name=trace_name,
|
||||||
run_type=trace_type, # type: ignore[arg-type]
|
run_type=self.get_run_type(trace_type),
|
||||||
|
parent=self._run_tree,
|
||||||
inputs=processed_inputs,
|
inputs=processed_inputs,
|
||||||
|
metadata=self._convert_to_langchain_types(metadata) if metadata else None,
|
||||||
)
|
)
|
||||||
if metadata:
|
child = child_trace.__enter__()
|
||||||
child.add_metadata(self._convert_to_langchain_types(metadata))
|
child.post()
|
||||||
self._children[trace_name] = child
|
self._children[trace_id] = child
|
||||||
self._child_link: dict[str, str] = {}
|
self._children_traces[trace_id] = child_trace
|
||||||
|
|
||||||
def _convert_to_langchain_types(self, io_dict: dict[str, Any]):
|
def _convert_to_langchain_types(self, io_dict: dict[str, Any]):
|
||||||
converted = {}
|
converted = {}
|
||||||
|
|
@ -117,15 +146,18 @@ class LangSmithTracer(BaseTracer):
|
||||||
|
|
||||||
def end_trace(
|
def end_trace(
|
||||||
self,
|
self,
|
||||||
trace_id: str, # noqa: ARG002
|
trace_id: str,
|
||||||
trace_name: str,
|
trace_name: str, # noqa: ARG002
|
||||||
outputs: dict[str, Any] | None = None,
|
outputs: dict[str, Any] | None = None,
|
||||||
error: Exception | None = None,
|
error: Exception | None = None,
|
||||||
logs: Sequence[Log | dict] = (),
|
logs: Sequence[Log | dict] = (),
|
||||||
):
|
):
|
||||||
if not self._ready or trace_name not in self._children:
|
if not self._ready or not self._run_tree:
|
||||||
return
|
return
|
||||||
child = self._children[trace_name]
|
if trace_id not in self._children:
|
||||||
|
logger.warning(f"Trace {trace_id} not found in children traces")
|
||||||
|
return
|
||||||
|
child = self._children[trace_id]
|
||||||
raw_outputs = {}
|
raw_outputs = {}
|
||||||
processed_outputs = {}
|
processed_outputs = {}
|
||||||
if outputs:
|
if outputs:
|
||||||
|
|
@ -136,10 +168,8 @@ class LangSmithTracer(BaseTracer):
|
||||||
child.add_metadata(self._convert_to_langchain_types({"logs": {log.get("name"): log for log in logs_dicts}}))
|
child.add_metadata(self._convert_to_langchain_types({"logs": {log.get("name"): log for log in logs_dicts}}))
|
||||||
child.add_metadata(self._convert_to_langchain_types({"outputs": raw_outputs}))
|
child.add_metadata(self._convert_to_langchain_types({"outputs": raw_outputs}))
|
||||||
child.end(outputs=processed_outputs, error=self._error_to_string(error))
|
child.end(outputs=processed_outputs, error=self._error_to_string(error))
|
||||||
if error:
|
self._children_traces[trace_id].__exit__(None, None, None)
|
||||||
child.patch()
|
self._child_link[trace_id] = child.get_url()
|
||||||
else:
|
|
||||||
child.post()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _error_to_string(error: Exception | None):
|
def _error_to_string(error: Exception | None):
|
||||||
|
|
@ -162,7 +192,10 @@ class LangSmithTracer(BaseTracer):
|
||||||
if metadata:
|
if metadata:
|
||||||
self._run_tree.add_metadata(serialize(metadata))
|
self._run_tree.add_metadata(serialize(metadata))
|
||||||
self._run_tree.end(outputs=serialize(outputs), error=self._error_to_string(error))
|
self._run_tree.end(outputs=serialize(outputs), error=self._error_to_string(error))
|
||||||
self._run_tree.post()
|
self._run_tree.patch()
|
||||||
|
self._run_link = self._run_tree.get_url()
|
||||||
|
if getattr(self, "_trace", None):
|
||||||
|
self._trace.__exit__()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def run_link(self):
|
def run_link(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue