Переглянути джерело

Feat/add langsmith dotted order (#10856)

Joe 5 місяців тому
батько
коміт
2dc29cfee3

+ 1 - 0
api/core/ops/langsmith_trace/entities/langsmith_trace_entity.py

@@ -49,6 +49,7 @@ class LangSmithRunModel(LangSmithTokenUsage, LangSmithMultiModel):
     reference_example_id: Optional[str] = Field(None, description="Reference example ID associated with the run")
     input_attachments: Optional[dict[str, Any]] = Field(None, description="Input attachments of the run")
     output_attachments: Optional[dict[str, Any]] = Field(None, description="Output attachments of the run")
+    dotted_order: Optional[str] = Field(None, description="Dotted order of the run")
 
     @field_validator("inputs", "outputs")
     @classmethod

+ 19 - 1
api/core/ops/langsmith_trace/langsmith_trace.py

@@ -25,7 +25,7 @@ from core.ops.langsmith_trace.entities.langsmith_trace_entity import (
     LangSmithRunType,
     LangSmithRunUpdateModel,
 )
-from core.ops.utils import filter_none_values
+from core.ops.utils import filter_none_values, generate_dotted_order
 from extensions.ext_database import db
 from models.model import EndUser, MessageFile
 from models.workflow import WorkflowNodeExecution
@@ -62,6 +62,16 @@ class LangSmithDataTrace(BaseTraceInstance):
             self.generate_name_trace(trace_info)
 
     def workflow_trace(self, trace_info: WorkflowTraceInfo):
+        trace_id = trace_info.message_id or trace_info.workflow_app_log_id or trace_info.workflow_run_id
+        message_dotted_order = (
+            generate_dotted_order(trace_info.message_id, trace_info.start_time) if trace_info.message_id else None
+        )
+        workflow_dotted_order = generate_dotted_order(
+            trace_info.workflow_app_log_id or trace_info.workflow_run_id,
+            trace_info.workflow_data.created_at,
+            message_dotted_order,
+        )
+
         if trace_info.message_id:
             message_run = LangSmithRunModel(
                 id=trace_info.message_id,
@@ -76,6 +86,8 @@ class LangSmithDataTrace(BaseTraceInstance):
                 },
                 tags=["message", "workflow"],
                 error=trace_info.error,
+                trace_id=trace_id,
+                dotted_order=message_dotted_order,
             )
             self.add_run(message_run)
 
@@ -95,6 +107,8 @@ class LangSmithDataTrace(BaseTraceInstance):
             error=trace_info.error,
             tags=["workflow"],
             parent_run_id=trace_info.message_id or None,
+            trace_id=trace_id,
+            dotted_order=workflow_dotted_order,
         )
 
         self.add_run(langsmith_run)
@@ -177,6 +191,7 @@ class LangSmithDataTrace(BaseTraceInstance):
             else:
                 run_type = LangSmithRunType.tool
 
+            node_dotted_order = generate_dotted_order(node_execution_id, created_at, workflow_dotted_order)
             langsmith_run = LangSmithRunModel(
                 total_tokens=node_total_tokens,
                 name=node_type,
@@ -191,6 +206,9 @@ class LangSmithDataTrace(BaseTraceInstance):
                 },
                 parent_run_id=trace_info.workflow_app_log_id or trace_info.workflow_run_id,
                 tags=["node_execution"],
+                id=node_execution_id,
+                trace_id=trace_id,
+                dotted_order=node_dotted_order,
             )
 
             self.add_run(langsmith_run)

+ 17 - 0
api/core/ops/utils.py

@@ -1,5 +1,6 @@
 from contextlib import contextmanager
 from datetime import datetime
+from typing import Optional, Union
 
 from extensions.ext_database import db
 from models.model import Message
@@ -43,3 +44,19 @@ def replace_text_with_content(data):
         return [replace_text_with_content(item) for item in data]
     else:
         return data
+
+
+def generate_dotted_order(
+    run_id: str, start_time: Union[str, datetime], parent_dotted_order: Optional[str] = None
+) -> str:
+    """
+    generate dotted_order for langsmith
+    """
+    start_time = datetime.fromisoformat(start_time) if isinstance(start_time, str) else start_time
+    timestamp = start_time.strftime("%Y%m%dT%H%M%S%f")[:-3] + "Z"
+    current_segment = f"{timestamp}{run_id}"
+
+    if parent_dotted_order is None:
+        return current_segment
+
+    return f"{parent_dotted_order}.{current_segment}"