Python v3 → v4

Python v3 → v4

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

출처: 문서

본문

이로 인해 트레이스 속성 설정 방식이 바뀌어요. update_current_trace()로 트레이스 객체를 명령형으로 업데이트하는 대신, propagate_attributes() — 현재 및 그 범위 안에서 생성된 모든 자식 observation에 속성을 자동으로 적용하는 컨텍스트 매니저를 사용해요.

v4는 기본 OpenTelemetry 내보내기 동작을 변경해요. Langfuse는 더 이상 기본적으로 모든 span을 내보내지 않아요. 이전에 비-LLM span(HTTP, DB, queue, 프레임워크 내부)이 전달되는 것에 의존했다면, 업그레이드 전에 아래 첫 번째 호환성 파괴 변경을 검토하세요.

호환성 파괴 변경

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

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

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

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

v4 이전에는 차단되지 않은 계측 범위가 기본적으로 내보내졌어요.

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

from langfuse import Langfuse

langfuse = Langfuse(should_export_span=lambda span: True)

기본 동작과 커스텀 필터 조합하기

from langfuse import Langfuse
from langfuse.span_filter import is_default_export_span

langfuse = Langfuse(
    should_export_span=lambda span: (
        is_default_export_span(span)
        or (
            span.instrumentation_scope is not None
            and span.instrumentation_scope.name.startswith("my_framework")
        )
    )
)

Python 호환성 참고: blocked_instrumentation_scopes는 deprecated

blocked_instrumentation_scopes는 v4에서 여전히 동작하지만 deprecated이며 향후 버전에서 제거될 거예요. should_export_span으로 마이그레이션하세요.

should_export_span로 동일한 차단목록 동작:

from langfuse import Langfuse
from langfuse.span_filter import is_default_export_span

blocked = {"sqlite", "requests"}

langfuse = Langfuse(
    should_export_span=lambda span: (
        is_default_export_span(span)
        and (
            span.instrumentation_scope is None
            or span.instrumentation_scope.name not in blocked
        )
    )
)

blocked_instrumentation_scopesshould_export_span이 모두 설정되면 차단된 범위가 여전히 우선(강한 거부권).

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

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

update_current_trace() → 3개의 메서드로 분해

새 모델에서는 연관 속성(user_id, session_id, metadata, tags, 요청 범위 환경)이 트레이스뿐 아니라 모든 observation에 존재해야 해요. 그래서 propagate_attributes() — 해당 속성을 범위 안에서 생성된 현재 및 모든 자식 observation에 자동으로 적용하는 컨텍스트 매니저로 이동하는 거예요.

v3:

langfuse.update_current_trace(
    name="trace-name",
    user_id="user-123",
    session_id="session-abc",
    version="1.0",
    input={"query": "hello"},
    output={"result": "world"},
    metadata={"key": "value"},
    tags=["tag1"],
    public=True,
)

v4 (분해됨):

from langfuse import observe, propagate_attributes, get_client

langfuse = get_client()

@observe()
def my_function():
    # (a) Correlating attributes → propagate_attributes() context manager
    with propagate_attributes(
        trace_name="trace-name",  # note: 'name' is now 'trace_name'
        user_id="user-123",
        session_id="session-abc",
        version="1.0",
        metadata={"key": "value"},
        tags=["tag1"],
        environment="staging",
    ):
        result = call_llm("hello")

    # (b) Trace I/O (deprecated, only for legacy trace-level LLM-as-a-judge configurations)
    langfuse.set_current_trace_io(input={"query": "hello"}, output={"result": result})

    # (c) Public flag
    langfuse.set_current_trace_as_public()

주요 차이점:

| 속성 | v3 | v4 | | name | update_current_trace(name=...) | propagate_attributes(trace_name=...) | | user_id, session_id, tags, version | update_current_trace(...) | propagate_attributes(...) | | metadata | update_current_trace(metadata=any) | propagate_attributes(metadata=dict[str,str]) | | input, output | update_current_trace(...) | set_current_trace_io(...) (deprecated) | | public | update_current_trace(public=True) | set_current_trace_as_public() | | release | update_current_trace(release=...) | LANGFUSE_RELEASE — 제거됨, 환경 변수 사용 | | environment | update_current_trace(environment=...) | LANGFUSE_TRACING_ENVIRONMENT / Langfuse(environment=...) / propagate_attributes(environment=...) — 프로세스 수준 환경은 전자, 요청 범위 환경은 후자 사용 |

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

span.update_trace() → 3개의 메서드로 분해

동일한 분해가 observation 수준의 update_trace() 메서드에도 적용돼요.

v3:

span.update_trace(
    name="trace-name",
    user_id="user-123",
    session_id="session-abc",
    input={"query": "hello"},
    output={"result": "world"},
    public=True,
)

v4:

from langfuse import get_client, propagate_attributes

langfuse = get_client()

with langfuse.start_as_current_observation(as_type="span", name="my-operation") as span:
    with propagate_attributes(trace_name="trace-name", user_id="user-123", session_id="session-abc"):
        result = call_llm("hello")

    span.set_trace_io(input={"query": "hello"}, output={"result": result})  # deprecated
    span.set_trace_as_public()

통합(LangChain, OpenAI)의 경우 전달된 트레이스 속성은 이제 자식에게만 전파되며 트레이스로 거슬러 올라가지 않아요.

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

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

| v3 / 전환 이름 | v4 이름 | | langfuse.api.observations_v_2 | langfuse.api.observations | | langfuse.api.score_v_2 | langfuse.api.scores | | langfuse.api.metrics_v_2 | langfuse.api.metrics | | langfuse.api.observations | langfuse.api.legacy.observations_v1 (legacy v1) | | langfuse.api.score | langfuse.api.legacy.score_v1 (legacy v1) | | langfuse.api.metrics | langfuse.api.legacy.metrics_v1 (legacy v1) |

