Your first trace
A trace is the record of one piece of work: what went in, what came out, and every step between. Tracing the shop's support desk takes five lines.
The desk before any tracing, as plain Python: it reads a ticket, finds an order id in it, and looks the order up.
import re
ORDERS = {"A17": "shipped on 3 March"}
def answer(ticket):
order = re.search(r"[A-Z]\d{2}", ticket)
if not order:
return "Could you send your order number?"
return f"Order {order.group()}: {ORDERS.get(order.group(), 'not found')}"
print(answer("Where is my order A17?"))
print(answer("Is B22 on its way?"))python plain.pyanswer finds an order id, a capital letter and two digits, and looks it up. B22 is not in ORDERS, so it says so. Nothing about this run is recorded anywhere.
A Langfuse to send traces to
Langfuse is a server, and the SDK needs one to send to. Instead of signing up, run local_langfuse.py on your own machine: it answers what the SDK sends and keeps it, so every lesson can print what was exported. Copy it once from the appendix at the end, save it beside your lesson files, and leave it alone.
from langfuse import Langfuse
import local_langfuse
url = local_langfuse.start()
langfuse = Langfuse(public_key="pk-lf-local", secret_key="sk-lf-local", base_url=url)start returns the address the server is listening on. The keys can be any strings, because this server does not check them, and base_url is what points the SDK at it instead of Langfuse's own servers.
Recording one piece of work
ticket = "Where is my order A17?"
with langfuse.start_as_current_observation(as_type="span", name="support-ticket", input=ticket) as span:
span.update(output=answer(ticket))
langfuse.flush()
local_langfuse.tree("input", "output")python first_trace.pystart_as_current_observation opens an observation, a single recorded step, named support-ticket, with the ticket as its input. The with block closes it, and span.update sets its output. The SDK sends in the background, so flush pushes what is queued before the program prints.
tree is a helper in that file: it prints what the server received, here one observation, which is also the whole trace. Most lessons from here on end this way.
Where traces go when you forget base_url
from langfuse import Langfuse
import local_langfuse
url = local_langfuse.start()
langfuse = Langfuse(public_key="pk-lf-local", secret_key="sk-lf-local")
with langfuse.start_as_current_observation(as_type="span", name="support-ticket"):
pass
langfuse.flush()
print(len(local_langfuse.SPANS), "observations reached the local server")python no_url.pyWith no base_url and no LANGFUSE_BASE_URL, the SDK exports to cloud.langfuse.com. The local server received nothing, the attempt was blocked, and the SDK retried and gave up. The program carried on: the error was logged, never raised. With real keys those retries would have succeeded, and whatever the trace held would now sit on someone else's servers.
base_url takes a minute.- Trace two tickets, one inside the other's
withblock, and print the tree. - Print
local_langfuse.REQUESTSafterflushto see what the SDK asked for. - Change the observation's name to
ticketand run it again.
You understood something today that you didn't yesterday.