조건부 트레이싱

조건부 트레이싱

LANGSMITH_TRACING=true 환경 변수가 전역으로 설정되어 있으면 트레이스가 자동으로 LangSmith로 전송돼요. 이 가이드는 특정 요청에 대해 트레이싱을 선택적으로 비활성화하거나 커스터마이즈하는 방법을 보여줍니다.

출처: 문서

본문

LANGSMITH_TRACING=true 환경 변수가 전역으로 설정되어 있으면 트레이스가 자동으로 LangSmith로 전송됩니다. 이 가이드는 특정 요청에 대해 트레이싱을 선택적으로 비활성화하거나 커스터마이즈하는 방법을 보여줍니다.

다음과 같은 경우 조건부 트레이싱을 사용하세요:

  • 데이터 보존 정책 준수: 일부 클라이언트는 규정 준수 또는 개인정보 보호 이유로 데이터 보존을 0으로 요구할 수 있습니다.
  • 민감한 작업 처리: PII, 자격 증명 또는 기밀 데이터와 관련된 작업의 트레이싱을 비활성화합니다.
  • 테넌트별 구성 구현: 고객에 따라 트레이스를 다른 프로젝트로 라우팅하거나 다른 설정을 적용합니다.
  • 비용 제어: 중요 작업의 가시성을 유지하면서 저가치 요청의 트레이싱을 비활성화합니다.
  • 기능 플래그 지원: 특정 기능이나 실험 코드 경로가 활성화된 경우에만 트레이싱을 활성화합니다.

팁: 모든 런의 일정 비율만 기록해 트레이스 볼륨을 줄이려면 트레이스 샘플링 비율 설정을 참고하세요.

tracing_context 컨텍스트 매니저(Python)와 tracingEnabled 옵션(TypeScript)을 사용하면 코드를 재구성하거나 환경 변수를 바꾸지 않고도 런타임에 전역 트레이싱 설정을 덮어쓸 수 있습니다.

참고: 다음 섹션은 애플리케이션 로직과 비즈니스 요구 사항에 맞게 적용할 수 있는 언어별 예시를 제공합니다.

Python

트레이싱 컨텍스트 작동 방식

tracing_context 컨텍스트 매니저를 사용하면, 그 범위 내에서 실행되는 코드에 대해 전역 트레이싱 구성을 덮어씁니다. 즉 자동 트레이싱을 전역으로 활성화해 두고 특정 함수 호출에 대해 트레이싱 동작을 선택적으로 제어할 수 있습니다.

세 가지 우선순위 수준의 제어가 있습니다:

  1. tracing_context(enabled=...): 최우선 (범위 지정 트레이싱 제어용 컨텍스트 매니저).
  2. ls.configure(enabled=...): 전역 구성 (전역 트레이싱 동작 설정).
  3. 환경 변수: 최저 우선순위 (LANGSMITH_TRACING).

특정 호출의 트레이싱 비활성화

특정 작업의 트레이싱을 비활성화하려면 enabled=Falsetracing_context로 감쌉니다:

import langsmith as ls
from langsmith import traceable

# LANGSMITH_TRACING=true is set globally

@traceable
def my_function(input_text: str):
    return process(input_text)

# Default invocation - is traced
result = my_function("regular data")

# Disable tracing for sensitive data
with ls.tracing_context(enabled=False):
    result = my_function("sensitive data")  # not traced

이 패턴은 특정 데이터를 기록해서는 안 된다는 것을 알 때의 일회성 경우에 유용합니다.

비즈니스 로직 기반 조건부 트레이싱 활성화

클라이언트 설정이나 요청 속성 같은 런타임 조건에 따라 트레이싱을 동적으로 활성화/비활성화할 수 있습니다.

import langsmith as ls
from langsmith import traceable

@traceable
def my_function(input_text: str):
    return process(input_text)

def client_requires_zero_retention(client_id: str) -> bool:
    """
    Check if a client has a zero-retention policy.

    In production, this would query a database, configuration service,
    or feature flag system. Consider caching results for performance.
    """
    # Example: Query from database or config
    zero_retention_clients = get_zero_retention_clients()  # Your implementation
    return client_id in zero_retention_clients

def handle_request(client_id: str, user_input: str):
    """
    Process a request with conditional tracing based on client requirements.
    """
    should_disable = client_requires_zero_retention(client_id)

    with ls.tracing_context(enabled=not should_disable):
        return my_function(user_input)

