Skip to content

Input capture and filtering

By default, @step serializes all function arguments into the observation input and the return value into the output. This section explains how to control what gets captured and how to strip noise without disabling capture entirely.

Two filtering layers

Two independent layers control what ends up in the observation input:

Layer Scope Configured at
Global InputFilter All @step observations in the process setup_tracing(input_filter=...)
Per-span exclude_args One specific @step decorator @step("name", exclude_args=[...])

Both layers stack: an argument excluded by either layer is stripped. The self argument is always stripped automatically.

Global InputFilter

InputFilter strips arguments by name or by type annotation across every @step in the process. Set it once at startup:

from semantic_tracing import InputFilter, setup_tracing

setup_tracing(
    service_name="my_workflow",
    input_filter=InputFilter(
        exclude_arg_names=["ctx", "runner_context"],
        exclude_arg_types=["WorkflowContext"],
    ),
)

exclude_arg_types matches against the argument's type annotation as a string. It does not perform an isinstance check, so the filter works without importing the type.

Per-span exclude_args

For a single @step, pass exclude_args with the argument names to omit in addition to the global filter:

from semantic_tracing import step

@step("orchestrate", as_type="agent", exclude_args=["internal_state"])
async def handle(self, request: WorkflowRequest, internal_state: dict) -> None:
    ...

Use this for arguments that are only noisy for one specific function, or for sensitive data that should not appear in Langfuse traces even though capture_sensitive_data=True is set globally.

Disabling capture entirely

Pass capture_input=False or capture_output=False to the @step decorator to suppress recording entirely for that function. This is appropriate for functions where arguments are large binary objects (image bytes, raw files) or when the return value is too large to be useful in a trace:

@step("embed_image", as_type="embedding", capture_input=False)
async def embed(image_bytes: bytes) -> list[float]:
    ...

Sensitive data from Agent Framework

Microsoft Agent Framework's telemetry layers only attach prompt and completion bodies and tool arguments and results to spans when sensitive data capture is explicitly enabled. This is controlled at the process level via setup_tracing(), not through InputFilter:

setup_tracing(
    service_name="my_workflow",
    capture_sensitive_data=True,
)

Setting capture_sensitive_data=True makes the actual content of LLM calls visible in Langfuse, which is required for evaluators that score against the model response text (such as groundedness scoring). It has no effect on @step-level input/output capture.

Summary of all capture controls

Control Level What it affects
InputFilter(exclude_arg_names=[...]) Global, all @step Named arguments stripped from input
InputFilter(exclude_arg_types=[...]) Global, all @step Type-annotated arguments stripped from input
@step(..., exclude_args=[...]) Per function Named arguments stripped from input for one step
@step(..., capture_input=False) Per function Entire input suppressed for one step
@step(..., capture_output=False) Per function Entire output suppressed for one step
capture_sensitive_data=True Global, Agent Framework Enables MAF prompt / tool body capture