JS/TS v4 → v5

JS/TS v4 → v5

JS/TS SDK v5는 observations 우선 데이터 모델 을 도입해요. 이 모델에서는 연관 속성(userId, sessionId, metadata, tags)이 트레이스에만 존재하는 것이 아니라 모든 observation으로 전파돼요. 이를 통해 비싼 join 없이 단일 테이블 쿼리가 가능해져 대규모에서 쿼리 성능이 크게 향상돼요.

출처: 문서

본문

이로 인해 트레이스 속성 설정 방식이 바뀌어요. updateActiveTrace()로 트레이스를 명령형으로 업데이트하는 대신, propagateAttributes() — 콜백을 감싸 그 범위 안에서 생성된 모든 자식 observation에 속성을 자동으로 적용하는 함수를 사용해요.

v5는 기본 OpenTelemetry 내보내기 동작을 변경해요. Langfuse는 이제 스마트 기본 span 필터를 적용해요. 이전에 모든 span(비-LLM span 포함)이 내보내질 것으로 기대했다면 아래 첫 번째 호환성 파괴 변경을 검토하세요.

콜백 이전에 생성된 span은 소급하여 업데이트되지 않아요.

호환성 파괴 변경

스마트 기본 span 필터링이 export-all 동작을 대체함

이전 버전에서는 기본적으로 모든 OpenTelemetry span을 내보내서 인프라 및 비-LLM 계측(HTTP, DB, queue, 프레임워크 내부)의 트레이스 노이즈가 증가했어요. 트레이스를 집중적이고 유용하게 유지하기 위해 v5는 스마트 기본 span 필터를 도입해요.

기본적으로 v5는 다음 중 하나라도 참이면 span을 내보내요:

  • span이 Langfuse(langfuse-sdk)로 생성됨
  • span에 gen_ai.* 속성이 있음
  • span 계측 범위가 알려진 LLM 범위 접두사와 일치함(예: openinference, langsmith, haystack, litellm)

v5 이전에는 커스텀 shouldExportSpan 함수를 구현하지 않으면 모든 span이 내보내졌어요.

pre-v5 "모두 내보내기" 동작 유지하기

import { LangfuseSpanProcessor } from "@langfuse/otel";

const spanProcessor = new LangfuseSpanProcessor({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  shouldExportSpan: () => true,
});

기본 동작과 커스텀 규칙 조합하기

v5에서 shouldExportSpan은 완전한 오버라이드예요. 기본 필터링을 확장(대체가 아닌)하려면 isDefaultExportSpan과 조합하세요.

import { LangfuseSpanProcessor, isDefaultExportSpan } from "@langfuse/otel";

const spanProcessor = new LangfuseSpanProcessor({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  shouldExportSpan: ({ otelSpan }) =>
    isDefaultExportSpan(otelSpan) ||
    otelSpan.instrumentationScope.name.startsWith("my_framework"),
});

가능한 트레이스 트리 부작용과 디버깅 방법

중간 또는 부모 span이 드롭되는 동안 자식 span이 여전히 내보내지면 필터링이 트레이스 트리를 깨뜨릴 수 있어요. 트레이스가 끊겨 보이면 SDK 디버그 로깅을 켜 드롭된 span을 검사한 다음 콜백에서 필요한 범위를 허용 목록에 추가하세요.

updateActiveTrace() → 3개의 함수로 분해

새 모델에서는 연관 속성(userId, sessionId, metadata, tags)이 트레이스뿐 아니라 모든 observation에 존재해야 해요. propagateAttributes()는 콜백을 감싸요 — 콜백 안에서 생성된 현재 및 모든 자식 span이 속성을 자동으로 상속해요. 콜백 이전에 생성된 span은 소급하여 업데이트되지 않아요.

v4:

import { updateActiveTrace, startActiveObservation } from "@langfuse/tracing";