# Example usage
handle_request("client-a", "some input")  # Traced or not based on client settings

요청별 트레이싱 구성 커스터마이즈

트레이스를 다른 프로젝트로 라우팅하거나 요청별 메타데이터를 추가하는 등 트레이싱 설정을 동적으로 커스터마이즈할 수도 있습니다.

import langsmith as ls
from langsmith import traceable

@traceable
def my_function(input_text: str):
    return process(input_text)

def handle_request(client_id: str, user_input: str, region: str):
    """
    Route traces to client-specific projects with custom metadata.
    """
    client_tier = get_client_tier(client_id)  # e.g., "enterprise", "standard"

    with ls.tracing_context(
        enabled=True,
        project_name=f"client-{client_id}",
        tags=["production", f"tier-{client_tier}", f"region-{region}"],
        metadata={
            "client_id": client_id,
            "region": region,
            "tier": client_tier
        }
    ):
        return my_function(user_input)

# Traces go to "client-abc" project with custom tags and metadata
handle_request("abc", "some input", "us-west")

이 패턴은 다음과 같은 경우에 유용합니다:

  • 멀티 테넌트 애플리케이션: 고객별로 별도 프로젝트에 트레이스 격리
  • 지역 배포: 지리적 지역별 성능 및 동작 추적
  • 기능 브랜치: 실험 기능 트레이스를 전용 프로젝트로 라우팅
  • 사용자 세그먼테이션: 사용자 등급, 코호트 또는 A/B 테스트 그룹별 동작 분석

자동 트레이싱과 함께 작업

tracing_context 컨텍스트 매니저는 자동 트레이싱과 함께 작동합니다. LANGSMITH_TRACING=true를 전역으로 설정해 두고 특정 요청에 대해 설정을 덮어쓰는 데 tracing_context를 사용할 수 있습니다:

import os
import langsmith as ls

# Global environment variable set
os.environ["LANGSMITH_TRACING"] = "true"

@ls.traceable
def process_data(data: str):
    return data.upper()

# Automatically traced (respects LANGSMITH_TRACING)
process_data("hello")

# Override global setting - disable for this call
with ls.tracing_context(enabled=False):
    process_data("sensitive")  # not traced

# Override global setting - enable with custom config
with ls.tracing_context(
    enabled=True,
    project_name="special-project"
):
    process_data("important")  # Traced to "special-project"

트레이싱 컨텍스트 중첩

tracing_context 블록을 중첩하면 가장 안쪽 컨텍스트가 우선합니다.

import langsmith as ls

@ls.traceable
def inner_function(data: str):
    return data

@ls.traceable
def outer_function(data: str):
    # This call respects the inner context
    return inner_function(data)

# Outer context disables tracing
with ls.tracing_context(enabled=False):
    # But inner context re-enables it
    with ls.tracing_context(enabled=True):
        outer_function("data")  # is traced

이는 일반적으로 트레이싱되지 않는 섹션에서 디버깅을 위해 임시로 트레이싱을 활성화하려 할 때 유용할 수 있습니다.

입력과 출력을 조건부로 마스킹하기

때로는 트레이스가 기록되기를 원합니다 — 런 타이밍, 구조, 오류, 메타데이터는 유지하되, 특정 요청(예: 엄격한 개인정보 요구 사항이 있는 테넌트의 트레이스)에 대해 입력과 출력은 숨겨야 할 수 있습니다. 이는 트레이싱 완전 비활성화 및 클라이언트가 보내는 모든 트레이스에 동일한 마스킹을 적용하는 Client(hide_inputs=...)와는 다릅니다.

요청별로 마스킹하려면 tracing_contextreplicas 매개변수와 함께 사용하고, 기록되는 런의 inputsoutputs를 덮어쓰는 updates dict를 전달하세요. tracing_context는 현재 실행 컨텍스트에 범위가 지정되므로, 서로 다른 마스킹 정책을 가진 동시 요청은 경합하지 않습니다.

import langsmith as ls
from langsmith import traceable

@traceable
def my_agent(user_input: str) -> str:
    return process(user_input)

def should_redact(tenant_id: str) -> bool:
    """Return True if traces for this tenant should have inputs/outputs masked."""
    return tenant_id in get_redacted_tenants()

