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 |