What gets recorded: arguments and return values
@observe sends every argument and return value to Langfuse. capture_input=False stops that for one function, but a card number inside a customer's text still leaves.
Lesson 13 showed when data leaves the process. This lesson is about what leaves. The desk will take payments, and a card number is the kind of data that should never reach a tracing service.
import json
@observe(name="take-payment", as_type="tool")
def take_payment(card_number, amount):
return f"charged {amount} euros"
take_payment("4111 1111 1111 1111", 40)
langfuse.flush()
print("card number exported:", "4111" in json.dumps([s["attributes"] for s in local_langfuse.SPANS]))
local_langfuse.tree("input")python card.pyThe card number is in the observation's input, exactly as passed, and was exported. A decorated function's arguments become its input, and for this function that means the card.
Turning capture off
@observe(name="take-payment", as_type="tool", capture_input=False)python card.pycapture_input=False leaves the input empty; capture_output=False does the same for the return value. LANGFUSE_OBSERVE_DECORATOR_IO_CAPTURE_ENABLED=false turns both off for every decorator at once. Better still, pass a reference such as a saved card's id, and look the number up inside the function, where nothing records it.
The card in the customer's words
Customers type card numbers into support tickets. The ticket is the agent's input and part of the model's messages.
import json
print(answer("My card 4111 1111 1111 1111 was charged twice for A17"))
langfuse.flush()
for span in local_langfuse.SPANS:
print(span["name"], "contains the card:", "4111" in json.dumps(span["attributes"]))python card_ticket.pyTwo of the three observations carry the card: the agent's input and the generation's input messages. Turning capture off there would remove what makes the trace useful, and the OpenAI wrapper from lesson 7 records messages whatever the decorator says. Changing the data as it leaves, lesson 15, fixes this for every observation at once.
- Return the card number from
take_paymentwithcapture_input=Falsestill set, and search again. - Set
LANGFUSE_OBSERVE_DECORATOR_IO_CAPTURE_ENABLED=falsein the shell and runcard_ticket.py. - Put an email address in the ticket and search the exported attributes for it.
This is what real progress feels like.