def handle_request(tenant_id: str, user_input: str) -> str:
    replica: dict = {"project_name": "my-project"}
    if should_redact(tenant_id):
        # Recorded run will have empty inputs/outputs but full structure,
        # timing, metadata, and any errors.
        replica["updates"] = {"inputs": {}, "outputs": {}}

    with ls.tracing_context(replicas=[replica]):
        return my_agent(user_input)

updates에서 런 필드의 어떤 하위 집합이든 사용할 수 있습니다(예: 마커를 유지하려면 {"inputs": {"redacted": True}}, 출력만 마스킹하려면 {"outputs": {}}). 동일한 패턴으로 서로 다른 마스킹 정책을 서로 다른 목적지로 라우팅할 수 있습니다 — 각 replica는 자체 project_name, api_key, updates를 지정할 수 있습니다. 전체 replica 레퍼런스는 replicas로 여러 목적지에 트레이스 쓰기를 참고하세요.

참고: updates로 입력 또는 출력을 마스킹할 때는 replica에 항상 project_name을 설정하세요. replica의 project_name이 활성 세션의 프로젝트와 일치하면 updates가 버려지고 마스킹되지 않은 입력/출력이 전송될 수 있습니다.

배포된 에이전트에서 트레이싱 커스터마이즈

LangSmith Deployment의 Agent Server 내에서는 트레이싱이 기본적으로 활성화됩니다. factory function을 사용할 때 산출된 그래프를 tracing_context로 감싸 실행별로 트레이싱을 제어할 수 있습니다. 이는 커스텀 메타데이터 추가, 트레이싱 완전 비활성화, 인증된 사용자 기반 트레이싱 커스터마이즈에 유용합니다.

그래프의 트레이싱 비활성화
import contextlib
import langsmith as ls
from langgraph_sdk.runtime import ServerRuntime


@contextlib.asynccontextmanager
async def make_graph(runtime: ServerRuntime):
    graph = build_my_graph()

    # You can use tracing_context to dynamically enable/disable tracing,
    # set metadata or tags, override the tracing project, etc.
    with ls.tracing_context(enabled=False, metadata={"foo": "bar"}):
        yield graph
사용자별 트레이싱
import contextlib
import langsmith as ls
from langgraph_sdk.runtime import ServerRuntime

def get_project_for_user(user_id: str) -> str | None:
    ...
    return "my-project"

graph = build_my_graph()

@contextlib.asynccontextmanager
async def make_graph(runtime: ServerRuntime):
    user = runtime.user
    # Route traces to a different project depending on user or disable tracing entirely
    project_name = get_project_for_user(user.identity)

    if project_name is None:
        with ls.tracing_context(enabled=False):
            yield graph
    else:
        with ls.tracing_context(
            enabled=True,
            project_name=project_name,
            metadata={"user_id": user.identity, "foo": "bar"},
        ):
            yield graph

재사용 가능한 트레이싱 래퍼

조건부 트레이싱 로직을 자동으로 적용하는 데코레이터를 만듭니다.

import functools
import langsmith as ls
from langsmith import traceable

def conditional_trace(check_function):
    """
    Decorator that conditionally traces based on a check function.

    Args:
        check_function: Function that returns True if tracing should be enabled
    """
    def decorator(func):
        traced_func = traceable(func)

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            should_trace = check_function(*args, **kwargs)
            with ls.tracing_context(enabled=should_trace):
                return traced_func(*args, **kwargs)
        return wrapper
    return decorator

# Usage
def should_trace_client(client_id: str, *args, **kwargs) -> bool:
    return not client_requires_zero_retention(client_id)

@conditional_trace(should_trace_client)
def process_request(client_id: str, data: str):
    return data.upper()

# Automatically applies conditional tracing based on client_id
process_request("client-a", "some data")

TypeScript

tracingEnabled 작동 방식

TypeScript에서는 traceable()을 호출할 때 tracingEnabled 매개변수를 사용해 함수별로 트레이싱을 제어합니다. 이를 통해 함수 수준에서 트레이싱을 선택적으로 활성화/비활성화할 수 있습니다.

함수별로 트레이싱이 제어되는 두 수준 시스템:

  1. tracingEnabled 매개변수: 최우선 (traceable() 구성에 전달).
  2. 환경 변수: 최저 우선순위 (LANGSMITH_TRACING).

특정 호출의 트레이싱 비활성화

