LangfuseLangfuse Python SDK 4.15.4 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
38 small wins to finish your pathNext lesson

Customer feedback, recorded later

Feedback arrives after the answer, often in other code. A seeded trace id lets that code find the trace, and a fixed score_id makes a new rating replace the old.

Lesson 23 scored a trace while it was open. A customer's thumbs-down comes later: a click in the chat window, handled by other code, maybe on another server. It has the ticket number, not a Langfuse trace id. Lesson 12's seeded ids close that gap.

Examplefeedback.py, after the setup lines and from desk import answer
def handle(ticket_number, ticket):
    trace_id = langfuse.create_trace_id(seed=ticket_number)
    with langfuse.start_as_current_observation(name="support-ticket", trace_context={"trace_id": trace_id}):
        return answer(ticket)


def record_feedback(ticket_number, helpful, comment=None):
    langfuse.create_score(
        trace_id=langfuse.create_trace_id(seed=ticket_number), score_id=f"{ticket_number}-feedback",
        name="user-feedback", value=1 if helpful else 0, data_type="BOOLEAN", comment=comment,
    )

handle gives the ticket's trace an id made from its ticket number. record_feedback makes the same id from the same number, with nothing shared between the two functions except the ticket number. score_id gives the score an id of your own: one per ticket, so a customer who changes their rating replaces the old score instead of adding a second.

Examplefeedback.py, continued
print(handle("ticket-1043", "Is B22 on its way?"))
record_feedback("ticket-1043", helpful=False, comment="B22 is on my receipt")
record_feedback("ticket-1043", helpful=False, comment="B22 is on my receipt, from 1 March")

langfuse.flush()
trace_ids = {span["trace"] for span in local_langfuse.SPANS}
for score in local_langfuse.SCORES:
    print(score["id"], score["value"], score["comment"], "| on this trace:", score["traceId"] in trace_ids)
Example
python feedback.py

Both scores landed on the ticket's trace. They share the id ticket-1043-feedback, and Langfuse replaces a score when a new one arrives with the same id and name on the same day, so the server keeps only the corrected comment. The local server keeps both, which shows what was sent. Always send the whole score again; the documentation warns against relying on partial updates.

A customer's comment is their own words, sent to Langfuse like a ticket is. The masking hook from lesson 15 only sees observations, not scores, so a card number typed into a feedback box would be sent unmasked; clean comments before create_score.

Feedback on a whole conversation

langfuse.create_score(session_id="chat-0042", name="conversation-quality", value=0.8) scores the session from lesson 10 without naming any trace. The same approach records signals the customer never states: a ticket that was reopened, or a refund that went through.

Try it yourself
  • Record feedback for a ticket number that was never handled, and check which trace id it carries.
  • Remove score_id and look at the two ids that are sent.
  • Record a session score and print its sessionId.

This is what real progress feels like.