await startActiveObservation("my-operation", async (span) => {
  updateActiveTrace({
    name: "user-workflow",
    userId: "user-123",
    sessionId: "session-456",
    tags: ["production"],
    public: true,
    metadata: { testRun: "server-export" },
    input: { query: "hello" },
    output: { response: "world" },
  });
});

v5:

import {
  propagateAttributes,
  startActiveObservation,
  setActiveTraceIO,
  setActiveTraceAsPublic,
} from "@langfuse/tracing";

await propagateAttributes(
  {
    traceName: "user-workflow", // was "name"
    userId: "user-123",
    sessionId: "session-456",
    tags: ["production"],
    metadata: { testRun: "server-export" },
  },
  async () => {
    await startActiveObservation("my-operation", async (span) => {
      setActiveTraceIO({
        input: { query: "hello" },
        output: { response: "world" },
      });
      setActiveTraceAsPublic();
    });
  },
);

주요 차이점:

| 속성 | v4 | v5 | | name | updateActiveTrace({name: ...}) | propagateAttributes({traceName: ...}, cb) | | userId, sessionId, tags, version | updateActiveTrace({...}) | propagateAttributes({...}, cb) | | metadata | updateActiveTrace({metadata: any}) | propagateAttributes({metadata: Record<string,string>}, cb) | | input, output | updateActiveTrace({...}) | setActiveTraceIO({...}) (deprecated) | | public | updateActiveTrace({public: true}) | setActiveTraceAsPublic() | | release | updateActiveTrace({release: ...}) | LANGFUSE_RELEASE — 제거됨, 환경 변수 사용 | | environment | updateActiveTrace({environment: ...}) | LANGFUSE_TRACING_ENVIRONMENT — 제거됨, 환경 변수 사용 |

setActiveTraceIO()는 deprecated이며 트레이스 입력/출력에 의존하는 트레이스 수준 LLM-as-a-judge 평가자와의 하위 호환을 위해서만 존재해요. 새 코드에서는 루트 observation에 직접 input/output을 설정하세요.

.updateTrace() → .setTraceIO() + .setTraceAsPublic()

동일한 분해가 모든 observation 래퍼 클래스(LangfuseSpan, LangfuseGeneration 등)에 적용돼요.

v4:

import { startObservation } from "@langfuse/tracing";

const span = startObservation("my-op");
span.updateTrace({
  name: "my-trace",
  userId: "user-123",
  sessionId: "session-456",
  tags: ["prod"],
  public: true,
  input: { query: "hello" },
  output: { response: "world" },
});

v5:

import { propagateAttributes, startObservation } from "@langfuse/tracing";

propagateAttributes(
  {
    traceName: "my-trace",
    userId: "user-123",
    sessionId: "session-456",
    tags: ["prod"],
  },
  () => {
    const span = startObservation("my-op");
    span.setTraceIO({
      input: { query: "hello" },
      output: { response: "world" },
    });
    span.setTraceAsPublic();
    span.end();
  },
);

.setTraceIO()는 deprecated이며 트레이스 입력/출력에 의존하는 트레이스 수준 LLM-as-a-judge 평가자와의 하위 호환을 위해서만 존재해요.

Public API 네임스페이스 재매핑 (api.*)

v5에서는 고성능 Public API 리소스가 기본값이 돼요. v2 별칭은 제거됐어요.

| v4 / 전환 이름 | v5 이름 | | langfuse.api.observationsV2 | langfuse.api.observations | | langfuse.api.scoreV2 | langfuse.api.scores | | langfuse.api.metricsV2 | langfuse.api.metrics | | langfuse.api.observations | langfuse.api.legacy.observationsV1 (legacy v1) | | langfuse.api.score | langfuse.api.legacy.scoreV1 (legacy v1) | | langfuse.api.metrics | langfuse.api.legacy.metricsV1 (legacy v1) |

JS/TS SDK v5 클라이언트가 셀프 호스트 Langfuse v3 서버를 일시적으로 조회해야 한다면 해당 langfuse.api.legacy.*V1 네임스페이스를 사용하세요.