특정 작업의 트레이싱을 비활성화하려면 tracingEnabled: false로 traceable 함수 버전을 만듭니다:

import { traceable } from "langsmith/traceable";

const myFunction = traceable(
    (inputText: string) => {
        return process(inputText);
    },
    { name: "my_function" }
);

// Default invocation - is traced
await myFunction("regular data");

// Disable tracing for sensitive data
const myFunctionNoTrace = traceable(
    (inputText: string) => {
        return process(inputText);
    },
    { name: "my_function", tracingEnabled: false }
);

await myFunctionNoTrace("sensitive data");  // not traced

이 패턴은 특정 데이터를 기록해서는 안 된다는 것을 알 때의 일회성 경우에 유용합니다.

비즈니스 로직 기반 조건부 트레이싱 활성화

많은 애플리케이션에서 클라이언트 개인정보 요구 사항, 규정 준수, 기능 플래그 같은 런타임 조건에 따라 트레이싱을 동적으로 제어해야 합니다.

TypeScript에서 가장 효율적인 접근 방식은 추적/비추적 함수 변형을 미리 만들어 두고, 런타임에 비즈니스 로직에 따라 그 사이에서 선택하는 것입니다. 이렇게 하면 요청마다 새 추적 래퍼를 만드는 성능 오버헤드를 피하면서도 트레이싱 시기에 대한 세밀한 제어를 제공합니다. 예:

import { traceable } from "langsmith/traceable";

// Define the core logic once
function processText(inputText: string): string {
    // Your actual processing logic
    return inputText.toUpperCase();
}

// Create traced and non-traced variants upfront
const myFunction = traceable(processText, { name: "my_function" });
const myFunctionNoTrace = traceable(processText, {
    name: "my_function",
    tracingEnabled: false
});

function clientRequiresZeroRetention(clientId: string): boolean {
    /**
     * Check if a client has a zero-retention policy.
     *
     * In production, this would query a database, configuration service,
     * or feature flag system. Consider caching results for performance.
     */
    const zeroRetentionClients = getZeroRetentionClients();  // Your implementation
    return zeroRetentionClients.includes(clientId);
}

async function handleRequest(clientId: string, userInput: string) {
    /**
     * Process a request with conditional tracing based on client requirements.
     * Efficiently selects pre-created traced or non-traced variant.
     */
    const shouldDisable = clientRequiresZeroRetention(clientId);

    // Select the appropriate pre-created variant
    const fn = shouldDisable ? myFunctionNoTrace : myFunction;
    return await fn(userInput);
}

// Example usage
await handleRequest("client-a", "some input");  // Traced or not based on client settings

자동 트레이싱과 함께 작업

tracingEnabled 옵션은 자동 트레이싱과 원활하게 작동합니다. LANGSMITH_TRACING=true를 전역으로 설정해 두고 특정 함수에 대한 설정을 덮어쓰는 데 tracingEnabled를 사용할 수 있습니다.

import { traceable } from "langsmith/traceable";

// Global tracing enabled via environment
process.env.LANGSMITH_TRACING = "true";

const processData = traceable(
    (data: string) => {
        return data.toUpperCase();
    },
    { name: "process_data" }
);

// Automatically traced (respects LANGSMITH_TRACING)
await processData("hello");

// Override global setting - disable for this call
const processDataNoTrace = traceable(
    (data: string) => {
        return data.toUpperCase();
    },
    { name: "process_data", tracingEnabled: false }
);

await processDataNoTrace("sensitive");  // not traced

// Override global setting - enable with custom config
const processDataCustom = traceable(
    (data: string) => {
        return data.toUpperCase();
    },
    {
        name: "process_data",
        project_name: "special-project",
        tracingEnabled: true
    }
);

await processDataCustom("important");  // Traced to "special-project"

샘플링과의 비교

조건부 트레이싱과 샘플링은 다른 목적을 제공합니다:

기능 조건부 트레이싱 샘플링
제어 결정적 (명시적 활성화/비활성화) 확률적 (무작위 샘플링)
사용 사례 비즈니스 로직, 규정 준수, 요청별 결정 비용 최적화, 고용량 관측성
예측 가능성 특정 요청에 대한 보장된 동작 트래픽의 통계적 표현
구성 런타임 코드 로직 환경 변수 또는 클라이언트 구성

세밀한 제어를 위해 두 접근 방식을 결합할 수 있습니다.

관련 문서

더 알아보기