Browse Source

fix(langfuse): send raw cost without multiplier and use username as userId

- Calculate raw cost (multiplier=1.0) separately for Langfuse while
  keeping multiplied cost for session billing and rate limiting
- Change userId from numeric ID to user.name for readable Langfuse traces
- Key name already available in trace metadata as keyName
ding113 1 week ago
parent
commit
debdd69237

+ 34 - 4
src/app/v1/_lib/proxy/response-handler.ts

@@ -740,8 +740,9 @@ export class ProxyResponseHandler {
           await trackCostToRedis(session, usageMetrics);
         }
 
-        // Calculate cost (for session tracking and Langfuse tracing)
+        // Calculate cost for session tracking (with multiplier) and Langfuse (raw)
         let costUsdStr: string | undefined;
+        let rawCostUsdStr: string | undefined;
         if (usageMetrics) {
           try {
             if (session.request.model) {
@@ -756,6 +757,20 @@ export class ProxyResponseHandler {
                 if (cost.gt(0)) {
                   costUsdStr = cost.toString();
                 }
+                // Raw cost without multiplier for Langfuse
+                if (provider.costMultiplier !== 1) {
+                  const rawCost = calculateRequestCost(
+                    usageMetrics,
+                    priceData,
+                    1.0,
+                    session.getContext1mApplied()
+                  );
+                  if (rawCost.gt(0)) {
+                    rawCostUsdStr = rawCost.toString();
+                  }
+                } else {
+                  rawCostUsdStr = costUsdStr;
+                }
               }
             }
           } catch (error) {
@@ -842,7 +857,7 @@ export class ProxyResponseHandler {
           responseHeaders: response.headers,
           responseText,
           usageMetrics,
-          costUsd: costUsdStr,
+          costUsd: rawCostUsdStr,
           statusCode,
           durationMs: Date.now() - session.startTime,
           isStreaming: false,
@@ -1665,8 +1680,9 @@ export class ProxyResponseHandler {
         // 追踪消费到 Redis(用于限流)
         await trackCostToRedis(session, usageForCost);
 
-        // Calculate cost (for session tracking and Langfuse tracing)
+        // Calculate cost for session tracking (with multiplier) and Langfuse (raw)
         let costUsdStr: string | undefined;
+        let rawCostUsdStr: string | undefined;
         if (usageForCost) {
           try {
             if (session.request.model) {
@@ -1681,6 +1697,20 @@ export class ProxyResponseHandler {
                 if (cost.gt(0)) {
                   costUsdStr = cost.toString();
                 }
+                // Raw cost without multiplier for Langfuse
+                if (provider.costMultiplier !== 1) {
+                  const rawCost = calculateRequestCost(
+                    usageForCost,
+                    priceData,
+                    1.0,
+                    session.getContext1mApplied()
+                  );
+                  if (rawCost.gt(0)) {
+                    rawCostUsdStr = rawCost.toString();
+                  }
+                } else {
+                  rawCostUsdStr = costUsdStr;
+                }
               }
             }
           } catch (error) {
@@ -1735,7 +1765,7 @@ export class ProxyResponseHandler {
           responseHeaders: response.headers,
           responseText: allContent,
           usageMetrics: usageForCost,
-          costUsd: costUsdStr,
+          costUsd: rawCostUsdStr,
           statusCode: effectiveStatusCode,
           durationMs: duration,
           isStreaming: true,

+ 1 - 1
src/lib/langfuse/trace-proxy-request.ts

@@ -205,7 +205,7 @@ export async function traceProxyRequest(ctx: TraceContext): Promise<void> {
     // Propagate trace attributes
     await propagateAttributes(
       {
-        userId: messageContext?.user?.id ? String(messageContext.user.id) : undefined,
+        userId: messageContext?.user?.name ?? undefined,
         sessionId: session.sessionId ?? undefined,
         tags,
         metadata: traceMetadata,

+ 1 - 1
tests/unit/langfuse/langfuse-trace.test.ts

@@ -239,7 +239,7 @@ describe("traceProxyRequest", () => {
 
     expect(mockPropagateAttributes).toHaveBeenCalledWith(
       expect.objectContaining({
-        userId: "7",
+        userId: "testuser",
         sessionId: "sess_abc12345_def67890",
         tags: expect.arrayContaining([
           "claude",