새 기본 langfuse.api.observationslangfuse.api.metrics 메서드는 Observations v2와 Metrics v2 엔드포인트를 가리키며, 이는 Langfuse v4(Langfuse Cloud 또는 v4로 업그레이드된 셀프 호스트 서버)가 필요해요. 셀프 호스트 Langfuse v3에서는 대신 langfuse.api.legacy.observationsV1langfuse.api.legacy.metricsV1을 사용하세요. 셀프 호스트 호환성 매트릭스 참고.

Public API 엔드포인트 폐기는 v5 호환성 파괴 변경과 별개예요. 일부 API 메서드는 JS/TS v5에서 호출 가능하지만 Langfuse v4에서 deprecated인 서버 엔드포인트를 호출해요. 업그레이드 후 deprecated API 마이그레이션 가이드의 JS/TS SDK 메서드 매핑을 사용해 langfuse.api.trace.list(), langfuse.api.sessions.list(), langfuse.api.scores.getMany() 같은 메서드를 감사하세요.

@langfuse/langchain 내부 변경

CallbackHandler는 이제 트레이스 수준 속성에 propagateAttributes()를 사용해요. 다음 사용자에게 영향을 줘요:

  • CallbackHandler를 서브클래싱하는 사용자
  • 내부 span 생성 동작에 의존하는 사용자
  • traceMetadata가 비문자열 값을 수락하는 것에 의존하는 사용자 — 비문자열 값은 이제 propagateAttributes에 전달되기 전에 JSON.stringify로 직렬화되는데, 이는 Record<string, string>을 요구함

@langfuse/openai 내부 변경

traceMethod 래퍼는 이제 observation에서 .updateTrace()를 호출하는 대신, 추적 호출을 propagateAttributes()로 감싸 userId, sessionId, tags, traceName을 설정해요. (부모 observation에도 속성이 설정되는 것에 의존한다면 전체 실행을 propagateAttributes로 감싸세요.)

제거된 속성

| 제거됨 | 대체 | | release | LANGFUSE_RELEASE — 환경 변수로 설정 | | environment | LANGFUSE_TRACING_ENVIRONMENT — 환경 변수로 설정 | | public | setActiveTraceAsPublic() / .setTraceAsPublic()로 대체 |

마이그레이션 체크리스트

  • 비-LLM OpenTelemetry span에 의존했던 트레이스/대시보드 감사: v5 기본 필터에서 더 이상 나타나지 않을 수 있음
  • 필요하면 LangfuseSpanProcessorshouldExportSpan: () => true로 pre-v5 "모든 span 내보내기" 동작 유지
  • 커스텀 필터링을 사용한다면 기본 LLM 중심 동작을 유지하기 위해 isDefaultExportSpan과 조합
  • updateActiveTrace 검색 → propagateAttributes() + setActiveTraceIO()(레거시 트레이스 수준 LLM-as-a-judge 구성에 의존할 때) + setActiveTraceAsPublic()로 분할
  • .updateTrace( 검색 → propagateAttributes() + .setTraceIO() + .setTraceAsPublic()로 분할
  • 전파된 metadata 값이 Record<string, string>이며 값 ≤200자임을 확인
  • release/environment 속성 사용을 환경 변수(LANGFUSE_RELEASE, LANGFUSE_TRACING_ENVIRONMENT)로 교체
  • api.observationsV2 / api.scoreV2 / api.metricsV2 검색 → api.observations / api.scores / api.metrics로 교체
  • api.observations / api.score / api.metrics의 legacy v1 사용 검색 → api.legacy.observationsV1 / api.legacy.scoreV1 / api.legacy.metricsV1로 이동
  • Langfuse v3을 셀프 호스트한다면 api.legacy.observationsV1api.legacy.metricsV1을 사용; 기본 api.observations / api.metrics는 Langfuse v4가 필요함(셀프 호스트 호환성 매트릭스 참고)
  • 남은 *V2 별칭 참조 제거(v5에서 제거됨)

더 알아보기 (Learn more)