Python SDK v4 클라이언트가 셀프 호스트 Langfuse v3 서버를 일시적으로 조회해야 한다면 해당 langfuse.api.legacy.<resource>_v1 네임스페이스를 사용하세요.

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

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

start_span() / start_generation() → start_observation()

observation이 새 모델의 주요 개념이에요. as_type 파라미터가 있는 통합 start_observation() API가 별도 메서드를 대체해요.

| v3 | v4 | | langfuse.start_span(name="x") | langfuse.start_observation(name="x") | | langfuse.start_as_current_span(name="x") | langfuse.start_as_current_observation(name="x") | | langfuse.start_generation(name="x", model="gpt-4") | langfuse.start_observation(name="x", as_type="generation", model="gpt-4") | | langfuse.start_as_current_generation(name="x", model="gpt-4") | langfuse.start_as_current_observation(name="x", as_type="generation", model="gpt-4") | | span.start_span(name="x") | span.start_observation(name="x") | | span.start_as_current_span(name="x") | span.start_as_current_observation(name="x") | | span.start_generation(name="x") | span.start_observation(name="x", as_type="generation") | | span.start_as_current_generation(name="x") | span.start_as_current_observation(name="x", as_type="generation") |

DatasetItemClient.run() 제거 → Experiment SDK 사용

Experiment SDK(dataset.run_experiment())가 실험 속성(run 메타데이터, 데이터셋 아이템 연결) 전파를 내부에서 처리해요.

v3:

for item in dataset.items:
    with item.run(run_name="my-run", run_metadata={...}) as span:
        result = my_llm(item.input)
        span.update(output=result)

v4:

from langfuse import get_client

dataset = get_client().get_dataset("my-dataset")

def my_task(*, item, **kwargs):
    return my_llm(item.input)

dataset.run_experiment(name="my-run", task=my_task)

DatasetItem 객체는 동일한 데이터 속성(id, input, expected_output, metadata 등)을 갖지만 run() 메서드는 제거됐어요.

LangChain CallbackHandler: update_trace 파라미터 제거

핸들러는 이제 내부적으로 propagate_attributes()를 사용해요. update_trace 파라미터는 더 이상 없으며, 전달하면 TypeError가 발생해요.

v3:

from langfuse.langchain import CallbackHandler

handler = CallbackHandler(update_trace=True, trace_context={...})

v4:

handler = CallbackHandler(trace_context={...})

propagate_attributes()로 LangChain 호출을 둘러싸는 observation으로 감싸면 여전히 트레이스 속성(user_id, session_id, tags 등)을 설정할 수 있어요. v2 → v3 마이그레이션 가이드의 LangChain 통합 예시 또는 커스텀 트레이스 속성 문서를 참고하세요.

제거된 타입

다음 타입이 langfuse.types에서 제거됐어요:

| 제거된 타입 | 설명 | | TraceMetadata | name, user_id, session_id, version, release, metadata, tags, public이 있는 TypedDict | | ObservationParams | observation 필드가 있는 TraceMetadata 확장 TypedDict | | MapValue, ModelUsage, PromptClient | 더 이상 langfuse.types에서 재-export되지 않음, langfuse.model에서 import |

Pydantic v1 지원 제거

SDK는 이제 Pydantic v2를 요구해요. 애플리케이션이 여전히 Pydantic v1을 사용한다면 pydantic.v1 호환성 shim을 사용해야 해요.

검증 변경

  • 전파된 metadata: 이제 dict[str, str]이며 값은 200자로 제한됨(이전에는 Any). 비문자열 값은 문자열로 강제 변환. 한도를 초과하는 값은 경고와 함께 버려짐.
  • user_id, session_id: 최대 길이 200자의 문자열로 검증. 한도를 초과하는 값은 경고와 함께 버려짐.

마이그레이션 체크리스트

  • 비-LLM OpenTelemetry span에 의존했던 트레이스/대시보드 감사: v4 기본 필터에서 더 이상 나타나지 않을 수 있음
  • 필요하면 should_export_span=lambda span: True로 pre-v4 "모든 span 내보내기" 동작 유지
  • 여전히 blocked_instrumentation_scopes를 사용한다면 deprecation 제거 전에 should_export_span 조합으로 마이그레이션
  • update_current_trace 검색 → propagate_attributes() + set_current_trace_io()(레거시 트레이스 수준 LLM-as-a-judge 구성에 의존할 때만) + set_current_trace_as_public()로 분할
  • .update_trace( 검색 → observation 객체에서 동일한 분할
  • start_span / start_generation 검색 → start_observation으로 교체
  • item.run( 검색 → dataset.run_experiment()로 교체
  • CallbackHandler(update_trace= 검색 → 파라미터 제거
  • metadata 값이 dict[str, str]이며 값 ≤200자임을 확인
  • 아직 v1이면 Pydantic을 v2로 업그레이드
  • api.observations_v_2 / api.score_v_2 / api.metrics_v_2 검색 → api.observations / api.scores / api.metrics로 교체
  • api.observations / api.score / api.metrics의 legacy v1 사용 검색 → api.legacy.observations_v1 / api.legacy.score_v1 / api.legacy.metrics_v1로 이동
  • Langfuse v3을 셀프 호스트한다면 api.legacy.observations_v1api.legacy.metrics_v1을 사용; 기본 api.observations / api.metrics는 Langfuse v4가 필요함(셀프 호스트 호환성 매트릭스 참고)
  • 남은 *_v_2 별칭 참조 제거(v4에서 제거됨)

더 알아보기 (Learn more)