diff --git a/apps/api/src/services/langfuse_client.py b/apps/api/src/services/langfuse_client.py index 5a28f4901..63946acae 100644 --- a/apps/api/src/services/langfuse_client.py +++ b/apps/api/src/services/langfuse_client.py @@ -123,14 +123,27 @@ class LangfuseTraceContext: self._otel_trace_id ) - self.trace = self._client.trace( - name=self.name, - metadata=enriched_metadata, - ) - - # 記錄 Langfuse trace_id 供反向連結 - if self.trace: - self._langfuse_trace_id = self.trace.id + # Langfuse v4.x API: 使用 create_trace_id() 取代舊的 trace() + # 舊 API (v2.x): self._client.trace(name=..., metadata=...) + # 新 API (v4.x): 透過 OTEL 整合或裝飾器 + if hasattr(self._client, "trace"): + # Legacy API (v2.x) + self.trace = self._client.trace( + name=self.name, + metadata=enriched_metadata, + ) + if self.trace: + self._langfuse_trace_id = self.trace.id + else: + # Langfuse v4.x - 使用 create_trace_id() 並記錄 + # 完整追蹤依賴 OTEL 整合 + self._langfuse_trace_id = self._client.create_trace_id() + logger.debug( + "langfuse_v4_trace_created", + trace_id=self._langfuse_trace_id, + name=self.name, + note="Full tracing via OTEL integration", + ) logger.debug( "langfuse_trace_started", @@ -177,25 +190,33 @@ class LangfuseTraceContext: usage: Token 使用量 {"input": x, "output": y} metadata: 額外 metadata """ - if not self.trace: - return None - - try: - gen = self.trace.generation( - name=name, - model=model, - input=input, - output=output, - usage=usage, - metadata=metadata or {}, - ) - return gen - except Exception as e: - logger.warning( - "langfuse_generation_failed", - error=str(e), + # Langfuse v4.x: trace 物件可能不存在,改用 logger 記錄 + if self.trace and hasattr(self.trace, "generation"): + try: + gen = self.trace.generation( + name=name, + model=model, + input=input, + output=output, + usage=usage, + metadata=metadata or {}, + ) + return gen + except Exception as e: + logger.warning( + "langfuse_generation_failed", + error=str(e), + name=name, + model=model, + ) + return None + else: + # Langfuse v4.x: 透過 OTEL 追蹤,這裡只記錄 debug log + logger.debug( + "langfuse_generation_logged", name=name, model=model, + trace_id=self._langfuse_trace_id, ) return None @@ -207,13 +228,15 @@ class LangfuseTraceContext: name: Span 名稱 metadata: 額外 metadata """ - if not self.trace: - return None - - try: - return self.trace.span(name=name, metadata=metadata or {}) - except Exception as e: - logger.warning("langfuse_span_failed", error=str(e), name=name) + if self.trace and hasattr(self.trace, "span"): + try: + return self.trace.span(name=name, metadata=metadata or {}) + except Exception as e: + logger.warning("langfuse_span_failed", error=str(e), name=name) + return None + else: + # Langfuse v4.x: OTEL spans + logger.debug("langfuse_span_logged", name=name, trace_id=self._langfuse_trace_id) return None def score( @@ -230,20 +253,26 @@ class LangfuseTraceContext: value: 分數 (0.0 - 1.0) comment: 評論 """ - if not self.trace: - return - - try: - self.trace.score( + if self.trace and hasattr(self.trace, "score"): + try: + self.trace.score( + name=name, + value=value, + comment=comment, + ) + except Exception as e: + logger.warning( + "langfuse_score_failed", + error=str(e), + name=name, + ) + else: + # Langfuse v4.x: score via OTEL attributes + logger.debug( + "langfuse_score_logged", name=name, value=value, - comment=comment, - ) - except Exception as e: - logger.warning( - "langfuse_score_failed", - error=str(e), - name=name, + trace_id=self._langfuse_trace_id, )